@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
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var React26 = require('react');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
|
+
var Animated9 = require('react-native-reanimated');
|
|
5
6
|
var reactNativeSizeMatters = require('react-native-size-matters');
|
|
6
7
|
var AntDesign = require('@expo/vector-icons/AntDesign');
|
|
7
8
|
var Entypo = require('@expo/vector-icons/Entypo');
|
|
@@ -11,7 +12,6 @@ var MaterialIcons = require('@expo/vector-icons/MaterialIcons');
|
|
|
11
12
|
var Ionicons = require('@expo/vector-icons/Ionicons');
|
|
12
13
|
var vectorIcons = require('@expo/vector-icons');
|
|
13
14
|
var expoLinearGradient = require('expo-linear-gradient');
|
|
14
|
-
var Animated12 = require('react-native-reanimated');
|
|
15
15
|
var RNSlider = require('@react-native-community/slider');
|
|
16
16
|
var bottomSheet = require('@gorhom/bottom-sheet');
|
|
17
17
|
var reactNativeSafeAreaContext = require('react-native-safe-area-context');
|
|
@@ -21,13 +21,13 @@ var sonnerNative = require('sonner-native');
|
|
|
21
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
22
|
|
|
23
23
|
var React26__default = /*#__PURE__*/_interopDefault(React26);
|
|
24
|
+
var Animated9__default = /*#__PURE__*/_interopDefault(Animated9);
|
|
24
25
|
var AntDesign__default = /*#__PURE__*/_interopDefault(AntDesign);
|
|
25
26
|
var Entypo__default = /*#__PURE__*/_interopDefault(Entypo);
|
|
26
27
|
var Feather__default = /*#__PURE__*/_interopDefault(Feather);
|
|
27
28
|
var FontAwesome5__default = /*#__PURE__*/_interopDefault(FontAwesome5);
|
|
28
29
|
var MaterialIcons__default = /*#__PURE__*/_interopDefault(MaterialIcons);
|
|
29
30
|
var Ionicons__default = /*#__PURE__*/_interopDefault(Ionicons);
|
|
30
|
-
var Animated12__default = /*#__PURE__*/_interopDefault(Animated12);
|
|
31
31
|
var RNSlider__default = /*#__PURE__*/_interopDefault(RNSlider);
|
|
32
32
|
|
|
33
33
|
// src/theme/ThemeProvider.tsx
|
|
@@ -87,19 +87,21 @@ function darken(hex, amount) {
|
|
|
87
87
|
// src/theme/colors.ts
|
|
88
88
|
var defaultLight = {
|
|
89
89
|
background: "#ffffff",
|
|
90
|
-
foreground: "#
|
|
91
|
-
// Airbnb ink — deep near-black, never pure black
|
|
90
|
+
foreground: "#1a1a1a",
|
|
92
91
|
card: "#ffffff",
|
|
93
92
|
primary: "#1a1a1a",
|
|
94
|
-
// Near-black primary — clean, premium default
|
|
95
93
|
primaryForeground: "#ffffff",
|
|
94
|
+
// AUDIT FIX: brand accent — was undefined; falls back to primary when omitted
|
|
95
|
+
accent: "#d4561d",
|
|
96
|
+
accentForeground: "#ffffff",
|
|
96
97
|
border: "#dddddd",
|
|
97
|
-
//
|
|
98
|
-
destructive: "#
|
|
98
|
+
// AUDIT FIX: was #e53935 (4.22:1 on white — fails AA); #c72828 = 5.59:1 ✓
|
|
99
|
+
destructive: "#c72828",
|
|
99
100
|
destructiveForeground: "#ffffff",
|
|
100
101
|
success: "#1a7a45",
|
|
101
102
|
successForeground: "#ffffff",
|
|
102
|
-
|
|
103
|
+
// AUDIT FIX: was #e67e00 (2.86:1 — severe fail); #9a5200 = 5.86:1 ✓ AAA-near
|
|
104
|
+
warning: "#9a5200",
|
|
103
105
|
warningForeground: "#ffffff"
|
|
104
106
|
};
|
|
105
107
|
var defaultDark = {
|
|
@@ -108,19 +110,24 @@ var defaultDark = {
|
|
|
108
110
|
card: "#1c1c1c",
|
|
109
111
|
primary: "#fafafa",
|
|
110
112
|
primaryForeground: "#0f0f0f",
|
|
113
|
+
// AUDIT FIX: lighter accent for dark surfaces (warm amber-orange)
|
|
114
|
+
accent: "#e87645",
|
|
115
|
+
accentForeground: "#ffffff",
|
|
111
116
|
border: "#303030",
|
|
112
117
|
destructive: "#ef5350",
|
|
113
118
|
destructiveForeground: "#ffffff",
|
|
114
119
|
success: "#2e7d52",
|
|
115
120
|
successForeground: "#ffffff",
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
// AUDIT FIX: brighter amber for dark-bg visibility; dark text for contrast
|
|
122
|
+
// #f5a623 on #0f0f0f = 8.6:1 ✓ as indicator; #0f0f0f text on #f5a623 = 8.6:1 ✓
|
|
123
|
+
warning: "#f5a623",
|
|
124
|
+
warningForeground: "#0f0f0f"
|
|
118
125
|
};
|
|
119
126
|
function deriveColors(t, scheme) {
|
|
120
127
|
const dark = scheme === "dark";
|
|
121
128
|
const bg = t.background;
|
|
122
|
-
const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.
|
|
123
|
-
const foregroundMuted = mixWithBackground(t.foreground, bg, 0.
|
|
129
|
+
const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.7);
|
|
130
|
+
const foregroundMuted = mixWithBackground(t.foreground, bg, 0.62);
|
|
124
131
|
const surface = dark ? lighten(bg, -0.06) : darken(bg, 0.04);
|
|
125
132
|
const surfaceStrong = dark ? lighten(bg, -0.12) : darken(bg, 0.08);
|
|
126
133
|
const destructiveTint = dark ? withAlphaOnDark(t.destructive, 0.15, bg) : withAlphaOnWhite(t.destructive, 0.08);
|
|
@@ -144,10 +151,9 @@ function deriveColors(t, scheme) {
|
|
|
144
151
|
overlay: t.overlay ?? "rgba(0,0,0,0.45)",
|
|
145
152
|
accentResolved: t.accent ?? t.primary,
|
|
146
153
|
accentForegroundResolved: t.accentForeground ?? t.primaryForeground,
|
|
147
|
-
ring: t.primary,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// input border always = border
|
|
154
|
+
ring: t.accent ?? t.primary,
|
|
155
|
+
input: t.border,
|
|
156
|
+
separator: dark ? lighten(t.border, 0.22) : darken(t.border, 0.16)
|
|
151
157
|
};
|
|
152
158
|
}
|
|
153
159
|
|
|
@@ -203,20 +209,27 @@ var s = isWeb ? (n) => n : reactNativeSizeMatters.scale;
|
|
|
203
209
|
var vs = isWeb ? (n) => n : reactNativeSizeMatters.verticalScale;
|
|
204
210
|
var ms = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateScale;
|
|
205
211
|
var mvs = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateVerticalScale;
|
|
206
|
-
var
|
|
207
|
-
|
|
208
|
-
{ name: "
|
|
209
|
-
{ name: "
|
|
210
|
-
{ name: "
|
|
211
|
-
{ name: "
|
|
212
|
-
{ name: "
|
|
212
|
+
var glyphMapOf = (mod) => mod.glyphMap ?? {};
|
|
213
|
+
var ALL_FAMILIES = [
|
|
214
|
+
{ name: "Ionicons", component: Ionicons__default.default, getGlyphMap: () => glyphMapOf(Ionicons__default.default) },
|
|
215
|
+
{ name: "MaterialIcons", component: MaterialIcons__default.default, getGlyphMap: () => glyphMapOf(MaterialIcons__default.default) },
|
|
216
|
+
{ name: "FontAwesome5", component: FontAwesome5__default.default, getGlyphMap: () => glyphMapOf(FontAwesome5__default.default) },
|
|
217
|
+
{ name: "Entypo", component: Entypo__default.default, getGlyphMap: () => glyphMapOf(Entypo__default.default) },
|
|
218
|
+
{ name: "AntDesign", component: AntDesign__default.default, getGlyphMap: () => glyphMapOf(AntDesign__default.default) },
|
|
219
|
+
{ name: "Feather", component: Feather__default.default, getGlyphMap: () => glyphMapOf(Feather__default.default) }
|
|
213
220
|
];
|
|
221
|
+
var activeFamilies = ALL_FAMILIES;
|
|
214
222
|
var resolvedCache = null;
|
|
223
|
+
function configureIconFamilies(families) {
|
|
224
|
+
const order = families.map((n) => ALL_FAMILIES.find((f) => f.name === n)).filter((f) => f !== void 0);
|
|
225
|
+
activeFamilies = order.length > 0 ? order : ALL_FAMILIES;
|
|
226
|
+
resolvedCache = null;
|
|
227
|
+
}
|
|
215
228
|
function buildCache() {
|
|
216
229
|
const cache = /* @__PURE__ */ new Map();
|
|
217
|
-
for (const family of
|
|
218
|
-
|
|
219
|
-
for (const iconName of Object.keys(
|
|
230
|
+
for (const family of activeFamilies) {
|
|
231
|
+
const glyphMap = family.getGlyphMap();
|
|
232
|
+
for (const iconName of Object.keys(glyphMap)) {
|
|
220
233
|
cache.set(iconName, family);
|
|
221
234
|
}
|
|
222
235
|
}
|
|
@@ -231,7 +244,7 @@ function resolveFamily(name) {
|
|
|
231
244
|
function Icon({ name, size, color, family }) {
|
|
232
245
|
let resolved = null;
|
|
233
246
|
if (family) {
|
|
234
|
-
resolved =
|
|
247
|
+
resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null;
|
|
235
248
|
} else {
|
|
236
249
|
resolved = resolveFamily(name);
|
|
237
250
|
}
|
|
@@ -306,122 +319,213 @@ var BREAKPOINTS = {
|
|
|
306
319
|
};
|
|
307
320
|
var TYPOGRAPHY = {
|
|
308
321
|
"display-hero": {
|
|
309
|
-
fontFamily: "
|
|
322
|
+
fontFamily: "Sohne-Bold",
|
|
310
323
|
fontSize: 64,
|
|
311
324
|
fontWeight: "700",
|
|
312
325
|
lineHeight: 70,
|
|
313
326
|
letterSpacing: -1
|
|
314
327
|
},
|
|
315
328
|
"display-xl": {
|
|
316
|
-
fontFamily: "
|
|
329
|
+
fontFamily: "Sohne-Bold",
|
|
317
330
|
fontSize: 28,
|
|
318
331
|
fontWeight: "700",
|
|
319
332
|
lineHeight: 40,
|
|
320
333
|
letterSpacing: 0
|
|
321
334
|
},
|
|
335
|
+
// AUDIT FIX: was 22px/500 — raised to 24px/600; removes weight inversion vs display-md
|
|
322
336
|
"display-lg": {
|
|
323
|
-
fontFamily: "
|
|
324
|
-
fontSize:
|
|
325
|
-
fontWeight: "
|
|
326
|
-
lineHeight:
|
|
327
|
-
letterSpacing: -0.
|
|
337
|
+
fontFamily: "Sohne-SemiBold",
|
|
338
|
+
fontSize: 24,
|
|
339
|
+
fontWeight: "600",
|
|
340
|
+
lineHeight: 32,
|
|
341
|
+
letterSpacing: -0.3
|
|
328
342
|
},
|
|
343
|
+
// AUDIT FIX: was 21px/700 — lowered to 20px/600; weight normalised, 4px gap preserved
|
|
329
344
|
"display-md": {
|
|
330
|
-
fontFamily: "
|
|
331
|
-
fontSize:
|
|
332
|
-
fontWeight: "
|
|
333
|
-
lineHeight:
|
|
345
|
+
fontFamily: "Sohne-SemiBold",
|
|
346
|
+
fontSize: 20,
|
|
347
|
+
fontWeight: "600",
|
|
348
|
+
lineHeight: 28,
|
|
334
349
|
letterSpacing: 0
|
|
335
350
|
},
|
|
336
351
|
"display-sm": {
|
|
337
|
-
fontFamily: "
|
|
338
|
-
fontSize:
|
|
352
|
+
fontFamily: "Sohne-SemiBold",
|
|
353
|
+
fontSize: 18,
|
|
339
354
|
fontWeight: "600",
|
|
340
355
|
lineHeight: 24,
|
|
341
356
|
letterSpacing: -0.18
|
|
342
357
|
},
|
|
358
|
+
// AUDIT FIX: was 16px — raised to 17px so title-md > title-sm is size-visible
|
|
343
359
|
"title-md": {
|
|
344
|
-
fontFamily: "
|
|
345
|
-
fontSize:
|
|
360
|
+
fontFamily: "Sohne-SemiBold",
|
|
361
|
+
fontSize: 17,
|
|
346
362
|
fontWeight: "600",
|
|
347
|
-
lineHeight:
|
|
363
|
+
lineHeight: 22,
|
|
348
364
|
letterSpacing: 0
|
|
349
365
|
},
|
|
366
|
+
// AUDIT FIX: was 16px — lowered to 15px; now distinct from title-md
|
|
350
367
|
"title-sm": {
|
|
351
|
-
fontFamily: "
|
|
352
|
-
fontSize:
|
|
368
|
+
fontFamily: "Sohne-Medium",
|
|
369
|
+
fontSize: 15,
|
|
353
370
|
fontWeight: "500",
|
|
354
371
|
lineHeight: 20,
|
|
355
372
|
letterSpacing: 0
|
|
356
373
|
},
|
|
357
374
|
"body-md": {
|
|
358
|
-
fontFamily: "
|
|
375
|
+
fontFamily: "Sohne-Regular",
|
|
359
376
|
fontSize: 16,
|
|
360
377
|
fontWeight: "400",
|
|
361
378
|
lineHeight: 24,
|
|
362
379
|
letterSpacing: 0
|
|
363
380
|
},
|
|
364
381
|
"body-sm": {
|
|
365
|
-
fontFamily: "
|
|
382
|
+
fontFamily: "Sohne-Regular",
|
|
366
383
|
fontSize: 14,
|
|
367
384
|
fontWeight: "400",
|
|
368
385
|
lineHeight: 20,
|
|
369
386
|
letterSpacing: 0
|
|
370
387
|
},
|
|
371
|
-
caption: {
|
|
372
|
-
fontFamily: "
|
|
388
|
+
"caption": {
|
|
389
|
+
fontFamily: "Sohne-Medium",
|
|
373
390
|
fontSize: 14,
|
|
374
391
|
fontWeight: "500",
|
|
375
392
|
lineHeight: 18,
|
|
376
393
|
letterSpacing: 0
|
|
377
394
|
},
|
|
378
395
|
"caption-sm": {
|
|
379
|
-
fontFamily: "
|
|
396
|
+
fontFamily: "Sohne-Regular",
|
|
380
397
|
fontSize: 13,
|
|
381
398
|
fontWeight: "400",
|
|
382
399
|
lineHeight: 16,
|
|
383
400
|
letterSpacing: 0
|
|
384
401
|
},
|
|
385
402
|
"badge-text": {
|
|
386
|
-
fontFamily: "
|
|
403
|
+
fontFamily: "Sohne-SemiBold",
|
|
387
404
|
fontSize: 11,
|
|
388
405
|
fontWeight: "600",
|
|
389
|
-
lineHeight:
|
|
406
|
+
lineHeight: 14,
|
|
407
|
+
letterSpacing: 0
|
|
408
|
+
},
|
|
409
|
+
// AUDIT FIX: added badge-text-md so Badge md size has a canonical token
|
|
410
|
+
"badge-text-md": {
|
|
411
|
+
fontFamily: "Sohne-SemiBold",
|
|
412
|
+
fontSize: 13,
|
|
413
|
+
fontWeight: "600",
|
|
414
|
+
lineHeight: 16,
|
|
390
415
|
letterSpacing: 0
|
|
391
416
|
},
|
|
392
417
|
"micro-label": {
|
|
393
|
-
fontFamily: "
|
|
418
|
+
fontFamily: "Sohne-Bold",
|
|
394
419
|
fontSize: 12,
|
|
395
420
|
fontWeight: "700",
|
|
396
421
|
lineHeight: 16,
|
|
397
422
|
letterSpacing: 0
|
|
398
423
|
},
|
|
424
|
+
// AUDIT FIX: was 10px/0.8 letterSpacing — raised to 11px/0.6; minimum mobile readability
|
|
399
425
|
"uppercase-tag": {
|
|
400
|
-
fontFamily: "
|
|
401
|
-
fontSize:
|
|
426
|
+
fontFamily: "Sohne-Bold",
|
|
427
|
+
fontSize: 11,
|
|
402
428
|
fontWeight: "700",
|
|
403
|
-
lineHeight:
|
|
404
|
-
letterSpacing: 0.
|
|
429
|
+
lineHeight: 14,
|
|
430
|
+
letterSpacing: 0.6,
|
|
405
431
|
textTransform: "uppercase"
|
|
406
432
|
},
|
|
407
433
|
"button-lg": {
|
|
408
|
-
fontFamily: "
|
|
434
|
+
fontFamily: "Sohne-Medium",
|
|
409
435
|
fontSize: 16,
|
|
410
436
|
fontWeight: "500",
|
|
411
437
|
lineHeight: 22,
|
|
412
438
|
letterSpacing: 0
|
|
413
439
|
},
|
|
414
440
|
"button-sm": {
|
|
415
|
-
fontFamily: "
|
|
441
|
+
fontFamily: "Sohne-Medium",
|
|
416
442
|
fontSize: 14,
|
|
417
443
|
fontWeight: "500",
|
|
418
444
|
lineHeight: 18,
|
|
419
445
|
letterSpacing: 0
|
|
420
446
|
}
|
|
421
447
|
};
|
|
448
|
+
var SPRINGS = {
|
|
449
|
+
/** Tight, premium press feel — Buttons, Toggle, Tabs triggers. */
|
|
450
|
+
pressIn: { stiffness: 600, damping: 35, mass: 0.8 },
|
|
451
|
+
pressOut: { stiffness: 280, damping: 22, mass: 0.8 },
|
|
452
|
+
/** Slightly softer for larger surfaces — Card, ListItem, MenuItem. */
|
|
453
|
+
surfacePressIn: { stiffness: 380, damping: 30, mass: 0.95 },
|
|
454
|
+
surfacePressOut: { stiffness: 220, damping: 20, mass: 0.95 },
|
|
455
|
+
/** Settled transitions for moving indicators — Tabs pill, Switch thumb. */
|
|
456
|
+
glide: { stiffness: 380, damping: 38, mass: 1 },
|
|
457
|
+
/** Elastic indicator — Switch thumb, RadioGroup dot. */
|
|
458
|
+
elastic: { stiffness: 320, damping: 22, mass: 0.7 }
|
|
459
|
+
};
|
|
460
|
+
var TIMINGS = {
|
|
461
|
+
/** Color/opacity transitions on toggles, checkboxes, switches. */
|
|
462
|
+
state: { duration: 160 },
|
|
463
|
+
/** Focus ring on inputs. */
|
|
464
|
+
focusIn: { duration: 140 },
|
|
465
|
+
focusOut: { duration: 100 },
|
|
466
|
+
/** Accordion / collapsible content. */
|
|
467
|
+
expand: { duration: 240 },
|
|
468
|
+
collapse: { duration: 200 },
|
|
469
|
+
/** Skeleton shimmer cycle (full pass). */
|
|
470
|
+
shimmer: { duration: 1400 }
|
|
471
|
+
};
|
|
472
|
+
var EASINGS = {
|
|
473
|
+
/** Material-style ease-out — natural deceleration for state changes. */
|
|
474
|
+
standard: Animated9.Easing.bezier(0.2, 0, 0, 1),
|
|
475
|
+
/** Strong ease-out for expanding surfaces (Accordion open). */
|
|
476
|
+
expand: Animated9.Easing.bezier(0.23, 1, 0.32, 1),
|
|
477
|
+
/** Quick ease-in for collapsing. */
|
|
478
|
+
collapse: Animated9.Easing.in(Animated9.Easing.ease)
|
|
479
|
+
};
|
|
480
|
+
var PRESS_SCALE = {
|
|
481
|
+
button: 0.95,
|
|
482
|
+
card: 0.98,
|
|
483
|
+
row: 0.97,
|
|
484
|
+
chip: 0.94
|
|
485
|
+
};
|
|
486
|
+
function useHover() {
|
|
487
|
+
const [hovered, setHovered] = React26.useState(false);
|
|
488
|
+
const onMouseEnter = React26.useCallback(() => setHovered(true), []);
|
|
489
|
+
const onMouseLeave = React26.useCallback(() => setHovered(false), []);
|
|
490
|
+
if (reactNative.Platform.OS !== "web") {
|
|
491
|
+
return { hovered: false, hoverHandlers: {} };
|
|
492
|
+
}
|
|
493
|
+
return { hovered, hoverHandlers: { onMouseEnter, onMouseLeave } };
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/utils/usePressScale.ts
|
|
497
|
+
function usePressScale({
|
|
498
|
+
pressScale = PRESS_SCALE.button,
|
|
499
|
+
hoverScale = 1.02,
|
|
500
|
+
pressInSpring = SPRINGS.pressIn,
|
|
501
|
+
pressOutSpring = SPRINGS.pressOut,
|
|
502
|
+
disabled = false
|
|
503
|
+
} = {}) {
|
|
504
|
+
const scale2 = Animated9.useSharedValue(1);
|
|
505
|
+
const { hovered, hoverHandlers } = useHover();
|
|
506
|
+
const onPressIn = React26.useCallback(() => {
|
|
507
|
+
if (disabled) return;
|
|
508
|
+
scale2.value = Animated9.withSpring(pressScale, pressInSpring);
|
|
509
|
+
}, [disabled, pressScale, pressInSpring, scale2]);
|
|
510
|
+
const onPressOut = React26.useCallback(() => {
|
|
511
|
+
if (disabled) return;
|
|
512
|
+
scale2.value = Animated9.withSpring(1, pressOutSpring);
|
|
513
|
+
}, [disabled, pressOutSpring, scale2]);
|
|
514
|
+
const hoverActive = reactNative.Platform.OS === "web" && hovered && hoverScale !== 1 && !disabled;
|
|
515
|
+
const animatedStyle = Animated9.useAnimatedStyle(() => ({
|
|
516
|
+
transform: [
|
|
517
|
+
{ scale: scale2.value * (hoverActive ? hoverScale : 1) }
|
|
518
|
+
]
|
|
519
|
+
}));
|
|
520
|
+
return {
|
|
521
|
+
animatedStyle,
|
|
522
|
+
onPressIn,
|
|
523
|
+
onPressOut,
|
|
524
|
+
hoverHandlers
|
|
525
|
+
};
|
|
526
|
+
}
|
|
422
527
|
|
|
423
528
|
// src/components/Button/Button.tsx
|
|
424
|
-
var nativeDriver = reactNative.Platform.OS !== "web";
|
|
425
529
|
var containerSizeStyles = {
|
|
426
530
|
sm: { paddingHorizontal: s(16), paddingVertical: vs(10), minHeight: 40 },
|
|
427
531
|
md: { paddingHorizontal: s(24), paddingVertical: vs(14), minHeight: 48 },
|
|
@@ -433,7 +537,7 @@ var labelSizeStyles = {
|
|
|
433
537
|
lg: { ...TYPOGRAPHY["button-lg"], fontSize: ms(TYPOGRAPHY["button-lg"].fontSize + 1), lineHeight: mvs(24) }
|
|
434
538
|
};
|
|
435
539
|
var iconSizeMap = { sm: 16, md: 18, lg: 20 };
|
|
436
|
-
function
|
|
540
|
+
function ButtonBase({
|
|
437
541
|
label,
|
|
438
542
|
variant = "primary",
|
|
439
543
|
size = "md",
|
|
@@ -446,18 +550,16 @@ function Button({
|
|
|
446
550
|
disabled,
|
|
447
551
|
style,
|
|
448
552
|
onPress,
|
|
553
|
+
accessibilityLabel,
|
|
554
|
+
accessibilityHint,
|
|
449
555
|
...props
|
|
450
556
|
}) {
|
|
451
557
|
const { colors } = useTheme();
|
|
452
558
|
const isDisabled = disabled || loading;
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
};
|
|
458
|
-
const handlePressOut = () => {
|
|
459
|
-
reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver, stiffness: 280, damping: 22, mass: 0.8 }).start();
|
|
460
|
-
};
|
|
559
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
560
|
+
pressScale: PRESS_SCALE.button,
|
|
561
|
+
disabled: isDisabled
|
|
562
|
+
});
|
|
461
563
|
const handlePress = (e) => {
|
|
462
564
|
impactMedium();
|
|
463
565
|
onPress?.(e);
|
|
@@ -471,57 +573,71 @@ function Button({
|
|
|
471
573
|
const labelVariantStyle = {
|
|
472
574
|
primary: { color: colors.primaryForeground },
|
|
473
575
|
secondary: { color: colors.primary },
|
|
474
|
-
|
|
576
|
+
// AUDIT FIX: was colors.foreground — visually indistinguishable from plain text,
|
|
577
|
+
// no affordance that it's a CTA. Now uses accentResolved so text-only buttons
|
|
578
|
+
// carry the brand voltage. Falls back to primary when no accent is defined.
|
|
579
|
+
text: { color: colors.accentResolved },
|
|
475
580
|
destructive: { color: colors.destructiveForeground }
|
|
476
581
|
}[variant];
|
|
477
582
|
const textColor = iconColor ?? labelVariantStyle.color;
|
|
478
583
|
const effectiveIcon = iconName ? renderIcon(iconName, iconSizeMap[size], textColor) : typeof icon === "function" ? icon({ label, size, variant, color: textColor }) : icon;
|
|
479
|
-
const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" ? colors.primaryForeground : colors.
|
|
584
|
+
const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" ? colors.primaryForeground : colors.accentResolved;
|
|
480
585
|
const styleArray = Array.isArray(style) ? style : style ? [style] : [];
|
|
481
586
|
const flatStyle = reactNative.StyleSheet.flatten(styleArray);
|
|
482
587
|
const { flex, ...restStyle } = flatStyle || {};
|
|
483
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
484
|
-
|
|
588
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
589
|
+
Animated9__default.default.View,
|
|
485
590
|
{
|
|
486
|
-
style: [
|
|
487
|
-
|
|
488
|
-
containerVariantStyle,
|
|
489
|
-
containerSizeStyles[size],
|
|
490
|
-
fullWidth && styles.fullWidth,
|
|
491
|
-
isDisabled && styles.disabled,
|
|
492
|
-
restStyle
|
|
493
|
-
],
|
|
494
|
-
disabled: isDisabled,
|
|
495
|
-
activeOpacity: 1,
|
|
496
|
-
touchSoundDisabled: true,
|
|
497
|
-
onPress: handlePress,
|
|
498
|
-
onPressIn: handlePressIn,
|
|
499
|
-
onPressOut: handlePressOut,
|
|
500
|
-
...props
|
|
591
|
+
style: [fullWidth && styles.fullWidth, flex !== void 0 && { flex }, animatedStyle],
|
|
592
|
+
...hoverHandlers
|
|
501
593
|
},
|
|
502
|
-
|
|
503
|
-
reactNative.
|
|
504
|
-
{
|
|
505
|
-
style: [styles.label, labelVariantStyle, labelSizeStyles[size], styles.labelLoading],
|
|
506
|
-
allowFontScaling: true,
|
|
507
|
-
numberOfLines: 1
|
|
508
|
-
},
|
|
509
|
-
label
|
|
510
|
-
)) : /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon && iconPosition === "left" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon), /* @__PURE__ */ React26__default.default.createElement(
|
|
511
|
-
reactNative.Text,
|
|
594
|
+
/* @__PURE__ */ React26__default.default.createElement(
|
|
595
|
+
reactNative.TouchableOpacity,
|
|
512
596
|
{
|
|
513
|
-
style: [
|
|
514
|
-
|
|
515
|
-
|
|
597
|
+
style: [
|
|
598
|
+
styles.base,
|
|
599
|
+
containerVariantStyle,
|
|
600
|
+
containerSizeStyles[size],
|
|
601
|
+
fullWidth && styles.fullWidth,
|
|
602
|
+
isDisabled && styles.disabled,
|
|
603
|
+
restStyle
|
|
604
|
+
],
|
|
605
|
+
disabled: isDisabled,
|
|
606
|
+
activeOpacity: 1,
|
|
607
|
+
touchSoundDisabled: true,
|
|
608
|
+
onPress: handlePress,
|
|
609
|
+
onPressIn,
|
|
610
|
+
onPressOut,
|
|
611
|
+
accessibilityRole: "button",
|
|
612
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
613
|
+
accessibilityHint,
|
|
614
|
+
accessibilityState: { disabled: isDisabled, busy: loading },
|
|
615
|
+
...props
|
|
516
616
|
},
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
617
|
+
loading ? /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, /* @__PURE__ */ React26__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor, style: { marginRight: s(6) } }), /* @__PURE__ */ React26__default.default.createElement(
|
|
618
|
+
reactNative.Text,
|
|
619
|
+
{
|
|
620
|
+
style: [styles.label, labelVariantStyle, labelSizeStyles[size], styles.labelLoading],
|
|
621
|
+
allowFontScaling: true,
|
|
622
|
+
numberOfLines: 1
|
|
623
|
+
},
|
|
624
|
+
label
|
|
625
|
+
)) : /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon && iconPosition === "left" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon), /* @__PURE__ */ React26__default.default.createElement(
|
|
626
|
+
reactNative.Text,
|
|
627
|
+
{
|
|
628
|
+
style: [styles.label, labelVariantStyle, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : void 0],
|
|
629
|
+
allowFontScaling: true,
|
|
630
|
+
numberOfLines: 1
|
|
631
|
+
},
|
|
632
|
+
label
|
|
633
|
+
), effectiveIcon && iconPosition === "right" && /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, effectiveIcon))
|
|
634
|
+
)
|
|
635
|
+
);
|
|
520
636
|
}
|
|
637
|
+
var Button = React26__default.default.memo(ButtonBase);
|
|
521
638
|
var styles = reactNative.StyleSheet.create({
|
|
522
639
|
base: {
|
|
523
640
|
borderRadius: RADIUS.md,
|
|
524
|
-
// 14px — Airbnb-aligned rounded rect (not pill)
|
|
525
641
|
alignItems: "center",
|
|
526
642
|
justifyContent: "center",
|
|
527
643
|
flexDirection: "row"
|
|
@@ -533,7 +649,7 @@ var styles = reactNative.StyleSheet.create({
|
|
|
533
649
|
opacity: 0.45
|
|
534
650
|
},
|
|
535
651
|
label: {
|
|
536
|
-
fontFamily: "
|
|
652
|
+
fontFamily: "Sohne-Medium",
|
|
537
653
|
flexShrink: 1
|
|
538
654
|
},
|
|
539
655
|
labelWithIcon: {
|
|
@@ -554,15 +670,17 @@ function ButtonGroup({ children, gap = 12, vertical = false, style }) {
|
|
|
554
670
|
style
|
|
555
671
|
]
|
|
556
672
|
},
|
|
557
|
-
React26__default.default.Children.map(
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
673
|
+
React26__default.default.Children.map(children, (child) => {
|
|
674
|
+
if (!React26__default.default.isValidElement(child)) return child;
|
|
675
|
+
const childProps = child.props;
|
|
676
|
+
const extraProps = {
|
|
677
|
+
style: [child.props.style, { flex: 1 }]
|
|
678
|
+
};
|
|
679
|
+
if (!vertical && "label" in childProps && childProps["size"] === void 0) {
|
|
680
|
+
extraProps["size"] = "sm";
|
|
681
|
+
}
|
|
682
|
+
return React26__default.default.cloneElement(child, extraProps);
|
|
683
|
+
})
|
|
566
684
|
);
|
|
567
685
|
}
|
|
568
686
|
var styles2 = reactNative.StyleSheet.create({
|
|
@@ -576,13 +694,12 @@ var styles2 = reactNative.StyleSheet.create({
|
|
|
576
694
|
flexDirection: "column"
|
|
577
695
|
}
|
|
578
696
|
});
|
|
579
|
-
var nativeDriver2 = reactNative.Platform.OS !== "web";
|
|
580
697
|
var sizeMap = {
|
|
581
698
|
sm: { container: s(32), icon: 16 },
|
|
582
699
|
md: { container: s(44), icon: 20 },
|
|
583
700
|
lg: { container: s(52), icon: 24 }
|
|
584
701
|
};
|
|
585
|
-
function
|
|
702
|
+
function IconButtonBase({
|
|
586
703
|
iconName,
|
|
587
704
|
icon,
|
|
588
705
|
iconColor,
|
|
@@ -593,18 +710,16 @@ function IconButton({
|
|
|
593
710
|
disabled,
|
|
594
711
|
style,
|
|
595
712
|
onPress,
|
|
713
|
+
accessibilityLabel,
|
|
714
|
+
accessibilityHint,
|
|
596
715
|
...props
|
|
597
716
|
}) {
|
|
598
717
|
const { colors } = useTheme();
|
|
599
718
|
const isDisabled = disabled || loading;
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
};
|
|
605
|
-
const handlePressOut = () => {
|
|
606
|
-
reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver2, speed: 40, bounciness: 4 }).start();
|
|
607
|
-
};
|
|
719
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
720
|
+
pressScale: PRESS_SCALE.button,
|
|
721
|
+
disabled: isDisabled
|
|
722
|
+
});
|
|
608
723
|
const handlePress = (e) => {
|
|
609
724
|
impactLight();
|
|
610
725
|
onPress?.(e);
|
|
@@ -629,31 +744,44 @@ function IconButton({
|
|
|
629
744
|
const showBadge = badge !== void 0 && badge !== false && badge !== 0;
|
|
630
745
|
const badgeCount = typeof badge === "number" ? Math.min(badge, 99) : null;
|
|
631
746
|
const showCount = typeof badge === "number" && badge > 0;
|
|
632
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
633
|
-
|
|
747
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
748
|
+
Animated9__default.default.View,
|
|
634
749
|
{
|
|
635
|
-
style: [
|
|
636
|
-
|
|
637
|
-
containerVariantStyle,
|
|
638
|
-
{ width: containerSize, height: containerSize },
|
|
639
|
-
isDisabled && styles3.disabled,
|
|
640
|
-
style
|
|
641
|
-
],
|
|
642
|
-
disabled: isDisabled,
|
|
643
|
-
activeOpacity: 1,
|
|
644
|
-
touchSoundDisabled: true,
|
|
645
|
-
onPress: handlePress,
|
|
646
|
-
onPressIn: handlePressIn,
|
|
647
|
-
onPressOut: handlePressOut,
|
|
648
|
-
...props
|
|
750
|
+
style: [styles3.wrapper, animatedStyle],
|
|
751
|
+
...hoverHandlers
|
|
649
752
|
},
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
753
|
+
/* @__PURE__ */ React26__default.default.createElement(
|
|
754
|
+
reactNative.TouchableOpacity,
|
|
755
|
+
{
|
|
756
|
+
style: [
|
|
757
|
+
styles3.base,
|
|
758
|
+
containerVariantStyle,
|
|
759
|
+
{ width: containerSize, height: containerSize },
|
|
760
|
+
isDisabled && styles3.disabled,
|
|
761
|
+
style
|
|
762
|
+
],
|
|
763
|
+
disabled: isDisabled,
|
|
764
|
+
activeOpacity: 1,
|
|
765
|
+
touchSoundDisabled: true,
|
|
766
|
+
onPress: handlePress,
|
|
767
|
+
onPressIn,
|
|
768
|
+
onPressOut,
|
|
769
|
+
accessibilityRole: "button",
|
|
770
|
+
accessibilityLabel: accessibilityLabel ?? iconName ?? "icon button",
|
|
771
|
+
accessibilityHint,
|
|
772
|
+
accessibilityState: { disabled: isDisabled, busy: loading },
|
|
773
|
+
...props
|
|
774
|
+
},
|
|
775
|
+
loading ? /* @__PURE__ */ React26__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor }) : resolvedIcon
|
|
776
|
+
),
|
|
777
|
+
showBadge && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
778
|
+
styles3.badge,
|
|
779
|
+
{ backgroundColor: colors.primary },
|
|
780
|
+
showCount ? styles3.badgeCount : styles3.badgeDot
|
|
781
|
+
] }, showCount && /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles3.badgeText, { color: colors.primaryForeground }] }, badgeCount))
|
|
782
|
+
);
|
|
656
783
|
}
|
|
784
|
+
var IconButton = React26__default.default.memo(IconButtonBase);
|
|
657
785
|
var styles3 = reactNative.StyleSheet.create({
|
|
658
786
|
wrapper: {
|
|
659
787
|
alignSelf: "flex-start"
|
|
@@ -685,7 +813,7 @@ var styles3 = reactNative.StyleSheet.create({
|
|
|
685
813
|
paddingHorizontal: 3
|
|
686
814
|
},
|
|
687
815
|
badgeText: {
|
|
688
|
-
fontFamily: "
|
|
816
|
+
fontFamily: "Sohne-Bold",
|
|
689
817
|
fontSize: ms(9),
|
|
690
818
|
lineHeight: 14
|
|
691
819
|
}
|
|
@@ -727,7 +855,7 @@ var defaultColorVariant = {
|
|
|
727
855
|
"button-lg": "foreground",
|
|
728
856
|
"button-sm": "foreground"
|
|
729
857
|
};
|
|
730
|
-
function
|
|
858
|
+
function TextBase({ variant = "body-md", color, style, children, ...props }) {
|
|
731
859
|
const { colors } = useTheme();
|
|
732
860
|
const colorKey = defaultColorVariant[variant] ?? "foreground";
|
|
733
861
|
const resolvedColor = color ?? colors[colorKey];
|
|
@@ -741,63 +869,90 @@ function Text3({ variant = "body-md", color, style, children, ...props }) {
|
|
|
741
869
|
children
|
|
742
870
|
);
|
|
743
871
|
}
|
|
872
|
+
var Text3 = React26__default.default.memo(TextBase);
|
|
873
|
+
function useColorTransition(active, options = {}) {
|
|
874
|
+
const { duration = TIMINGS.state.duration } = options;
|
|
875
|
+
const progress = Animated9.useSharedValue(active ? 1 : 0);
|
|
876
|
+
React26.useEffect(() => {
|
|
877
|
+
progress.value = Animated9.withTiming(active ? 1 : 0, { duration, easing: EASINGS.standard });
|
|
878
|
+
}, [active, duration, progress]);
|
|
879
|
+
return progress;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// src/components/Input/Input.tsx
|
|
744
883
|
var webInputResetStyle = reactNative.Platform.OS === "web" ? { outlineStyle: "none", outlineWidth: 0, outlineColor: "transparent", boxShadow: "none" } : {};
|
|
745
|
-
function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = "text", containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, ...props }) {
|
|
884
|
+
function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = "text", containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }) {
|
|
746
885
|
const { colors } = useTheme();
|
|
747
886
|
const [focused, setFocused] = React26.useState(false);
|
|
748
887
|
const [showPassword, setShowPassword] = React26.useState(false);
|
|
749
|
-
const
|
|
888
|
+
const focusProgress = useColorTransition(focused, {
|
|
889
|
+
duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration
|
|
890
|
+
});
|
|
750
891
|
const isDisabled = disabled || editable === false;
|
|
751
892
|
const isPassword = type === "password";
|
|
752
893
|
const effectiveSecure = isPassword ? !showPassword : secureTextEntry;
|
|
753
894
|
const effectivePrefix = prefixIcon ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.foregroundMuted) : prefix;
|
|
754
|
-
const effectiveSuffix = isPassword && !suffix && !suffixIcon ? /* @__PURE__ */ React26__default.default.createElement(
|
|
895
|
+
const effectiveSuffix = isPassword && !suffix && !suffixIcon ? /* @__PURE__ */ React26__default.default.createElement(
|
|
896
|
+
reactNative.TouchableOpacity,
|
|
897
|
+
{
|
|
898
|
+
onPress: () => setShowPassword(!showPassword),
|
|
899
|
+
style: styles4.passwordToggle,
|
|
900
|
+
activeOpacity: 0.6,
|
|
901
|
+
accessibilityRole: "button",
|
|
902
|
+
accessibilityLabel: showPassword ? "Hide password" : "Show password"
|
|
903
|
+
},
|
|
904
|
+
/* @__PURE__ */ React26__default.default.createElement(vectorIcons.AntDesign, { name: showPassword ? "eye" : "eye-invisible", size: 20, color: colors.foregroundMuted })
|
|
905
|
+
) : suffixIcon ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted) : suffix;
|
|
906
|
+
const borderAnimStyle = Animated9.useAnimatedStyle(() => ({
|
|
907
|
+
borderColor: error ? colors.destructive : Animated9.interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
|
|
908
|
+
borderWidth: error ? 2 : Animated9.interpolate(focusProgress.value, [0, 1], [1, 2])
|
|
909
|
+
}));
|
|
755
910
|
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles4.container, isDisabled && styles4.containerDisabled, containerStyle] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React26__default.default.createElement(
|
|
756
|
-
|
|
911
|
+
Animated9__default.default.View,
|
|
757
912
|
{
|
|
758
913
|
style: [
|
|
759
914
|
styles4.inputWrapper,
|
|
760
|
-
{
|
|
761
|
-
borderColor: error ? colors.destructive : focusAnim.interpolate({
|
|
762
|
-
inputRange: [0, 1],
|
|
763
|
-
outputRange: [colors.border, colors.primary]
|
|
764
|
-
}),
|
|
765
|
-
backgroundColor: isDisabled ? colors.surface : colors.background
|
|
766
|
-
},
|
|
915
|
+
{ backgroundColor: isDisabled ? colors.surface : colors.background },
|
|
767
916
|
inputWrapperStyle
|
|
768
917
|
]
|
|
769
918
|
},
|
|
919
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles4.borderOverlay, borderAnimStyle], pointerEvents: "none" }),
|
|
770
920
|
effectivePrefix ? typeof effectivePrefix === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.prefixText, { color: colors.foregroundMuted }, prefixStyle], allowFontScaling: true }, effectivePrefix) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles4.prefixContainer }, effectivePrefix) : null,
|
|
771
921
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
772
922
|
reactNative.TextInput,
|
|
773
923
|
{
|
|
774
924
|
style: [
|
|
775
925
|
styles4.input,
|
|
776
|
-
{
|
|
777
|
-
color: colors.foreground
|
|
778
|
-
},
|
|
926
|
+
{ color: colors.foreground },
|
|
779
927
|
webInputResetStyle,
|
|
780
928
|
style
|
|
781
929
|
],
|
|
782
930
|
onFocus: (e) => {
|
|
783
931
|
setFocused(true);
|
|
784
|
-
reactNative.Animated.timing(focusAnim, { toValue: 1, duration: 120, easing: reactNative.Easing.out(reactNative.Easing.ease), useNativeDriver: false }).start();
|
|
785
932
|
onFocus?.(e);
|
|
786
933
|
},
|
|
787
934
|
onBlur: (e) => {
|
|
788
935
|
setFocused(false);
|
|
789
|
-
reactNative.Animated.timing(focusAnim, { toValue: 0, duration: 80, easing: reactNative.Easing.out(reactNative.Easing.ease), useNativeDriver: false }).start();
|
|
790
936
|
onBlur?.(e);
|
|
791
937
|
},
|
|
792
938
|
placeholderTextColor: colors.foregroundMuted,
|
|
793
939
|
allowFontScaling: true,
|
|
794
940
|
secureTextEntry: effectiveSecure,
|
|
795
941
|
editable: isDisabled ? false : editable,
|
|
942
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
796
943
|
...props
|
|
797
944
|
}
|
|
798
945
|
),
|
|
799
946
|
effectiveSuffix ? typeof effectiveSuffix === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.suffixText, { color: colors.foregroundMuted }, suffixStyle], allowFontScaling: true }, effectiveSuffix) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles4.suffixContainer }, effectiveSuffix) : null
|
|
800
|
-
), error ? /* @__PURE__ */ React26__default.default.createElement(
|
|
947
|
+
), error ? /* @__PURE__ */ React26__default.default.createElement(
|
|
948
|
+
reactNative.Text,
|
|
949
|
+
{
|
|
950
|
+
style: [styles4.helperText, { color: colors.destructive }],
|
|
951
|
+
allowFontScaling: true,
|
|
952
|
+
accessibilityLiveRegion: "polite"
|
|
953
|
+
},
|
|
954
|
+
error
|
|
955
|
+
) : null, !error && hint ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles4.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
|
|
801
956
|
}
|
|
802
957
|
var styles4 = reactNative.StyleSheet.create({
|
|
803
958
|
container: {
|
|
@@ -807,21 +962,25 @@ var styles4 = reactNative.StyleSheet.create({
|
|
|
807
962
|
opacity: 0.6
|
|
808
963
|
},
|
|
809
964
|
label: {
|
|
810
|
-
fontFamily: "
|
|
965
|
+
fontFamily: "Sohne-Medium",
|
|
811
966
|
fontSize: ms(14)
|
|
812
|
-
// caption size for input labels
|
|
813
967
|
},
|
|
814
968
|
inputWrapper: {
|
|
815
969
|
flexDirection: "row",
|
|
816
970
|
alignItems: "center",
|
|
817
|
-
|
|
971
|
+
// Border lives on borderOverlay (absolute) so its 1px→2px focus change
|
|
972
|
+
// never resizes this box. Wrapper itself carries no border.
|
|
818
973
|
borderRadius: 8,
|
|
819
974
|
paddingHorizontal: s(14),
|
|
820
975
|
paddingVertical: vs(11),
|
|
821
976
|
minHeight: 48
|
|
822
977
|
},
|
|
978
|
+
borderOverlay: {
|
|
979
|
+
...reactNative.StyleSheet.absoluteFillObject,
|
|
980
|
+
borderRadius: 8
|
|
981
|
+
},
|
|
823
982
|
input: {
|
|
824
|
-
fontFamily: "
|
|
983
|
+
fontFamily: "Sohne-Regular",
|
|
825
984
|
flex: 1,
|
|
826
985
|
fontSize: ms(16),
|
|
827
986
|
paddingVertical: vs(2),
|
|
@@ -831,7 +990,7 @@ var styles4 = reactNative.StyleSheet.create({
|
|
|
831
990
|
marginRight: s(8)
|
|
832
991
|
},
|
|
833
992
|
prefixText: {
|
|
834
|
-
fontFamily: "
|
|
993
|
+
fontFamily: "Sohne-Regular",
|
|
835
994
|
fontSize: ms(15),
|
|
836
995
|
marginRight: s(8)
|
|
837
996
|
},
|
|
@@ -839,15 +998,18 @@ var styles4 = reactNative.StyleSheet.create({
|
|
|
839
998
|
marginLeft: s(8)
|
|
840
999
|
},
|
|
841
1000
|
suffixText: {
|
|
842
|
-
fontFamily: "
|
|
1001
|
+
fontFamily: "Sohne-Regular",
|
|
843
1002
|
fontSize: ms(15),
|
|
844
1003
|
marginLeft: s(8)
|
|
845
1004
|
},
|
|
1005
|
+
// AUDIT FIX: was padding: s(4) → ~28px tap target. Now 12px padding → ~44px.
|
|
1006
|
+
// Negative margin compensates so the visual icon position is unchanged.
|
|
846
1007
|
passwordToggle: {
|
|
847
|
-
padding: s(
|
|
1008
|
+
padding: s(12),
|
|
1009
|
+
margin: -s(8)
|
|
848
1010
|
},
|
|
849
1011
|
helperText: {
|
|
850
|
-
fontFamily: "
|
|
1012
|
+
fontFamily: "Sohne-Regular",
|
|
851
1013
|
fontSize: ms(13)
|
|
852
1014
|
}
|
|
853
1015
|
});
|
|
@@ -867,7 +1029,7 @@ var sizeIconGap = {
|
|
|
867
1029
|
lg: s(6)
|
|
868
1030
|
};
|
|
869
1031
|
var sizeIconSize = { sm: 10, md: 12, lg: 14 };
|
|
870
|
-
function
|
|
1032
|
+
function BadgeBase({ label, children, variant = "default", size = "md", icon, iconName, iconColor, style }) {
|
|
871
1033
|
const { colors } = useTheme();
|
|
872
1034
|
const containerStyle = {
|
|
873
1035
|
default: { backgroundColor: colors.primary },
|
|
@@ -895,6 +1057,7 @@ function Badge({ label, children, variant = "default", size = "md", icon, iconNa
|
|
|
895
1057
|
const content = children ?? label;
|
|
896
1058
|
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles5.container, containerStyle, sizePadding[size], { gap: sizeIconGap[size] }, style] }, effectiveIcon, typeof content === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles5.label, { color: textColor }, sizeFontSize[size]], allowFontScaling: true }, content) : content);
|
|
897
1059
|
}
|
|
1060
|
+
var Badge = React26__default.default.memo(BadgeBase);
|
|
898
1061
|
var styles5 = reactNative.StyleSheet.create({
|
|
899
1062
|
container: {
|
|
900
1063
|
borderRadius: 9999,
|
|
@@ -903,33 +1066,17 @@ var styles5 = reactNative.StyleSheet.create({
|
|
|
903
1066
|
alignItems: "center"
|
|
904
1067
|
},
|
|
905
1068
|
label: {
|
|
906
|
-
fontFamily: "
|
|
1069
|
+
fontFamily: "Sohne-Medium"
|
|
907
1070
|
}
|
|
908
1071
|
});
|
|
909
|
-
|
|
910
|
-
function Card({ children, variant = "elevated", onPress, style }) {
|
|
1072
|
+
function Card({ children, variant = "elevated", onPress, style, accessibilityLabel }) {
|
|
911
1073
|
const { colors } = useTheme();
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
stiffness: 400,
|
|
919
|
-
damping: 30,
|
|
920
|
-
mass: 1
|
|
921
|
-
}).start();
|
|
922
|
-
};
|
|
923
|
-
const handlePressOut = () => {
|
|
924
|
-
if (!onPress) return;
|
|
925
|
-
reactNative.Animated.spring(scale2, {
|
|
926
|
-
toValue: 1,
|
|
927
|
-
useNativeDriver: nativeDriver3,
|
|
928
|
-
stiffness: 250,
|
|
929
|
-
damping: 24,
|
|
930
|
-
mass: 1
|
|
931
|
-
}).start();
|
|
932
|
-
};
|
|
1074
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
1075
|
+
pressScale: PRESS_SCALE.card,
|
|
1076
|
+
pressInSpring: SPRINGS.surfacePressIn,
|
|
1077
|
+
pressOutSpring: SPRINGS.surfacePressOut,
|
|
1078
|
+
disabled: !onPress
|
|
1079
|
+
});
|
|
933
1080
|
const handlePress = () => {
|
|
934
1081
|
if (!onPress) return;
|
|
935
1082
|
impactLight();
|
|
@@ -938,11 +1085,14 @@ function Card({ children, variant = "elevated", onPress, style }) {
|
|
|
938
1085
|
const variantStyle = {
|
|
939
1086
|
elevated: {
|
|
940
1087
|
backgroundColor: colors.card,
|
|
941
|
-
|
|
1088
|
+
// AUDIT FIX: removed borderColor — shadow is the depth signal; a border on
|
|
1089
|
+
// top of a shadow creates redundant double-framing that reads as "heavy"
|
|
1090
|
+
// rather than "elevated". borderWidth: 0 overrides the base style's borderWidth: 1.
|
|
1091
|
+
borderWidth: 0,
|
|
942
1092
|
shadowColor: "#000",
|
|
943
|
-
shadowOffset: { width: 0, height:
|
|
944
|
-
shadowOpacity: 0.
|
|
945
|
-
shadowRadius:
|
|
1093
|
+
shadowOffset: { width: 0, height: 4 },
|
|
1094
|
+
shadowOpacity: 0.09,
|
|
1095
|
+
shadowRadius: 14,
|
|
946
1096
|
elevation: 4
|
|
947
1097
|
},
|
|
948
1098
|
outlined: {
|
|
@@ -960,14 +1110,16 @@ function Card({ children, variant = "elevated", onPress, style }) {
|
|
|
960
1110
|
}[variant];
|
|
961
1111
|
const cardContent = /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles6.card, variantStyle, style] }, children);
|
|
962
1112
|
if (onPress) {
|
|
963
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1113
|
+
return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: animatedStyle, ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
|
|
964
1114
|
reactNative.TouchableOpacity,
|
|
965
1115
|
{
|
|
966
1116
|
onPress: handlePress,
|
|
967
|
-
onPressIn
|
|
968
|
-
onPressOut
|
|
1117
|
+
onPressIn,
|
|
1118
|
+
onPressOut,
|
|
969
1119
|
activeOpacity: 1,
|
|
970
|
-
touchSoundDisabled: true
|
|
1120
|
+
touchSoundDisabled: true,
|
|
1121
|
+
accessibilityRole: "button",
|
|
1122
|
+
accessibilityLabel
|
|
971
1123
|
},
|
|
972
1124
|
cardContent
|
|
973
1125
|
));
|
|
@@ -983,7 +1135,7 @@ function CardTitle({ children, style }) {
|
|
|
983
1135
|
}
|
|
984
1136
|
function CardDescription({ children, style }) {
|
|
985
1137
|
const { colors } = useTheme();
|
|
986
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles6.description, { color: colors.
|
|
1138
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles6.description, { color: colors.foregroundSubtle }, style], allowFontScaling: true }, children);
|
|
987
1139
|
}
|
|
988
1140
|
function CardContent({ children, style }) {
|
|
989
1141
|
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles6.content, style] }, children);
|
|
@@ -994,7 +1146,6 @@ function CardFooter({ children, style }) {
|
|
|
994
1146
|
var styles6 = reactNative.StyleSheet.create({
|
|
995
1147
|
card: {
|
|
996
1148
|
borderRadius: RADIUS.md,
|
|
997
|
-
// 14px — Airbnb property card spec
|
|
998
1149
|
borderWidth: 1
|
|
999
1150
|
},
|
|
1000
1151
|
header: {
|
|
@@ -1003,12 +1154,14 @@ var styles6 = reactNative.StyleSheet.create({
|
|
|
1003
1154
|
gap: vs(4)
|
|
1004
1155
|
},
|
|
1005
1156
|
title: {
|
|
1006
|
-
fontFamily: "
|
|
1157
|
+
fontFamily: "Sohne-SemiBold",
|
|
1007
1158
|
fontSize: ms(16),
|
|
1008
1159
|
lineHeight: mvs(22)
|
|
1009
1160
|
},
|
|
1161
|
+
// AUDIT FIX: was foregroundMuted (2.2:1 fail) — description text now uses
|
|
1162
|
+
// foregroundSubtle (5.9:1 ✓) which is readable while still visually secondary.
|
|
1010
1163
|
description: {
|
|
1011
|
-
fontFamily: "
|
|
1164
|
+
fontFamily: "Sohne-Regular",
|
|
1012
1165
|
fontSize: ms(13),
|
|
1013
1166
|
lineHeight: mvs(18)
|
|
1014
1167
|
},
|
|
@@ -1031,7 +1184,7 @@ function Separator({ orientation = "horizontal", style }) {
|
|
|
1031
1184
|
{
|
|
1032
1185
|
style: [
|
|
1033
1186
|
orientation === "horizontal" ? styles7.horizontal : styles7.vertical,
|
|
1034
|
-
{ backgroundColor: colors.
|
|
1187
|
+
{ backgroundColor: colors.separator },
|
|
1035
1188
|
style
|
|
1036
1189
|
]
|
|
1037
1190
|
}
|
|
@@ -1040,13 +1193,11 @@ function Separator({ orientation = "horizontal", style }) {
|
|
|
1040
1193
|
var styles7 = reactNative.StyleSheet.create({
|
|
1041
1194
|
horizontal: {
|
|
1042
1195
|
height: 1,
|
|
1043
|
-
width: "100%"
|
|
1044
|
-
opacity: 0.7
|
|
1196
|
+
width: "100%"
|
|
1045
1197
|
},
|
|
1046
1198
|
vertical: {
|
|
1047
1199
|
width: 1,
|
|
1048
|
-
height: "100%"
|
|
1049
|
-
opacity: 0.7
|
|
1200
|
+
height: "100%"
|
|
1050
1201
|
}
|
|
1051
1202
|
});
|
|
1052
1203
|
var sizeMap2 = {
|
|
@@ -1079,7 +1230,7 @@ var styles8 = reactNative.StyleSheet.create({
|
|
|
1079
1230
|
gap: vs(6)
|
|
1080
1231
|
},
|
|
1081
1232
|
label: {
|
|
1082
|
-
fontFamily: "
|
|
1233
|
+
fontFamily: "Sohne-Regular",
|
|
1083
1234
|
lineHeight: mvs(18)
|
|
1084
1235
|
}
|
|
1085
1236
|
});
|
|
@@ -1092,20 +1243,19 @@ function Skeleton({
|
|
|
1092
1243
|
style
|
|
1093
1244
|
}) {
|
|
1094
1245
|
const { colors, colorScheme } = useTheme();
|
|
1095
|
-
const
|
|
1246
|
+
const shimmer = Animated9.useSharedValue(0);
|
|
1096
1247
|
const [containerWidth, setContainerWidth] = React26.useState(300);
|
|
1097
1248
|
const shimmerHighlight = colorScheme === "dark" ? "rgba(255,255,255,0.08)" : "rgba(255,255,255,0.7)";
|
|
1098
1249
|
React26.useEffect(() => {
|
|
1099
|
-
|
|
1100
|
-
|
|
1250
|
+
shimmer.value = Animated9.withRepeat(
|
|
1251
|
+
Animated9.withTiming(1, { duration: TIMINGS.shimmer.duration, easing: Animated9.Easing.linear }),
|
|
1252
|
+
-1,
|
|
1253
|
+
false
|
|
1101
1254
|
);
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
inputRange: [0, 1],
|
|
1107
|
-
outputRange: [-containerWidth, containerWidth]
|
|
1108
|
-
});
|
|
1255
|
+
}, [shimmer]);
|
|
1256
|
+
const shimmerStyle = Animated9.useAnimatedStyle(() => ({
|
|
1257
|
+
transform: [{ translateX: -containerWidth + shimmer.value * (containerWidth * 2) }]
|
|
1258
|
+
}));
|
|
1109
1259
|
const resolvedWidth = preset === "circle" ? s(diameter) : preset === "text" ? "60%" : width;
|
|
1110
1260
|
const resolvedHeight = preset === "circle" ? s(diameter) : preset === "text" ? 14 : height;
|
|
1111
1261
|
const resolvedRadius = preset === "circle" ? 9999 : preset === "text" ? 4 : borderRadius;
|
|
@@ -1117,9 +1267,12 @@ function Skeleton({
|
|
|
1117
1267
|
{ width: resolvedWidth, height: resolvedHeight, borderRadius: resolvedRadius, backgroundColor: colors.surface },
|
|
1118
1268
|
style
|
|
1119
1269
|
],
|
|
1120
|
-
onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width)
|
|
1270
|
+
onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width),
|
|
1271
|
+
accessibilityRole: "progressbar",
|
|
1272
|
+
accessibilityLabel: "Loading",
|
|
1273
|
+
accessibilityState: { busy: true }
|
|
1121
1274
|
},
|
|
1122
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
1275
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [reactNative.StyleSheet.absoluteFill, shimmerStyle] }, /* @__PURE__ */ React26__default.default.createElement(
|
|
1123
1276
|
expoLinearGradient.LinearGradient,
|
|
1124
1277
|
{
|
|
1125
1278
|
colors: ["transparent", shimmerHighlight, "transparent"],
|
|
@@ -1162,7 +1315,7 @@ function getInitials(fallback, fallbackText) {
|
|
|
1162
1315
|
}
|
|
1163
1316
|
return "?";
|
|
1164
1317
|
}
|
|
1165
|
-
function
|
|
1318
|
+
function AvatarBase({ src, fallback, fallbackText, size = "md", status, style }) {
|
|
1166
1319
|
const { colors } = useTheme();
|
|
1167
1320
|
const [imageError, setImageError] = React26.useState(false);
|
|
1168
1321
|
const dimension = typeof size === "number" ? size : sizeMap3[size];
|
|
@@ -1213,6 +1366,7 @@ function Avatar({ src, fallback, fallbackText, size = "md", status, style }) {
|
|
|
1213
1366
|
}
|
|
1214
1367
|
));
|
|
1215
1368
|
}
|
|
1369
|
+
var Avatar = React26__default.default.memo(AvatarBase);
|
|
1216
1370
|
var styles10 = reactNative.StyleSheet.create({
|
|
1217
1371
|
wrapper: {
|
|
1218
1372
|
alignSelf: "flex-start",
|
|
@@ -1223,7 +1377,7 @@ var styles10 = reactNative.StyleSheet.create({
|
|
|
1223
1377
|
justifyContent: "center"
|
|
1224
1378
|
},
|
|
1225
1379
|
fallback: {
|
|
1226
|
-
fontFamily: "
|
|
1380
|
+
fontFamily: "Sohne-Medium"
|
|
1227
1381
|
},
|
|
1228
1382
|
statusDot: {
|
|
1229
1383
|
position: "absolute",
|
|
@@ -1232,11 +1386,30 @@ var styles10 = reactNative.StyleSheet.create({
|
|
|
1232
1386
|
}
|
|
1233
1387
|
});
|
|
1234
1388
|
function AlertBanner({ title, description, variant = "default", icon, iconName, iconColor, style }) {
|
|
1235
|
-
const { colors } = useTheme();
|
|
1236
|
-
const
|
|
1237
|
-
const
|
|
1389
|
+
const { colors, colorScheme } = useTheme();
|
|
1390
|
+
const isDark = colorScheme === "dark";
|
|
1391
|
+
const accentColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : variant === "warning" ? colors.warning : colors.foreground;
|
|
1392
|
+
const bgColor = variant === "destructive" ? isDark ? "rgba(239, 83, 80, 0.15)" : "rgba(199, 40, 40, 0.10)" : variant === "success" ? isDark ? "rgba(46, 125, 82, 0.15)" : "rgba(26, 122, 69, 0.10)" : variant === "warning" ? isDark ? "rgba(245, 166, 35, 0.15)" : "rgba(154, 82, 0, 0.10)" : colors.surface;
|
|
1393
|
+
const borderColor = variant === "destructive" ? isDark ? "rgba(239, 83, 80, 0.30)" : "rgba(199, 40, 40, 0.25)" : variant === "success" ? isDark ? "rgba(46, 125, 82, 0.30)" : "rgba(26, 122, 69, 0.25)" : variant === "warning" ? isDark ? "rgba(245, 166, 35, 0.30)" : "rgba(154, 82, 0, 0.25)" : colors.border;
|
|
1394
|
+
const defaultIcon = variant === "success" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: ms(16), color: accentColor }) : variant === "destructive" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.MaterialIcons, { name: "error-outline", size: ms(17), color: accentColor }) : variant === "warning" ? /* @__PURE__ */ React26__default.default.createElement(vectorIcons.MaterialIcons, { name: "warning-amber", size: ms(17), color: accentColor }) : (
|
|
1395
|
+
// AUDIT FIX: default variant previously used colors.primary (near-black)
|
|
1396
|
+
// as the info icon tint — ambiguous and heavy. accentResolved gives it
|
|
1397
|
+
// a meaningful chromatic signal when an accent is defined.
|
|
1398
|
+
/* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "info-with-circle", size: ms(16), color: accentColor })
|
|
1399
|
+
);
|
|
1238
1400
|
const effectiveIcon = iconName ? renderIcon(iconName, ms(16), iconColor ?? accentColor) : icon ?? defaultIcon;
|
|
1239
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1401
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1402
|
+
reactNative.View,
|
|
1403
|
+
{
|
|
1404
|
+
style: [
|
|
1405
|
+
styles11.container,
|
|
1406
|
+
{ backgroundColor: bgColor, borderWidth: 1, borderColor },
|
|
1407
|
+
style
|
|
1408
|
+
]
|
|
1409
|
+
},
|
|
1410
|
+
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles11.iconSlot }, effectiveIcon),
|
|
1411
|
+
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles11.content }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles11.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles11.description, { color: colors.foreground, opacity: 0.85 }], allowFontScaling: true }, description) : null)
|
|
1412
|
+
);
|
|
1240
1413
|
}
|
|
1241
1414
|
var styles11 = reactNative.StyleSheet.create({
|
|
1242
1415
|
container: {
|
|
@@ -1244,8 +1417,8 @@ var styles11 = reactNative.StyleSheet.create({
|
|
|
1244
1417
|
alignItems: "flex-start",
|
|
1245
1418
|
borderRadius: RADIUS.lg,
|
|
1246
1419
|
gap: s(8),
|
|
1247
|
-
paddingVertical: vs(
|
|
1248
|
-
paddingHorizontal: s(
|
|
1420
|
+
paddingVertical: vs(10),
|
|
1421
|
+
paddingHorizontal: s(12)
|
|
1249
1422
|
},
|
|
1250
1423
|
iconSlot: {
|
|
1251
1424
|
marginTop: vs(1)
|
|
@@ -1255,41 +1428,40 @@ var styles11 = reactNative.StyleSheet.create({
|
|
|
1255
1428
|
gap: vs(2)
|
|
1256
1429
|
},
|
|
1257
1430
|
title: {
|
|
1258
|
-
fontFamily: "
|
|
1259
|
-
fontSize: ms(13)
|
|
1260
|
-
lineHeight: ms(19)
|
|
1431
|
+
fontFamily: "Sohne-Medium",
|
|
1432
|
+
fontSize: ms(13)
|
|
1261
1433
|
},
|
|
1262
1434
|
description: {
|
|
1263
|
-
fontFamily: "
|
|
1264
|
-
fontSize: ms(12)
|
|
1265
|
-
lineHeight: ms(17)
|
|
1435
|
+
fontFamily: "Sohne-Regular",
|
|
1436
|
+
fontSize: ms(12)
|
|
1266
1437
|
}
|
|
1267
1438
|
});
|
|
1268
|
-
function Progress({ value = 0, max = 100, variant = "default", style }) {
|
|
1439
|
+
function Progress({ value = 0, max = 100, variant = "default", style, accessibilityLabel }) {
|
|
1269
1440
|
const { colors } = useTheme();
|
|
1270
1441
|
const percent = Math.min(Math.max(value / max * 100, 0), 100);
|
|
1271
1442
|
const [trackWidth, setTrackWidth] = React26.useState(0);
|
|
1272
|
-
const animatedWidth =
|
|
1443
|
+
const animatedWidth = Animated9.useSharedValue(0);
|
|
1273
1444
|
React26.useEffect(() => {
|
|
1274
1445
|
if (trackWidth === 0) return;
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}).start();
|
|
1281
|
-
}, [percent, trackWidth]);
|
|
1446
|
+
animatedWidth.value = Animated9.withSpring(percent / 100 * trackWidth, SPRINGS.glide);
|
|
1447
|
+
}, [percent, trackWidth, animatedWidth]);
|
|
1448
|
+
const indicatorAnimatedStyle = Animated9.useAnimatedStyle(() => ({
|
|
1449
|
+
width: animatedWidth.value
|
|
1450
|
+
}));
|
|
1282
1451
|
const indicatorColor = variant === "success" ? colors.success : variant === "warning" ? colors.warning : variant === "destructive" ? colors.destructive : colors.primary;
|
|
1283
1452
|
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1284
1453
|
reactNative.View,
|
|
1285
1454
|
{
|
|
1286
1455
|
style: [styles12.track, { backgroundColor: colors.surface }, style],
|
|
1287
|
-
onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width)
|
|
1456
|
+
onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width),
|
|
1457
|
+
accessibilityRole: "progressbar",
|
|
1458
|
+
accessibilityLabel,
|
|
1459
|
+
accessibilityValue: { min: 0, max: 100, now: Math.round(percent) }
|
|
1288
1460
|
},
|
|
1289
1461
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
1290
|
-
|
|
1462
|
+
Animated9__default.default.View,
|
|
1291
1463
|
{
|
|
1292
|
-
style: [styles12.indicator, {
|
|
1464
|
+
style: [styles12.indicator, { backgroundColor: indicatorColor }, indicatorAnimatedStyle]
|
|
1293
1465
|
}
|
|
1294
1466
|
)
|
|
1295
1467
|
);
|
|
@@ -1373,7 +1545,7 @@ var styles13 = reactNative.StyleSheet.create({
|
|
|
1373
1545
|
marginTop: vs(16)
|
|
1374
1546
|
},
|
|
1375
1547
|
title: {
|
|
1376
|
-
fontFamily: "
|
|
1548
|
+
fontFamily: "Sohne-Medium",
|
|
1377
1549
|
fontSize: ms(18),
|
|
1378
1550
|
textAlign: "center"
|
|
1379
1551
|
},
|
|
@@ -1382,7 +1554,7 @@ var styles13 = reactNative.StyleSheet.create({
|
|
|
1382
1554
|
marginTop: vs(10)
|
|
1383
1555
|
},
|
|
1384
1556
|
description: {
|
|
1385
|
-
fontFamily: "
|
|
1557
|
+
fontFamily: "Sohne-Regular",
|
|
1386
1558
|
fontSize: ms(14),
|
|
1387
1559
|
lineHeight: mvs(20),
|
|
1388
1560
|
textAlign: "center"
|
|
@@ -1406,22 +1578,28 @@ function Textarea({
|
|
|
1406
1578
|
style,
|
|
1407
1579
|
onFocus,
|
|
1408
1580
|
onBlur,
|
|
1581
|
+
accessibilityLabel,
|
|
1409
1582
|
...props
|
|
1410
1583
|
}) {
|
|
1411
1584
|
const { colors } = useTheme();
|
|
1412
1585
|
const [focused, setFocused] = React26.useState(false);
|
|
1586
|
+
const focusProgress = useColorTransition(focused, {
|
|
1587
|
+
duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration
|
|
1588
|
+
});
|
|
1413
1589
|
const resolvedPrefixIcon = prefixIcon ? renderIcon(prefixIcon, ms(16), prefixIconColor ?? colors.foregroundMuted) : prefixIconNode;
|
|
1590
|
+
const borderAnimStyle = Animated9.useAnimatedStyle(() => ({
|
|
1591
|
+
borderColor: error ? colors.destructive : Animated9.interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
|
|
1592
|
+
borderWidth: error ? 2 : Animated9.interpolate(focusProgress.value, [0, 1], [1, 2])
|
|
1593
|
+
}));
|
|
1414
1594
|
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles14.container, containerStyle] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles14.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React26__default.default.createElement(
|
|
1415
|
-
|
|
1595
|
+
Animated9__default.default.View,
|
|
1416
1596
|
{
|
|
1417
1597
|
style: [
|
|
1418
1598
|
styles14.inputWrapper,
|
|
1419
|
-
{
|
|
1420
|
-
borderColor: error ? colors.destructive : focused ? colors.ring ?? colors.primary : colors.border,
|
|
1421
|
-
backgroundColor: colors.background
|
|
1422
|
-
}
|
|
1599
|
+
{ backgroundColor: colors.background }
|
|
1423
1600
|
]
|
|
1424
1601
|
},
|
|
1602
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles14.borderOverlay, borderAnimStyle], pointerEvents: "none" }),
|
|
1425
1603
|
resolvedPrefixIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles14.prefixIcon }, resolvedPrefixIcon) : null,
|
|
1426
1604
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
1427
1605
|
reactNative.TextInput,
|
|
@@ -1448,124 +1626,113 @@ function Textarea({
|
|
|
1448
1626
|
},
|
|
1449
1627
|
placeholderTextColor: colors.foregroundMuted,
|
|
1450
1628
|
allowFontScaling: true,
|
|
1629
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
1451
1630
|
...props
|
|
1452
1631
|
}
|
|
1453
1632
|
)
|
|
1454
|
-
), error ? /* @__PURE__ */ React26__default.default.createElement(
|
|
1633
|
+
), error ? /* @__PURE__ */ React26__default.default.createElement(
|
|
1634
|
+
reactNative.Text,
|
|
1635
|
+
{
|
|
1636
|
+
style: [styles14.helperText, { color: colors.destructive }],
|
|
1637
|
+
allowFontScaling: true,
|
|
1638
|
+
accessibilityLiveRegion: "polite"
|
|
1639
|
+
},
|
|
1640
|
+
error
|
|
1641
|
+
) : null, !error && hint ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles14.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
|
|
1455
1642
|
}
|
|
1456
1643
|
var styles14 = reactNative.StyleSheet.create({
|
|
1457
1644
|
container: {
|
|
1458
1645
|
gap: vs(4)
|
|
1459
1646
|
},
|
|
1460
1647
|
label: {
|
|
1461
|
-
fontFamily: "
|
|
1648
|
+
fontFamily: "Sohne-Medium",
|
|
1462
1649
|
fontSize: ms(13),
|
|
1463
1650
|
lineHeight: vs(18),
|
|
1464
1651
|
marginBottom: vs(2)
|
|
1465
1652
|
},
|
|
1466
1653
|
inputWrapper: {
|
|
1467
|
-
|
|
1654
|
+
// Border lives on borderOverlay (absolute); wrapper carries none so the
|
|
1655
|
+
// focus weight change never reflows content.
|
|
1468
1656
|
borderRadius: 8,
|
|
1469
1657
|
paddingHorizontal: s(14),
|
|
1470
1658
|
paddingVertical: vs(11),
|
|
1471
1659
|
gap: s(8)
|
|
1472
1660
|
},
|
|
1661
|
+
borderOverlay: {
|
|
1662
|
+
...reactNative.StyleSheet.absoluteFillObject,
|
|
1663
|
+
borderRadius: 8
|
|
1664
|
+
},
|
|
1473
1665
|
prefixIcon: {
|
|
1474
1666
|
alignItems: "flex-start",
|
|
1475
1667
|
justifyContent: "flex-start",
|
|
1476
1668
|
paddingTop: vs(2)
|
|
1477
1669
|
},
|
|
1478
1670
|
input: {
|
|
1479
|
-
fontFamily: "
|
|
1671
|
+
fontFamily: "Sohne-Regular",
|
|
1480
1672
|
fontSize: ms(14),
|
|
1481
1673
|
lineHeight: vs(22),
|
|
1482
1674
|
padding: 0,
|
|
1483
1675
|
margin: 0
|
|
1484
1676
|
},
|
|
1485
1677
|
helperText: {
|
|
1486
|
-
fontFamily: "
|
|
1678
|
+
fontFamily: "Sohne-Regular",
|
|
1487
1679
|
fontSize: ms(12),
|
|
1488
1680
|
lineHeight: vs(16),
|
|
1489
1681
|
marginTop: vs(4)
|
|
1490
1682
|
}
|
|
1491
1683
|
});
|
|
1492
|
-
var nativeDriver4 = reactNative.Platform.OS !== "web";
|
|
1493
1684
|
function Checkbox({
|
|
1494
1685
|
checked = false,
|
|
1495
1686
|
onCheckedChange,
|
|
1496
1687
|
label,
|
|
1497
1688
|
disabled,
|
|
1498
|
-
style
|
|
1689
|
+
style,
|
|
1690
|
+
accessibilityLabel
|
|
1499
1691
|
}) {
|
|
1500
1692
|
const { colors } = useTheme();
|
|
1501
|
-
const
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
React26.useEffect(() => {
|
|
1505
|
-
reactNative.Animated.parallel([
|
|
1506
|
-
reactNative.Animated.timing(bgOpacity, {
|
|
1507
|
-
toValue: checked ? 1 : 0,
|
|
1508
|
-
duration: 150,
|
|
1509
|
-
useNativeDriver: false
|
|
1510
|
-
}),
|
|
1511
|
-
reactNative.Animated.timing(checkOpacity, {
|
|
1512
|
-
toValue: checked ? 1 : 0,
|
|
1513
|
-
duration: 120,
|
|
1514
|
-
useNativeDriver: false
|
|
1515
|
-
})
|
|
1516
|
-
]).start();
|
|
1517
|
-
}, [checked, bgOpacity, checkOpacity]);
|
|
1518
|
-
const borderColor = bgOpacity.interpolate({
|
|
1519
|
-
inputRange: [0, 1],
|
|
1520
|
-
outputRange: [colors.border, colors.primary]
|
|
1693
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut } = usePressScale({
|
|
1694
|
+
pressScale: PRESS_SCALE.button,
|
|
1695
|
+
disabled
|
|
1521
1696
|
});
|
|
1522
|
-
const
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
};
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
style: [styles15.row, style],
|
|
1537
|
-
onPress: () => {
|
|
1538
|
-
selectionAsync();
|
|
1539
|
-
onCheckedChange?.(!checked);
|
|
1540
|
-
},
|
|
1541
|
-
onPressIn: handlePressIn,
|
|
1542
|
-
onPressOut: handlePressOut,
|
|
1543
|
-
disabled,
|
|
1544
|
-
activeOpacity: 1,
|
|
1545
|
-
touchSoundDisabled: true
|
|
1546
|
-
},
|
|
1547
|
-
/* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React26__default.default.createElement(
|
|
1548
|
-
reactNative.Animated.View,
|
|
1549
|
-
{
|
|
1550
|
-
style: [
|
|
1551
|
-
styles15.box,
|
|
1552
|
-
{
|
|
1553
|
-
borderColor,
|
|
1554
|
-
backgroundColor,
|
|
1555
|
-
opacity: disabled ? 0.45 : 1
|
|
1556
|
-
}
|
|
1557
|
-
]
|
|
1558
|
-
},
|
|
1559
|
-
/* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: { opacity: checkOpacity } }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles15.checkmark, { borderColor: colors.primaryForeground }] }))
|
|
1560
|
-
)),
|
|
1561
|
-
label ? /* @__PURE__ */ React26__default.default.createElement(
|
|
1562
|
-
reactNative.Text,
|
|
1697
|
+
const progress = useColorTransition(checked);
|
|
1698
|
+
const boxStyle = Animated9.useAnimatedStyle(() => ({
|
|
1699
|
+
borderColor: Animated9.interpolateColor(progress.value, [0, 1], [colors.border, colors.primary]),
|
|
1700
|
+
backgroundColor: Animated9.interpolateColor(progress.value, [0, 1], ["transparent", colors.primary])
|
|
1701
|
+
}));
|
|
1702
|
+
const checkStyle = Animated9.useAnimatedStyle(() => ({
|
|
1703
|
+
opacity: Animated9.withTiming(checked ? 1 : 0, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
|
|
1704
|
+
}));
|
|
1705
|
+
return (
|
|
1706
|
+
// AUDIT FIX: opacity was applied only to the box, leaving the label at full
|
|
1707
|
+
// opacity when disabled — a contradictory visual signal. Now the entire row
|
|
1708
|
+
// dims uniformly so label and control communicate the same disabled state.
|
|
1709
|
+
/* @__PURE__ */ React26__default.default.createElement(
|
|
1710
|
+
reactNative.TouchableOpacity,
|
|
1563
1711
|
{
|
|
1564
|
-
style: [styles15.
|
|
1565
|
-
|
|
1712
|
+
style: [styles15.row, disabled && styles15.rowDisabled, style],
|
|
1713
|
+
onPress: () => {
|
|
1714
|
+
selectionAsync();
|
|
1715
|
+
onCheckedChange?.(!checked);
|
|
1716
|
+
},
|
|
1717
|
+
onPressIn,
|
|
1718
|
+
onPressOut,
|
|
1719
|
+
disabled,
|
|
1720
|
+
activeOpacity: 1,
|
|
1721
|
+
touchSoundDisabled: true,
|
|
1722
|
+
accessibilityRole: "checkbox",
|
|
1723
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
1724
|
+
accessibilityState: { checked, disabled: !!disabled }
|
|
1566
1725
|
},
|
|
1567
|
-
|
|
1568
|
-
|
|
1726
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: scaleStyle }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles15.box, boxStyle] }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: checkStyle }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles15.checkmark, { borderColor: colors.primaryForeground }] })))),
|
|
1727
|
+
label ? /* @__PURE__ */ React26__default.default.createElement(
|
|
1728
|
+
reactNative.Text,
|
|
1729
|
+
{
|
|
1730
|
+
style: [styles15.label, { color: colors.foreground }],
|
|
1731
|
+
allowFontScaling: true
|
|
1732
|
+
},
|
|
1733
|
+
label
|
|
1734
|
+
) : null
|
|
1735
|
+
)
|
|
1569
1736
|
);
|
|
1570
1737
|
}
|
|
1571
1738
|
var styles15 = reactNative.StyleSheet.create({
|
|
@@ -1574,6 +1741,10 @@ var styles15 = reactNative.StyleSheet.create({
|
|
|
1574
1741
|
alignItems: "center",
|
|
1575
1742
|
gap: s(12)
|
|
1576
1743
|
},
|
|
1744
|
+
// AUDIT FIX: was inline opacity on the box only
|
|
1745
|
+
rowDisabled: {
|
|
1746
|
+
opacity: 0.45
|
|
1747
|
+
},
|
|
1577
1748
|
box: {
|
|
1578
1749
|
width: s(24),
|
|
1579
1750
|
height: s(24),
|
|
@@ -1590,53 +1761,48 @@ var styles15 = reactNative.StyleSheet.create({
|
|
|
1590
1761
|
transform: [{ rotate: "-45deg" }, { translateY: -1 }]
|
|
1591
1762
|
},
|
|
1592
1763
|
label: {
|
|
1593
|
-
fontFamily: "
|
|
1764
|
+
fontFamily: "Sohne-Regular",
|
|
1594
1765
|
fontSize: ms(14),
|
|
1595
1766
|
lineHeight: mvs(20)
|
|
1596
1767
|
}
|
|
1597
1768
|
});
|
|
1598
|
-
var nativeDriver5 = reactNative.Platform.OS !== "web";
|
|
1599
1769
|
var TRACK_WIDTH = s(52);
|
|
1600
1770
|
var TRACK_HEIGHT = s(30);
|
|
1601
1771
|
var THUMB_SIZE = s(24);
|
|
1602
1772
|
var THUMB_OFFSET = s(3);
|
|
1603
1773
|
var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
|
|
1604
1774
|
var ICON_SIZE = s(13);
|
|
1605
|
-
function Switch({ checked = false, onCheckedChange, disabled, style }) {
|
|
1775
|
+
function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel }) {
|
|
1606
1776
|
const { colors } = useTheme();
|
|
1607
|
-
const
|
|
1608
|
-
const trackOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
|
|
1609
|
-
const checkOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
|
|
1610
|
-
const crossOpacity = React26.useRef(new reactNative.Animated.Value(checked ? 0 : 1)).current;
|
|
1777
|
+
const progress = Animated9.useSharedValue(checked ? 1 : 0);
|
|
1611
1778
|
React26.useEffect(() => {
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
}
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
}
|
|
1639
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [{ opacity: disabled ? 0.45 : 1 }, style] }, /* @__PURE__ */ React26__default.default.createElement(
|
|
1779
|
+
progress.value = Animated9.withSpring(checked ? 1 : 0, SPRINGS.elastic);
|
|
1780
|
+
}, [checked, progress]);
|
|
1781
|
+
const thumbStyle = Animated9.useAnimatedStyle(() => ({
|
|
1782
|
+
transform: [{ translateX: progress.value * THUMB_TRAVEL }]
|
|
1783
|
+
}));
|
|
1784
|
+
const trackStyle = Animated9.useAnimatedStyle(() => ({
|
|
1785
|
+
backgroundColor: Animated9.interpolateColor(
|
|
1786
|
+
progress.value,
|
|
1787
|
+
[0, 1],
|
|
1788
|
+
[colors.surfaceStrong, colors.primary]
|
|
1789
|
+
)
|
|
1790
|
+
}));
|
|
1791
|
+
const trackBorderStyle = Animated9.useAnimatedStyle(() => ({
|
|
1792
|
+
borderWidth: 1.5,
|
|
1793
|
+
borderColor: Animated9.interpolateColor(
|
|
1794
|
+
progress.value,
|
|
1795
|
+
[0, 1],
|
|
1796
|
+
[colors.border, "transparent"]
|
|
1797
|
+
)
|
|
1798
|
+
}));
|
|
1799
|
+
const checkIconStyle = Animated9.useAnimatedStyle(() => ({
|
|
1800
|
+
opacity: Animated9.withTiming(checked ? 1 : 0, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
|
|
1801
|
+
}));
|
|
1802
|
+
const crossIconStyle = Animated9.useAnimatedStyle(() => ({
|
|
1803
|
+
opacity: Animated9.withTiming(checked ? 0 : 1, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
|
|
1804
|
+
}));
|
|
1805
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [{ opacity: disabled ? 0.45 : 1, alignSelf: "flex-start" }, style] }, /* @__PURE__ */ React26__default.default.createElement(
|
|
1640
1806
|
reactNative.TouchableOpacity,
|
|
1641
1807
|
{
|
|
1642
1808
|
onPress: () => {
|
|
@@ -1646,29 +1812,33 @@ function Switch({ checked = false, onCheckedChange, disabled, style }) {
|
|
|
1646
1812
|
disabled,
|
|
1647
1813
|
activeOpacity: 0.8,
|
|
1648
1814
|
touchSoundDisabled: true,
|
|
1649
|
-
|
|
1815
|
+
accessibilityRole: "switch",
|
|
1816
|
+
accessibilityLabel,
|
|
1817
|
+
accessibilityState: { checked, disabled: !!disabled },
|
|
1818
|
+
style: styles16.touchable
|
|
1650
1819
|
},
|
|
1651
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
1652
|
-
|
|
1820
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.track, trackStyle] }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.trackBorder, trackBorderStyle], pointerEvents: "none" }), /* @__PURE__ */ React26__default.default.createElement(
|
|
1821
|
+
Animated9__default.default.View,
|
|
1653
1822
|
{
|
|
1654
|
-
style: [
|
|
1655
|
-
styles16.thumb,
|
|
1656
|
-
{ backgroundColor: colors.primaryForeground, transform: [{ translateX }] }
|
|
1657
|
-
]
|
|
1823
|
+
style: [styles16.thumb, { backgroundColor: colors.primaryForeground }, thumbStyle]
|
|
1658
1824
|
},
|
|
1659
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
1660
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
1825
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.iconWrapper, checkIconStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Feather, { name: "check", size: ICON_SIZE, color: colors.primary })),
|
|
1826
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles16.iconWrapper, crossIconStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
|
|
1661
1827
|
))
|
|
1662
1828
|
));
|
|
1663
1829
|
}
|
|
1664
1830
|
var styles16 = reactNative.StyleSheet.create({
|
|
1665
|
-
|
|
1831
|
+
touchable: {
|
|
1832
|
+
alignSelf: "flex-start"
|
|
1833
|
+
},
|
|
1666
1834
|
track: {
|
|
1667
1835
|
width: TRACK_WIDTH,
|
|
1668
1836
|
height: TRACK_HEIGHT,
|
|
1669
1837
|
borderRadius: TRACK_HEIGHT / 2
|
|
1670
|
-
|
|
1671
|
-
|
|
1838
|
+
},
|
|
1839
|
+
trackBorder: {
|
|
1840
|
+
...reactNative.StyleSheet.absoluteFillObject,
|
|
1841
|
+
borderRadius: TRACK_HEIGHT / 2
|
|
1672
1842
|
},
|
|
1673
1843
|
thumb: {
|
|
1674
1844
|
position: "absolute",
|
|
@@ -1686,10 +1856,28 @@ var styles16 = reactNative.StyleSheet.create({
|
|
|
1686
1856
|
justifyContent: "center"
|
|
1687
1857
|
},
|
|
1688
1858
|
iconWrapper: {
|
|
1689
|
-
position: "absolute"
|
|
1859
|
+
position: "absolute",
|
|
1860
|
+
alignItems: "center",
|
|
1861
|
+
justifyContent: "center"
|
|
1690
1862
|
}
|
|
1691
1863
|
});
|
|
1692
|
-
|
|
1864
|
+
function ToggleIcon({ pressed, iconName, activeIconName, icon, activeIcon, iconColor, activeIconColor, iconSize, primaryColor, mutedColor }) {
|
|
1865
|
+
const renderProp = (prop) => {
|
|
1866
|
+
if (!prop) return null;
|
|
1867
|
+
if (typeof prop === "function") return prop(pressed);
|
|
1868
|
+
return prop;
|
|
1869
|
+
};
|
|
1870
|
+
if (pressed) {
|
|
1871
|
+
if (activeIconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(activeIconName, iconSize, activeIconColor ?? primaryColor));
|
|
1872
|
+
const active = renderProp(activeIcon);
|
|
1873
|
+
if (active) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, active);
|
|
1874
|
+
return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: iconSize, color: primaryColor });
|
|
1875
|
+
}
|
|
1876
|
+
if (iconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(iconName, iconSize, iconColor ?? mutedColor));
|
|
1877
|
+
const custom = renderProp(icon);
|
|
1878
|
+
if (custom) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, custom);
|
|
1879
|
+
return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "circle", size: iconSize, color: mutedColor });
|
|
1880
|
+
}
|
|
1693
1881
|
var sizeStyles = {
|
|
1694
1882
|
sm: { paddingHorizontal: s(12), paddingVertical: vs(8), minWidth: s(40), minHeight: vs(40) },
|
|
1695
1883
|
md: { paddingHorizontal: s(16), paddingVertical: vs(12), minWidth: s(44), minHeight: vs(44) },
|
|
@@ -1710,82 +1898,75 @@ function Toggle({
|
|
|
1710
1898
|
activeIconColor,
|
|
1711
1899
|
disabled,
|
|
1712
1900
|
style,
|
|
1901
|
+
accessibilityLabel,
|
|
1713
1902
|
...props
|
|
1714
1903
|
}) {
|
|
1715
1904
|
const { colors } = useTheme();
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
reactNative.Animated.timing(pressAnim, {
|
|
1720
|
-
toValue: pressed ? 1 : 0,
|
|
1721
|
-
duration: 150,
|
|
1722
|
-
easing: reactNative.Easing.out(reactNative.Easing.ease),
|
|
1723
|
-
useNativeDriver: false
|
|
1724
|
-
}).start();
|
|
1725
|
-
}, [pressed, pressAnim]);
|
|
1726
|
-
const handlePressIn = () => {
|
|
1727
|
-
if (disabled) return;
|
|
1728
|
-
reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver6, stiffness: 600, damping: 35, mass: 0.8 }).start();
|
|
1729
|
-
};
|
|
1730
|
-
const handlePressOut = () => {
|
|
1731
|
-
reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver6, stiffness: 280, damping: 22, mass: 0.8 }).start();
|
|
1732
|
-
};
|
|
1733
|
-
const borderColor = pressAnim.interpolate({
|
|
1734
|
-
inputRange: [0, 1],
|
|
1735
|
-
outputRange: [variant === "outline" ? colors.border : "transparent", colors.primary]
|
|
1736
|
-
});
|
|
1737
|
-
const backgroundColor = pressAnim.interpolate({
|
|
1738
|
-
inputRange: [0, 1],
|
|
1739
|
-
outputRange: ["transparent", colors.surfaceStrong]
|
|
1740
|
-
});
|
|
1741
|
-
const textColor = pressAnim.interpolate({
|
|
1742
|
-
inputRange: [0, 1],
|
|
1743
|
-
outputRange: [colors.foreground, colors.primary]
|
|
1905
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
1906
|
+
pressScale: PRESS_SCALE.button,
|
|
1907
|
+
disabled
|
|
1744
1908
|
});
|
|
1909
|
+
const progress = useColorTransition(pressed);
|
|
1910
|
+
const inactiveBorder = variant === "outline" ? colors.border : "transparent";
|
|
1911
|
+
const surfaceStyle = Animated9.useAnimatedStyle(() => ({
|
|
1912
|
+
borderColor: Animated9.interpolateColor(progress.value, [0, 1], [inactiveBorder, colors.primary]),
|
|
1913
|
+
backgroundColor: Animated9.interpolateColor(progress.value, [0, 1], ["transparent", colors.surfaceStrong])
|
|
1914
|
+
}));
|
|
1915
|
+
const textStyle = Animated9.useAnimatedStyle(() => ({
|
|
1916
|
+
color: Animated9.interpolateColor(progress.value, [0, 1], [colors.foreground, colors.primary])
|
|
1917
|
+
}));
|
|
1745
1918
|
const iconSize = iconSizeMap2[size];
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
if (!prop) return null;
|
|
1749
|
-
if (typeof prop === "function") return prop(pressed);
|
|
1750
|
-
return prop;
|
|
1751
|
-
};
|
|
1752
|
-
if (pressed) {
|
|
1753
|
-
if (activeIconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(activeIconName, iconSize, activeIconColor ?? colors.primary));
|
|
1754
|
-
const active = renderProp(activeIcon);
|
|
1755
|
-
if (active) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, active);
|
|
1756
|
-
return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "check-circle", size: iconSize, color: colors.primary });
|
|
1757
|
-
}
|
|
1758
|
-
if (iconName) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, renderIcon(iconName, iconSize, iconColor ?? colors.foregroundMuted));
|
|
1759
|
-
const custom = renderProp(icon);
|
|
1760
|
-
if (custom) return /* @__PURE__ */ React26__default.default.createElement(React26__default.default.Fragment, null, custom);
|
|
1761
|
-
return /* @__PURE__ */ React26__default.default.createElement(vectorIcons.FontAwesome5, { name: "circle", size: iconSize, color: colors.foregroundMuted });
|
|
1762
|
-
};
|
|
1763
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.Animated.View, { style: [{ transform: [{ scale: scale2 }] }, disabled && styles17.disabled, style] }, /* @__PURE__ */ React26__default.default.createElement(
|
|
1764
|
-
reactNative.TouchableOpacity,
|
|
1919
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1920
|
+
Animated9__default.default.View,
|
|
1765
1921
|
{
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
onPressedChange?.(!pressed);
|
|
1769
|
-
},
|
|
1770
|
-
onPressIn: handlePressIn,
|
|
1771
|
-
onPressOut: handlePressOut,
|
|
1772
|
-
disabled,
|
|
1773
|
-
activeOpacity: 1,
|
|
1774
|
-
touchSoundDisabled: true,
|
|
1775
|
-
...props
|
|
1922
|
+
style: [scaleStyle, disabled && styles17.disabled, style],
|
|
1923
|
+
...hoverHandlers
|
|
1776
1924
|
},
|
|
1777
1925
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
1778
|
-
reactNative.
|
|
1926
|
+
reactNative.TouchableOpacity,
|
|
1779
1927
|
{
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1928
|
+
onPress: () => {
|
|
1929
|
+
selectionAsync();
|
|
1930
|
+
onPressedChange?.(!pressed);
|
|
1931
|
+
},
|
|
1932
|
+
onPressIn,
|
|
1933
|
+
onPressOut,
|
|
1934
|
+
disabled,
|
|
1935
|
+
activeOpacity: 1,
|
|
1936
|
+
touchSoundDisabled: true,
|
|
1937
|
+
accessibilityRole: "button",
|
|
1938
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
1939
|
+
accessibilityState: { selected: pressed, disabled: !!disabled },
|
|
1940
|
+
...props
|
|
1785
1941
|
},
|
|
1786
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
1942
|
+
/* @__PURE__ */ React26__default.default.createElement(
|
|
1943
|
+
Animated9__default.default.View,
|
|
1944
|
+
{
|
|
1945
|
+
style: [
|
|
1946
|
+
styles17.base,
|
|
1947
|
+
sizeStyles[size],
|
|
1948
|
+
{ borderWidth: 2 },
|
|
1949
|
+
surfaceStyle
|
|
1950
|
+
]
|
|
1951
|
+
},
|
|
1952
|
+
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles17.inner }, /* @__PURE__ */ React26__default.default.createElement(
|
|
1953
|
+
ToggleIcon,
|
|
1954
|
+
{
|
|
1955
|
+
pressed,
|
|
1956
|
+
iconName,
|
|
1957
|
+
activeIconName,
|
|
1958
|
+
icon,
|
|
1959
|
+
activeIcon,
|
|
1960
|
+
iconColor,
|
|
1961
|
+
activeIconColor,
|
|
1962
|
+
iconSize,
|
|
1963
|
+
primaryColor: colors.primary,
|
|
1964
|
+
mutedColor: colors.foregroundMuted
|
|
1965
|
+
}
|
|
1966
|
+
), label ? /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.Text, { style: [styles17.label, textStyle], allowFontScaling: true }, label) : null)
|
|
1967
|
+
)
|
|
1787
1968
|
)
|
|
1788
|
-
)
|
|
1969
|
+
);
|
|
1789
1970
|
}
|
|
1790
1971
|
var styles17 = reactNative.StyleSheet.create({
|
|
1791
1972
|
base: {
|
|
@@ -1801,65 +1982,64 @@ var styles17 = reactNative.StyleSheet.create({
|
|
|
1801
1982
|
opacity: 0.45
|
|
1802
1983
|
},
|
|
1803
1984
|
label: {
|
|
1804
|
-
fontFamily: "
|
|
1985
|
+
fontFamily: "Sohne-Medium",
|
|
1805
1986
|
fontSize: ms(14)
|
|
1806
1987
|
}
|
|
1807
1988
|
});
|
|
1808
|
-
var nativeDriver7 = reactNative.Platform.OS !== "web";
|
|
1809
1989
|
function RadioItem({
|
|
1810
1990
|
option,
|
|
1811
1991
|
selected,
|
|
1812
1992
|
onSelect
|
|
1813
1993
|
}) {
|
|
1814
1994
|
const { colors } = useTheme();
|
|
1815
|
-
const
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
const
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
activeOpacity: 1,
|
|
1836
|
-
touchSoundDisabled: true,
|
|
1837
|
-
disabled: option.disabled
|
|
1838
|
-
},
|
|
1995
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut } = usePressScale({
|
|
1996
|
+
pressScale: PRESS_SCALE.button,
|
|
1997
|
+
disabled: option.disabled
|
|
1998
|
+
});
|
|
1999
|
+
const colorProgress = useColorTransition(selected);
|
|
2000
|
+
const dotScale = Animated9.useSharedValue(selected ? 1 : 0);
|
|
2001
|
+
React26.useEffect(() => {
|
|
2002
|
+
dotScale.value = Animated9.withSpring(selected ? 1 : 0, SPRINGS.elastic);
|
|
2003
|
+
}, [selected, dotScale]);
|
|
2004
|
+
const radioStyle = Animated9.useAnimatedStyle(() => ({
|
|
2005
|
+
borderColor: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.border, colors.primary])
|
|
2006
|
+
}));
|
|
2007
|
+
const dotStyle = Animated9.useAnimatedStyle(() => ({
|
|
2008
|
+
transform: [{ scale: dotScale.value }],
|
|
2009
|
+
opacity: dotScale.value
|
|
2010
|
+
}));
|
|
2011
|
+
return (
|
|
2012
|
+
// AUDIT FIX: opacity was applied only to the radio circle, leaving the label
|
|
2013
|
+
// at full opacity when disabled. The whole row now dims uniformly so users
|
|
2014
|
+
// get a single, consistent disabled signal across the entire item.
|
|
1839
2015
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
1840
|
-
reactNative.
|
|
2016
|
+
reactNative.TouchableOpacity,
|
|
1841
2017
|
{
|
|
1842
|
-
style: [
|
|
1843
|
-
|
|
1844
|
-
{
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
transform: [{ scale: scale2 }]
|
|
2018
|
+
style: [styles18.row, option.disabled && styles18.rowDisabled],
|
|
2019
|
+
onPress: () => {
|
|
2020
|
+
if (!option.disabled) {
|
|
2021
|
+
selectionAsync();
|
|
2022
|
+
onSelect();
|
|
1848
2023
|
}
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
{ color: option.disabled ? colors.foregroundMuted : colors.foreground }
|
|
1859
|
-
],
|
|
1860
|
-
allowFontScaling: true
|
|
2024
|
+
},
|
|
2025
|
+
onPressIn,
|
|
2026
|
+
onPressOut,
|
|
2027
|
+
activeOpacity: 1,
|
|
2028
|
+
touchSoundDisabled: true,
|
|
2029
|
+
disabled: option.disabled,
|
|
2030
|
+
accessibilityRole: "radio",
|
|
2031
|
+
accessibilityLabel: option.label,
|
|
2032
|
+
accessibilityState: { checked: selected, disabled: !!option.disabled }
|
|
1861
2033
|
},
|
|
1862
|
-
|
|
2034
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: scaleStyle }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles18.radio, radioStyle] }, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles18.dot, { backgroundColor: colors.primary }, dotStyle] }))),
|
|
2035
|
+
/* @__PURE__ */ React26__default.default.createElement(
|
|
2036
|
+
reactNative.Text,
|
|
2037
|
+
{
|
|
2038
|
+
style: [styles18.label, { color: colors.foreground }],
|
|
2039
|
+
allowFontScaling: true
|
|
2040
|
+
},
|
|
2041
|
+
option.label
|
|
2042
|
+
)
|
|
1863
2043
|
)
|
|
1864
2044
|
);
|
|
1865
2045
|
}
|
|
@@ -1868,17 +2048,26 @@ function RadioGroup({
|
|
|
1868
2048
|
value,
|
|
1869
2049
|
onValueChange,
|
|
1870
2050
|
orientation = "vertical",
|
|
1871
|
-
style
|
|
2051
|
+
style,
|
|
2052
|
+
accessibilityLabel
|
|
1872
2053
|
}) {
|
|
1873
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1874
|
-
|
|
2054
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
2055
|
+
reactNative.View,
|
|
1875
2056
|
{
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
2057
|
+
style: [styles18.container, orientation === "horizontal" && styles18.horizontal, style],
|
|
2058
|
+
accessibilityRole: "radiogroup",
|
|
2059
|
+
accessibilityLabel
|
|
2060
|
+
},
|
|
2061
|
+
options.map((option) => /* @__PURE__ */ React26__default.default.createElement(
|
|
2062
|
+
RadioItem,
|
|
2063
|
+
{
|
|
2064
|
+
key: option.value,
|
|
2065
|
+
option,
|
|
2066
|
+
selected: option.value === value,
|
|
2067
|
+
onSelect: () => onValueChange?.(option.value)
|
|
2068
|
+
}
|
|
2069
|
+
))
|
|
2070
|
+
);
|
|
1882
2071
|
}
|
|
1883
2072
|
var styles18 = reactNative.StyleSheet.create({
|
|
1884
2073
|
container: {
|
|
@@ -1893,6 +2082,10 @@ var styles18 = reactNative.StyleSheet.create({
|
|
|
1893
2082
|
alignItems: "center",
|
|
1894
2083
|
gap: s(12)
|
|
1895
2084
|
},
|
|
2085
|
+
// AUDIT FIX: was opacity on the inner circle only
|
|
2086
|
+
rowDisabled: {
|
|
2087
|
+
opacity: 0.45
|
|
2088
|
+
},
|
|
1896
2089
|
radio: {
|
|
1897
2090
|
width: s(24),
|
|
1898
2091
|
height: s(24),
|
|
@@ -1907,12 +2100,11 @@ var styles18 = reactNative.StyleSheet.create({
|
|
|
1907
2100
|
borderRadius: s(5)
|
|
1908
2101
|
},
|
|
1909
2102
|
label: {
|
|
1910
|
-
fontFamily: "
|
|
2103
|
+
fontFamily: "Sohne-Regular",
|
|
1911
2104
|
fontSize: ms(14),
|
|
1912
2105
|
lineHeight: mvs(20)
|
|
1913
2106
|
}
|
|
1914
2107
|
});
|
|
1915
|
-
var nativeDriver8 = reactNative.Platform.OS !== "web";
|
|
1916
2108
|
function TabTrigger({
|
|
1917
2109
|
tab,
|
|
1918
2110
|
isActive,
|
|
@@ -1921,13 +2113,9 @@ function TabTrigger({
|
|
|
1921
2113
|
variant
|
|
1922
2114
|
}) {
|
|
1923
2115
|
const { colors } = useTheme();
|
|
1924
|
-
const
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
};
|
|
1928
|
-
const handlePressOut = () => {
|
|
1929
|
-
reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver8, stiffness: 280, damping: 22, mass: 0.8 }).start();
|
|
1930
|
-
};
|
|
2116
|
+
const { animatedStyle, onPressIn, onPressOut } = usePressScale({
|
|
2117
|
+
pressScale: PRESS_SCALE.button
|
|
2118
|
+
});
|
|
1931
2119
|
const isUnderline = variant === "underline";
|
|
1932
2120
|
return /* @__PURE__ */ React26__default.default.createElement(
|
|
1933
2121
|
reactNative.TouchableOpacity,
|
|
@@ -1938,19 +2126,25 @@ function TabTrigger({
|
|
|
1938
2126
|
isUnderline && isActive && { borderBottomColor: colors.primary }
|
|
1939
2127
|
],
|
|
1940
2128
|
onPress,
|
|
1941
|
-
onPressIn
|
|
1942
|
-
onPressOut
|
|
2129
|
+
onPressIn,
|
|
2130
|
+
onPressOut,
|
|
1943
2131
|
onLayout,
|
|
1944
2132
|
activeOpacity: 1,
|
|
1945
|
-
touchSoundDisabled: true
|
|
2133
|
+
touchSoundDisabled: true,
|
|
2134
|
+
accessibilityRole: "tab",
|
|
2135
|
+
accessibilityState: { selected: isActive },
|
|
2136
|
+
accessibilityLabel: tab.label
|
|
1946
2137
|
},
|
|
1947
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
2138
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: animatedStyle }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles19.triggerInner }, tab.icon ? typeof tab.icon === "function" ? tab.icon(isActive) : tab.icon : null, /* @__PURE__ */ React26__default.default.createElement(
|
|
1948
2139
|
reactNative.Text,
|
|
1949
2140
|
{
|
|
1950
2141
|
style: [
|
|
1951
2142
|
styles19.triggerLabel,
|
|
1952
|
-
|
|
1953
|
-
|
|
2143
|
+
// AUDIT FIX: active state now only changes color, never font metrics.
|
|
2144
|
+
// Previously: inactive=Regular, active=Medium (pill) or SemiBold+fontSize14 (underline)
|
|
2145
|
+
// The weight/size change caused measurable layout reflow every tab switch.
|
|
2146
|
+
// Solution: all labels render at SemiBold always; active = foreground, inactive = foregroundMuted.
|
|
2147
|
+
{ color: isActive ? colors.foreground : colors.foregroundMuted }
|
|
1954
2148
|
],
|
|
1955
2149
|
allowFontScaling: true
|
|
1956
2150
|
},
|
|
@@ -1963,75 +2157,85 @@ function Tabs({ tabs, variant = "pill", value, onValueChange, children, style })
|
|
|
1963
2157
|
const { colors } = useTheme();
|
|
1964
2158
|
const active = value ?? internal;
|
|
1965
2159
|
const tabLayouts = React26.useRef({});
|
|
1966
|
-
const pillX =
|
|
1967
|
-
const pillWidth =
|
|
2160
|
+
const pillX = Animated9.useSharedValue(0);
|
|
2161
|
+
const pillWidth = Animated9.useSharedValue(0);
|
|
1968
2162
|
const initialised = React26.useRef(false);
|
|
1969
|
-
const animatePill = (tabValue, animate) => {
|
|
2163
|
+
const animatePill = React26.useCallback((tabValue, animate) => {
|
|
1970
2164
|
const layout = tabLayouts.current[tabValue];
|
|
1971
2165
|
if (!layout) return;
|
|
1972
2166
|
if (animate) {
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
reactNative.Animated.spring(pillWidth, { toValue: layout.width, useNativeDriver: false, stiffness: 380, damping: 38, mass: 1 })
|
|
1976
|
-
]).start();
|
|
2167
|
+
pillX.value = Animated9.withSpring(layout.x, SPRINGS.glide);
|
|
2168
|
+
pillWidth.value = Animated9.withSpring(layout.width, SPRINGS.glide);
|
|
1977
2169
|
} else {
|
|
1978
|
-
pillX.
|
|
1979
|
-
pillWidth.
|
|
2170
|
+
pillX.value = layout.x;
|
|
2171
|
+
pillWidth.value = layout.width;
|
|
1980
2172
|
}
|
|
1981
|
-
};
|
|
2173
|
+
}, [pillX, pillWidth]);
|
|
1982
2174
|
React26.useEffect(() => {
|
|
1983
2175
|
if (initialised.current) animatePill(active, true);
|
|
1984
|
-
}, [active]);
|
|
2176
|
+
}, [active, animatePill]);
|
|
1985
2177
|
const handlePress = (v) => {
|
|
1986
2178
|
selectionAsync();
|
|
1987
2179
|
if (!value) setInternal(v);
|
|
1988
2180
|
onValueChange?.(v);
|
|
1989
2181
|
};
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2182
|
+
const pillAnimatedStyle = Animated9.useAnimatedStyle(() => ({
|
|
2183
|
+
transform: [{ translateX: pillX.value }],
|
|
2184
|
+
width: pillWidth.value
|
|
2185
|
+
}));
|
|
2186
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style }, /* @__PURE__ */ React26__default.default.createElement(
|
|
2187
|
+
reactNative.View,
|
|
1994
2188
|
{
|
|
1995
2189
|
style: [
|
|
1996
|
-
styles19.
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2190
|
+
variant === "pill" ? [styles19.list, { backgroundColor: colors.surface }] : styles19.listUnderline
|
|
2191
|
+
],
|
|
2192
|
+
accessibilityRole: "tablist"
|
|
2193
|
+
},
|
|
2194
|
+
variant === "pill" && /* @__PURE__ */ React26__default.default.createElement(
|
|
2195
|
+
Animated9__default.default.View,
|
|
2196
|
+
{
|
|
2197
|
+
style: [
|
|
2198
|
+
styles19.pill,
|
|
2199
|
+
{
|
|
2200
|
+
backgroundColor: colors.background,
|
|
2201
|
+
position: "absolute",
|
|
2202
|
+
top: 4,
|
|
2203
|
+
bottom: 4,
|
|
2204
|
+
left: 0,
|
|
2205
|
+
borderRadius: 8,
|
|
2206
|
+
shadowColor: "#000",
|
|
2207
|
+
shadowOffset: { width: 0, height: 1 },
|
|
2208
|
+
shadowOpacity: 0.08,
|
|
2209
|
+
shadowRadius: 2,
|
|
2210
|
+
elevation: 2
|
|
2211
|
+
},
|
|
2212
|
+
pillAnimatedStyle
|
|
2213
|
+
]
|
|
2214
|
+
}
|
|
2215
|
+
),
|
|
2216
|
+
tabs.map((tab) => /* @__PURE__ */ React26__default.default.createElement(
|
|
2217
|
+
TabTrigger,
|
|
2218
|
+
{
|
|
2219
|
+
key: tab.value,
|
|
2220
|
+
tab,
|
|
2221
|
+
isActive: tab.value === active,
|
|
2222
|
+
onPress: () => handlePress(tab.value),
|
|
2223
|
+
variant,
|
|
2224
|
+
onLayout: (e) => {
|
|
2225
|
+
const { x, width } = e.nativeEvent.layout;
|
|
2226
|
+
tabLayouts.current[tab.value] = { x, width };
|
|
2227
|
+
if (tab.value === active) {
|
|
2228
|
+
animatePill(tab.value, false);
|
|
2229
|
+
initialised.current = true;
|
|
2230
|
+
}
|
|
2027
2231
|
}
|
|
2028
2232
|
}
|
|
2029
|
-
|
|
2030
|
-
)
|
|
2233
|
+
))
|
|
2234
|
+
), children);
|
|
2031
2235
|
}
|
|
2032
2236
|
function TabsContent({ value, activeValue, children, style }) {
|
|
2033
2237
|
if (value !== activeValue) return null;
|
|
2034
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style }, children);
|
|
2238
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style, accessibilityRole: "none" }, children);
|
|
2035
2239
|
}
|
|
2036
2240
|
var styles19 = reactNative.StyleSheet.create({
|
|
2037
2241
|
list: {
|
|
@@ -2042,6 +2246,8 @@ var styles19 = reactNative.StyleSheet.create({
|
|
|
2042
2246
|
},
|
|
2043
2247
|
listUnderline: {
|
|
2044
2248
|
flexDirection: "row",
|
|
2249
|
+
// AUDIT FIX: was missing borderBottomColor — the 1px hairline would render
|
|
2250
|
+
// as transparent on some platforms. Explicit token reference ensures visibility.
|
|
2045
2251
|
borderBottomWidth: 1
|
|
2046
2252
|
},
|
|
2047
2253
|
pill: {},
|
|
@@ -2068,20 +2274,16 @@ var styles19 = reactNative.StyleSheet.create({
|
|
|
2068
2274
|
justifyContent: "center",
|
|
2069
2275
|
gap: s(4)
|
|
2070
2276
|
},
|
|
2277
|
+
// AUDIT FIX: was Sohne-Regular at rest, Sohne-Medium/SemiBold when active.
|
|
2278
|
+
// Font-weight changes at runtime cause advance-width shifts → the tab bar would
|
|
2279
|
+
// visibly jump/reflow on every selection. Now always SemiBold; active state
|
|
2280
|
+
// is communicated by color alone (foreground vs foregroundMuted). The pill
|
|
2281
|
+
// indicator provides additional active signal without text layout side-effects.
|
|
2071
2282
|
triggerLabel: {
|
|
2072
|
-
fontFamily: "
|
|
2283
|
+
fontFamily: "Sohne-SemiBold",
|
|
2073
2284
|
fontSize: ms(13)
|
|
2074
|
-
},
|
|
2075
|
-
activeTriggerLabel: {
|
|
2076
|
-
fontFamily: "Poppins-Medium"
|
|
2077
|
-
},
|
|
2078
|
-
activeTriggerLabelUnderline: {
|
|
2079
|
-
fontFamily: "Poppins-SemiBold",
|
|
2080
|
-
fontSize: ms(14)
|
|
2081
2285
|
}
|
|
2082
2286
|
});
|
|
2083
|
-
var easingExpand = Animated12.Easing.bezier(0.23, 1, 0.32, 1);
|
|
2084
|
-
var easingCollapse = Animated12.Easing.in(Animated12.Easing.ease);
|
|
2085
2287
|
function AccordionItemComponent({
|
|
2086
2288
|
item,
|
|
2087
2289
|
isOpen,
|
|
@@ -2089,28 +2291,28 @@ function AccordionItemComponent({
|
|
|
2089
2291
|
}) {
|
|
2090
2292
|
const { colors } = useTheme();
|
|
2091
2293
|
const resolvedIcon = item.iconName ? renderIcon(item.iconName, ms(16), item.iconColor ?? colors.foregroundMuted) : item.icon;
|
|
2092
|
-
const isExpanded =
|
|
2093
|
-
const height =
|
|
2294
|
+
const isExpanded = Animated9.useSharedValue(isOpen);
|
|
2295
|
+
const height = Animated9.useSharedValue(0);
|
|
2094
2296
|
React26__default.default.useEffect(() => {
|
|
2095
2297
|
isExpanded.value = isOpen;
|
|
2096
|
-
}, [isOpen]);
|
|
2097
|
-
const derivedHeight =
|
|
2098
|
-
() =>
|
|
2099
|
-
duration:
|
|
2100
|
-
easing: isExpanded.value ?
|
|
2298
|
+
}, [isOpen, isExpanded]);
|
|
2299
|
+
const derivedHeight = Animated9.useDerivedValue(
|
|
2300
|
+
() => Animated9.withTiming(height.value * Number(isExpanded.value), {
|
|
2301
|
+
duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
|
|
2302
|
+
easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse
|
|
2101
2303
|
})
|
|
2102
2304
|
);
|
|
2103
|
-
const derivedRotation =
|
|
2104
|
-
() =>
|
|
2105
|
-
duration:
|
|
2106
|
-
easing: isExpanded.value ?
|
|
2305
|
+
const derivedRotation = Animated9.useDerivedValue(
|
|
2306
|
+
() => Animated9.withTiming(isExpanded.value ? 1 : 0, {
|
|
2307
|
+
duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
|
|
2308
|
+
easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse
|
|
2107
2309
|
})
|
|
2108
2310
|
);
|
|
2109
|
-
const bodyStyle =
|
|
2311
|
+
const bodyStyle = Animated9.useAnimatedStyle(() => ({
|
|
2110
2312
|
height: derivedHeight.value,
|
|
2111
2313
|
overflow: "hidden"
|
|
2112
2314
|
}));
|
|
2113
|
-
const rotationStyle =
|
|
2315
|
+
const rotationStyle = Animated9.useAnimatedStyle(() => ({
|
|
2114
2316
|
transform: [{ rotate: `${derivedRotation.value * 180}deg` }]
|
|
2115
2317
|
}));
|
|
2116
2318
|
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles20.item, { backgroundColor: colors.card, borderColor: colors.border }] }, /* @__PURE__ */ React26__default.default.createElement(
|
|
@@ -2120,11 +2322,14 @@ function AccordionItemComponent({
|
|
|
2120
2322
|
onPress: () => {
|
|
2121
2323
|
selectionAsync();
|
|
2122
2324
|
onToggle();
|
|
2123
|
-
}
|
|
2325
|
+
},
|
|
2326
|
+
accessibilityRole: "button",
|
|
2327
|
+
accessibilityState: { expanded: isOpen },
|
|
2328
|
+
accessibilityLabel: item.trigger
|
|
2124
2329
|
},
|
|
2125
2330
|
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles20.triggerContent }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles20.icon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles20.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger)),
|
|
2126
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
2127
|
-
), /* @__PURE__ */ React26__default.default.createElement(
|
|
2331
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles20.chevron, rotationStyle] }, /* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
|
|
2332
|
+
), /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: bodyStyle }, /* @__PURE__ */ React26__default.default.createElement(
|
|
2128
2333
|
reactNative.View,
|
|
2129
2334
|
{
|
|
2130
2335
|
style: styles20.content,
|
|
@@ -2186,7 +2391,7 @@ var styles20 = reactNative.StyleSheet.create({
|
|
|
2186
2391
|
justifyContent: "center"
|
|
2187
2392
|
},
|
|
2188
2393
|
triggerText: {
|
|
2189
|
-
fontFamily: "
|
|
2394
|
+
fontFamily: "Sohne-Medium",
|
|
2190
2395
|
fontSize: ms(14)
|
|
2191
2396
|
},
|
|
2192
2397
|
chevron: {
|
|
@@ -2195,7 +2400,7 @@ var styles20 = reactNative.StyleSheet.create({
|
|
|
2195
2400
|
// position:'absolute' is the key — the inner View escapes the animated wrapper's
|
|
2196
2401
|
// clipped height so onLayout always reports the true content height.
|
|
2197
2402
|
content: {
|
|
2198
|
-
paddingHorizontal: s(
|
|
2403
|
+
paddingHorizontal: s(8),
|
|
2199
2404
|
paddingBottom: vs(12),
|
|
2200
2405
|
position: "absolute",
|
|
2201
2406
|
width: "100%"
|
|
@@ -2224,23 +2429,38 @@ function Slider({
|
|
|
2224
2429
|
}
|
|
2225
2430
|
onValueChange?.(v);
|
|
2226
2431
|
};
|
|
2227
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
2228
|
-
|
|
2432
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
2433
|
+
reactNative.View,
|
|
2229
2434
|
{
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2435
|
+
style: [styles21.wrapper, style],
|
|
2436
|
+
accessibilityRole: "adjustable",
|
|
2437
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
2438
|
+
accessibilityValue: {
|
|
2439
|
+
min: minimumValue,
|
|
2440
|
+
max: maximumValue,
|
|
2441
|
+
now: value,
|
|
2442
|
+
text: formatValue2(value)
|
|
2443
|
+
}
|
|
2444
|
+
},
|
|
2445
|
+
label || showValue ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles21.header }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles21.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, showValue ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles21.valueText, { color: colors.foregroundMuted }], allowFontScaling: true }, formatValue2(value)) : null) : null,
|
|
2446
|
+
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: disabled ? styles21.disabled : void 0 }, /* @__PURE__ */ React26__default.default.createElement(
|
|
2447
|
+
RNSlider__default.default,
|
|
2448
|
+
{
|
|
2449
|
+
value,
|
|
2450
|
+
minimumValue,
|
|
2451
|
+
maximumValue,
|
|
2452
|
+
step: step || 0,
|
|
2453
|
+
disabled,
|
|
2454
|
+
onValueChange: handleValueChange,
|
|
2455
|
+
onSlidingComplete,
|
|
2456
|
+
minimumTrackTintColor: colors.primary,
|
|
2457
|
+
maximumTrackTintColor: colors.surface,
|
|
2458
|
+
thumbTintColor: colors.primary,
|
|
2459
|
+
style: styles21.slider,
|
|
2460
|
+
accessibilityLabel
|
|
2461
|
+
}
|
|
2462
|
+
))
|
|
2463
|
+
);
|
|
2244
2464
|
}
|
|
2245
2465
|
var styles21 = reactNative.StyleSheet.create({
|
|
2246
2466
|
wrapper: {
|
|
@@ -2252,11 +2472,11 @@ var styles21 = reactNative.StyleSheet.create({
|
|
|
2252
2472
|
alignItems: "center"
|
|
2253
2473
|
},
|
|
2254
2474
|
label: {
|
|
2255
|
-
fontFamily: "
|
|
2475
|
+
fontFamily: "Sohne-Medium",
|
|
2256
2476
|
fontSize: ms(15)
|
|
2257
2477
|
},
|
|
2258
2478
|
valueText: {
|
|
2259
|
-
fontFamily: "
|
|
2479
|
+
fontFamily: "Sohne-Medium",
|
|
2260
2480
|
fontSize: ms(14)
|
|
2261
2481
|
},
|
|
2262
2482
|
slider: {
|
|
@@ -2270,6 +2490,16 @@ var styles21 = reactNative.StyleSheet.create({
|
|
|
2270
2490
|
var SCREEN_HEIGHT = reactNative.Dimensions.get("window").height;
|
|
2271
2491
|
var DEFAULT_MAX_HEIGHT = SCREEN_HEIGHT * 0.85;
|
|
2272
2492
|
var isAndroid = reactNative.Platform.OS === "android";
|
|
2493
|
+
function SheetHeader({ children, style }) {
|
|
2494
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles22.header, style] }, children);
|
|
2495
|
+
}
|
|
2496
|
+
function SheetContent({ children, style }) {
|
|
2497
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles22.sheetContent, style] }, children);
|
|
2498
|
+
}
|
|
2499
|
+
function SheetFooter({ children, style }) {
|
|
2500
|
+
const { colors } = useTheme();
|
|
2501
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles22.sheetFooter, { backgroundColor: colors.card, borderTopColor: colors.border }, style] }, children);
|
|
2502
|
+
}
|
|
2273
2503
|
function Sheet({
|
|
2274
2504
|
open,
|
|
2275
2505
|
onClose,
|
|
@@ -2310,22 +2540,34 @@ function Sheet({
|
|
|
2310
2540
|
pressBehavior: "close"
|
|
2311
2541
|
}
|
|
2312
2542
|
), []);
|
|
2313
|
-
const
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2543
|
+
const childArray = React26__default.default.Children.toArray(children);
|
|
2544
|
+
const customHeader = childArray.find((child) => React26__default.default.isValidElement(child) && child.type === SheetHeader);
|
|
2545
|
+
const customContent = childArray.find((child) => React26__default.default.isValidElement(child) && child.type === SheetContent);
|
|
2546
|
+
const customFooter = childArray.find((child) => React26__default.default.isValidElement(child) && child.type === SheetFooter);
|
|
2547
|
+
const filteredChildren = customHeader || customContent || customFooter ? childArray.filter(
|
|
2548
|
+
(child) => !React26__default.default.isValidElement(child) || child.type !== SheetHeader && child.type !== SheetContent && child.type !== SheetFooter
|
|
2549
|
+
) : children;
|
|
2317
2550
|
const effectiveSubtitle = subtitle ?? description;
|
|
2318
|
-
const showHeader = !!(title || effectiveSubtitle || showCloseButton);
|
|
2319
|
-
const headerNode = showHeader ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.header }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.headerRow }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles22.title, { color: colors.foreground }], allowFontScaling: true }, title) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { flex: 1 } }), showCloseButton ? /* @__PURE__ */ React26__default.default.createElement(
|
|
2551
|
+
const showHeader = !!(title || effectiveSubtitle || showCloseButton) && !customHeader;
|
|
2552
|
+
const headerNode = customHeader ? customHeader : showHeader ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.header, accessibilityRole: "header" }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles22.headerRow }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles22.title, { color: colors.foreground }], allowFontScaling: true }, title) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { flex: 1 } }), showCloseButton ? /* @__PURE__ */ React26__default.default.createElement(
|
|
2320
2553
|
reactNative.TouchableOpacity,
|
|
2321
2554
|
{
|
|
2322
2555
|
onPress: onClose,
|
|
2323
2556
|
style: styles22.closeButton,
|
|
2324
2557
|
activeOpacity: 0.6,
|
|
2325
|
-
touchSoundDisabled: true
|
|
2558
|
+
touchSoundDisabled: true,
|
|
2559
|
+
accessibilityRole: "button",
|
|
2560
|
+
accessibilityLabel: "Close",
|
|
2561
|
+
hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }
|
|
2326
2562
|
},
|
|
2327
2563
|
/* @__PURE__ */ React26__default.default.createElement(vectorIcons.AntDesign, { name: "close", size: ms(18), color: colors.foregroundMuted })
|
|
2328
2564
|
) : null), effectiveSubtitle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles22.subtitle, { color: colors.foregroundMuted }], allowFontScaling: true }, effectiveSubtitle) : null) : null;
|
|
2565
|
+
const contentNode = customContent ? customContent : filteredChildren;
|
|
2566
|
+
const effectiveFooter = customFooter ? customFooter : footer;
|
|
2567
|
+
const renderFooter = React26.useCallback((props) => {
|
|
2568
|
+
if (!effectiveFooter) return null;
|
|
2569
|
+
return /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetFooter, { ...props }, effectiveFooter);
|
|
2570
|
+
}, [effectiveFooter]);
|
|
2329
2571
|
const useScroll = scrollable || !!maxHeight;
|
|
2330
2572
|
const effectiveMaxHeight = maxHeight ?? DEFAULT_MAX_HEIGHT;
|
|
2331
2573
|
const useDynamicSizing = !snapPoints;
|
|
@@ -2338,7 +2580,7 @@ function Sheet({
|
|
|
2338
2580
|
maxDynamicContentSize: useDynamicSizing ? effectiveMaxHeight : void 0,
|
|
2339
2581
|
onDismiss: onClose,
|
|
2340
2582
|
backdropComponent: renderBackdrop,
|
|
2341
|
-
footerComponent:
|
|
2583
|
+
footerComponent: effectiveFooter ? renderFooter : void 0,
|
|
2342
2584
|
backgroundStyle: [styles22.background, { backgroundColor: colors.card }],
|
|
2343
2585
|
handleIndicatorStyle: [styles22.handle, { backgroundColor: colors.border }],
|
|
2344
2586
|
enablePanDownToClose: true,
|
|
@@ -2361,10 +2603,13 @@ function Sheet({
|
|
|
2361
2603
|
persistentScrollbar: isAndroid
|
|
2362
2604
|
},
|
|
2363
2605
|
headerNode,
|
|
2364
|
-
|
|
2365
|
-
) : /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: [styles22.content, contentStyle, style] }, headerNode,
|
|
2606
|
+
contentNode
|
|
2607
|
+
) : /* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: [styles22.content, contentStyle, style] }, headerNode, contentNode)
|
|
2366
2608
|
);
|
|
2367
2609
|
}
|
|
2610
|
+
Sheet.Header = SheetHeader;
|
|
2611
|
+
Sheet.Content = SheetContent;
|
|
2612
|
+
Sheet.Footer = SheetFooter;
|
|
2368
2613
|
var styles22 = reactNative.StyleSheet.create({
|
|
2369
2614
|
background: {
|
|
2370
2615
|
borderTopLeftRadius: ms(16),
|
|
@@ -2387,12 +2632,12 @@ var styles22 = reactNative.StyleSheet.create({
|
|
|
2387
2632
|
justifyContent: "space-between"
|
|
2388
2633
|
},
|
|
2389
2634
|
title: {
|
|
2390
|
-
fontFamily: "
|
|
2635
|
+
fontFamily: "Sohne-SemiBold",
|
|
2391
2636
|
fontSize: ms(18),
|
|
2392
2637
|
flex: 1
|
|
2393
2638
|
},
|
|
2394
2639
|
subtitle: {
|
|
2395
|
-
fontFamily: "
|
|
2640
|
+
fontFamily: "Sohne-Regular",
|
|
2396
2641
|
fontSize: ms(14),
|
|
2397
2642
|
lineHeight: mvs(20)
|
|
2398
2643
|
},
|
|
@@ -2408,12 +2653,21 @@ var styles22 = reactNative.StyleSheet.create({
|
|
|
2408
2653
|
paddingHorizontal: s(16),
|
|
2409
2654
|
paddingBottom: vs(32),
|
|
2410
2655
|
paddingRight: s(16)
|
|
2656
|
+
},
|
|
2657
|
+
sheetContent: {
|
|
2658
|
+
gap: vs(16)
|
|
2659
|
+
},
|
|
2660
|
+
sheetFooter: {
|
|
2661
|
+
paddingHorizontal: s(16),
|
|
2662
|
+
paddingVertical: vs(16),
|
|
2663
|
+
borderTopWidth: 1,
|
|
2664
|
+
flexDirection: "row",
|
|
2665
|
+
gap: s(12)
|
|
2411
2666
|
}
|
|
2412
2667
|
});
|
|
2413
2668
|
var isIOS = reactNative.Platform.OS === "ios";
|
|
2414
2669
|
var isAndroid2 = reactNative.Platform.OS === "android";
|
|
2415
2670
|
var isWeb2 = reactNative.Platform.OS === "web";
|
|
2416
|
-
var nativeDriver9 = reactNative.Platform.OS !== "web";
|
|
2417
2671
|
function Select({
|
|
2418
2672
|
options,
|
|
2419
2673
|
value,
|
|
@@ -2422,21 +2676,18 @@ function Select({
|
|
|
2422
2676
|
label,
|
|
2423
2677
|
error,
|
|
2424
2678
|
disabled,
|
|
2425
|
-
style
|
|
2679
|
+
style,
|
|
2680
|
+
accessibilityLabel
|
|
2426
2681
|
}) {
|
|
2427
2682
|
const { colors } = useTheme();
|
|
2428
|
-
const
|
|
2683
|
+
const { animatedStyle, onPressIn, onPressOut } = usePressScale({
|
|
2684
|
+
pressScale: PRESS_SCALE.button,
|
|
2685
|
+
disabled
|
|
2686
|
+
});
|
|
2429
2687
|
const [pickerVisible, setPickerVisible] = React26.useState(false);
|
|
2430
2688
|
const [pendingValue, setPendingValue] = React26.useState(value);
|
|
2431
2689
|
const pickerRef = React26.useRef(null);
|
|
2432
2690
|
const selected = options.find((o) => o.value === value);
|
|
2433
|
-
const handlePressIn = () => {
|
|
2434
|
-
if (disabled) return;
|
|
2435
|
-
reactNative.Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver9, speed: 40, bounciness: 0 }).start();
|
|
2436
|
-
};
|
|
2437
|
-
const handlePressOut = () => {
|
|
2438
|
-
reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver9, speed: 40, bounciness: 4 }).start();
|
|
2439
|
-
};
|
|
2440
2691
|
const handleOpen = () => {
|
|
2441
2692
|
if (disabled) return;
|
|
2442
2693
|
selectionAsync();
|
|
@@ -2444,7 +2695,7 @@ function Select({
|
|
|
2444
2695
|
setPendingValue(value);
|
|
2445
2696
|
setPickerVisible(true);
|
|
2446
2697
|
} else if (isAndroid2) {
|
|
2447
|
-
pickerRef.current?.focus();
|
|
2698
|
+
pickerRef.current?.focus?.();
|
|
2448
2699
|
}
|
|
2449
2700
|
};
|
|
2450
2701
|
const handleDismiss = () => {
|
|
@@ -2457,7 +2708,7 @@ function Select({
|
|
|
2457
2708
|
}
|
|
2458
2709
|
setPickerVisible(false);
|
|
2459
2710
|
};
|
|
2460
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles23.container, style] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles23.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, !isWeb2 ? /* @__PURE__ */ React26__default.default.createElement(
|
|
2711
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles23.container, style] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles23.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, !isWeb2 ? /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [animatedStyle, { opacity: disabled ? 0.45 : 1 }] }, /* @__PURE__ */ React26__default.default.createElement(
|
|
2461
2712
|
reactNative.TouchableOpacity,
|
|
2462
2713
|
{
|
|
2463
2714
|
style: [
|
|
@@ -2468,10 +2719,14 @@ function Select({
|
|
|
2468
2719
|
}
|
|
2469
2720
|
],
|
|
2470
2721
|
onPress: handleOpen,
|
|
2471
|
-
onPressIn
|
|
2472
|
-
onPressOut
|
|
2722
|
+
onPressIn,
|
|
2723
|
+
onPressOut,
|
|
2473
2724
|
activeOpacity: 1,
|
|
2474
|
-
touchSoundDisabled: true
|
|
2725
|
+
touchSoundDisabled: true,
|
|
2726
|
+
accessibilityRole: "combobox",
|
|
2727
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
2728
|
+
accessibilityValue: { text: selected?.label ?? placeholder },
|
|
2729
|
+
accessibilityState: { disabled: !!disabled, expanded: pickerVisible }
|
|
2475
2730
|
},
|
|
2476
2731
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
2477
2732
|
reactNative.Text,
|
|
@@ -2577,7 +2832,7 @@ var styles23 = reactNative.StyleSheet.create({
|
|
|
2577
2832
|
gap: vs(8)
|
|
2578
2833
|
},
|
|
2579
2834
|
label: {
|
|
2580
|
-
fontFamily: "
|
|
2835
|
+
fontFamily: "Sohne-Medium",
|
|
2581
2836
|
fontSize: ms(13)
|
|
2582
2837
|
},
|
|
2583
2838
|
trigger: {
|
|
@@ -2590,7 +2845,7 @@ var styles23 = reactNative.StyleSheet.create({
|
|
|
2590
2845
|
paddingVertical: vs(11)
|
|
2591
2846
|
},
|
|
2592
2847
|
triggerText: {
|
|
2593
|
-
fontFamily: "
|
|
2848
|
+
fontFamily: "Sohne-Regular",
|
|
2594
2849
|
fontSize: ms(15),
|
|
2595
2850
|
flex: 1
|
|
2596
2851
|
},
|
|
@@ -2598,7 +2853,7 @@ var styles23 = reactNative.StyleSheet.create({
|
|
|
2598
2853
|
marginLeft: s(8)
|
|
2599
2854
|
},
|
|
2600
2855
|
helperText: {
|
|
2601
|
-
fontFamily: "
|
|
2856
|
+
fontFamily: "Sohne-Regular",
|
|
2602
2857
|
fontSize: ms(13)
|
|
2603
2858
|
},
|
|
2604
2859
|
iosBackdrop: {
|
|
@@ -2619,14 +2874,14 @@ var styles23 = reactNative.StyleSheet.create({
|
|
|
2619
2874
|
borderBottomWidth: 1
|
|
2620
2875
|
},
|
|
2621
2876
|
iosToolbarTitle: {
|
|
2622
|
-
fontFamily: "
|
|
2877
|
+
fontFamily: "Sohne-SemiBold",
|
|
2623
2878
|
fontSize: ms(17)
|
|
2624
2879
|
},
|
|
2625
2880
|
iosDoneBtn: {
|
|
2626
2881
|
padding: s(4)
|
|
2627
2882
|
},
|
|
2628
2883
|
iosDoneBtnText: {
|
|
2629
|
-
fontFamily: "
|
|
2884
|
+
fontFamily: "Sohne-SemiBold",
|
|
2630
2885
|
fontSize: ms(17)
|
|
2631
2886
|
},
|
|
2632
2887
|
androidHiddenPicker: {
|
|
@@ -2656,7 +2911,7 @@ function ToastProvider({ children }) {
|
|
|
2656
2911
|
{
|
|
2657
2912
|
theme: colorScheme,
|
|
2658
2913
|
position: "top-center",
|
|
2659
|
-
richColors:
|
|
2914
|
+
richColors: true,
|
|
2660
2915
|
gap: vs(8),
|
|
2661
2916
|
offset: insets.top + vs(8),
|
|
2662
2917
|
visibleToasts: 3,
|
|
@@ -2670,11 +2925,11 @@ function ToastProvider({ children }) {
|
|
|
2670
2925
|
paddingVertical: vs(10)
|
|
2671
2926
|
},
|
|
2672
2927
|
titleStyle: {
|
|
2673
|
-
fontFamily: "
|
|
2928
|
+
fontFamily: "Sohne-Medium",
|
|
2674
2929
|
fontSize: ms(13)
|
|
2675
2930
|
},
|
|
2676
2931
|
descriptionStyle: {
|
|
2677
|
-
fontFamily: "
|
|
2932
|
+
fontFamily: "Sohne-Regular",
|
|
2678
2933
|
fontSize: ms(12),
|
|
2679
2934
|
opacity: 0.85
|
|
2680
2935
|
}
|
|
@@ -2712,7 +2967,7 @@ function CurrencyInput({
|
|
|
2712
2967
|
const raw = parseFloat(formatted.replace(separatorRegex, "") || "0");
|
|
2713
2968
|
onChangeValue?.(isNaN(raw) ? 0 : raw);
|
|
2714
2969
|
};
|
|
2715
|
-
const inputStyle = size === "large" ? { fontFamily: "
|
|
2970
|
+
const inputStyle = size === "large" ? { fontFamily: "Sohne-Regular", fontSize: ms(36) } : { fontFamily: "Sohne-Regular" };
|
|
2716
2971
|
const dollarIcon = renderIcon("dollar-sign", size === "large" ? 24 : 16, colors.foregroundMuted);
|
|
2717
2972
|
const displayValue = value && prefix && value.startsWith(prefix) ? value.slice(prefix.length) : value;
|
|
2718
2973
|
return /* @__PURE__ */ React26__default.default.createElement(
|
|
@@ -2757,7 +3012,7 @@ function formatValue(value, prefix, showDecimals) {
|
|
|
2757
3012
|
}
|
|
2758
3013
|
return `${sign}${prefix}${intPart}`;
|
|
2759
3014
|
}
|
|
2760
|
-
function
|
|
3015
|
+
function CurrencyDisplayBase({ value, prefix = "$", showDecimals = false, textColor, variant, autoScale, maxFontSize, style }) {
|
|
2761
3016
|
const { colors } = useTheme();
|
|
2762
3017
|
const formatted = formatValue(value, prefix, showDecimals);
|
|
2763
3018
|
const baseFontSize = variant ? variantFontSize[variant] : ms(56);
|
|
@@ -2775,18 +3030,18 @@ function CurrencyDisplay({ value, prefix = "$", showDecimals = false, textColor,
|
|
|
2775
3030
|
formatted
|
|
2776
3031
|
));
|
|
2777
3032
|
}
|
|
3033
|
+
var CurrencyDisplay = React26__default.default.memo(CurrencyDisplayBase);
|
|
2778
3034
|
var styles24 = reactNative.StyleSheet.create({
|
|
2779
3035
|
container: {
|
|
2780
3036
|
alignSelf: "flex-start"
|
|
2781
3037
|
},
|
|
2782
3038
|
amount: {
|
|
2783
|
-
fontFamily: "
|
|
3039
|
+
fontFamily: "Sohne-Bold",
|
|
2784
3040
|
includeFontPadding: false,
|
|
2785
3041
|
textAlignVertical: "top"
|
|
2786
3042
|
}
|
|
2787
3043
|
});
|
|
2788
|
-
|
|
2789
|
-
function ListItem({
|
|
3044
|
+
function ListItemBase({
|
|
2790
3045
|
leftRender,
|
|
2791
3046
|
rightRender,
|
|
2792
3047
|
trailing,
|
|
@@ -2806,29 +3061,16 @@ function ListItem({
|
|
|
2806
3061
|
style,
|
|
2807
3062
|
titleStyle,
|
|
2808
3063
|
subtitleStyle,
|
|
2809
|
-
captionStyle
|
|
3064
|
+
captionStyle,
|
|
3065
|
+
accessibilityLabel
|
|
2810
3066
|
}) {
|
|
2811
3067
|
const { colors } = useTheme();
|
|
2812
|
-
const
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
stiffness: 350,
|
|
2819
|
-
damping: 28,
|
|
2820
|
-
mass: 0.9
|
|
2821
|
-
}).start();
|
|
2822
|
-
};
|
|
2823
|
-
const handlePressOut = () => {
|
|
2824
|
-
reactNative.Animated.spring(scale2, {
|
|
2825
|
-
toValue: 1,
|
|
2826
|
-
useNativeDriver: nativeDriver10,
|
|
2827
|
-
stiffness: 220,
|
|
2828
|
-
damping: 20,
|
|
2829
|
-
mass: 0.9
|
|
2830
|
-
}).start();
|
|
2831
|
-
};
|
|
3068
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
3069
|
+
pressScale: PRESS_SCALE.row,
|
|
3070
|
+
pressInSpring: SPRINGS.surfacePressIn,
|
|
3071
|
+
pressOutSpring: SPRINGS.surfacePressOut,
|
|
3072
|
+
disabled: !onPress || disabled
|
|
3073
|
+
});
|
|
2832
3074
|
const handlePress = () => {
|
|
2833
3075
|
selectionAsync();
|
|
2834
3076
|
onPress?.();
|
|
@@ -2846,16 +3088,20 @@ function ListItem({
|
|
|
2846
3088
|
shadowRadius: 6,
|
|
2847
3089
|
elevation: 2
|
|
2848
3090
|
} : {};
|
|
2849
|
-
|
|
3091
|
+
const a11yLabel = accessibilityLabel ?? [title, subtitle, caption].filter(Boolean).join(". ");
|
|
3092
|
+
return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [animatedStyle, disabled && styles25.disabled], ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
|
|
2850
3093
|
reactNative.TouchableOpacity,
|
|
2851
3094
|
{
|
|
2852
3095
|
style: [styles25.container, cardStyle, style],
|
|
2853
3096
|
onPress: onPress ? handlePress : void 0,
|
|
2854
|
-
onPressIn
|
|
2855
|
-
onPressOut
|
|
3097
|
+
onPressIn,
|
|
3098
|
+
onPressOut,
|
|
2856
3099
|
disabled,
|
|
2857
3100
|
activeOpacity: 1,
|
|
2858
|
-
touchSoundDisabled: true
|
|
3101
|
+
touchSoundDisabled: true,
|
|
3102
|
+
accessibilityRole: onPress ? "button" : void 0,
|
|
3103
|
+
accessibilityLabel: onPress ? a11yLabel : void 0,
|
|
3104
|
+
accessibilityState: onPress ? { disabled: !!disabled } : void 0
|
|
2859
3105
|
},
|
|
2860
3106
|
effectiveLeft ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles25.leftContainer }, effectiveLeft) : null,
|
|
2861
3107
|
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles25.content }, /* @__PURE__ */ React26__default.default.createElement(
|
|
@@ -2896,19 +3142,17 @@ function ListItem({
|
|
|
2896
3142
|
{
|
|
2897
3143
|
style: [
|
|
2898
3144
|
styles25.separator,
|
|
2899
|
-
{
|
|
2900
|
-
backgroundColor: colors.border,
|
|
2901
|
-
marginLeft: effectiveLeft ? s(44) + s(12) : 0
|
|
2902
|
-
}
|
|
3145
|
+
{ backgroundColor: colors.separator }
|
|
2903
3146
|
]
|
|
2904
3147
|
}
|
|
2905
3148
|
) : null);
|
|
2906
3149
|
}
|
|
3150
|
+
var ListItem = React26__default.default.memo(ListItemBase);
|
|
2907
3151
|
var styles25 = reactNative.StyleSheet.create({
|
|
2908
3152
|
container: {
|
|
2909
3153
|
flexDirection: "row",
|
|
2910
3154
|
alignItems: "center",
|
|
2911
|
-
paddingHorizontal:
|
|
3155
|
+
paddingHorizontal: s(16),
|
|
2912
3156
|
paddingVertical: vs(10),
|
|
2913
3157
|
gap: s(12)
|
|
2914
3158
|
},
|
|
@@ -2924,17 +3168,17 @@ var styles25 = reactNative.StyleSheet.create({
|
|
|
2924
3168
|
gap: vs(4)
|
|
2925
3169
|
},
|
|
2926
3170
|
title: {
|
|
2927
|
-
fontFamily: "
|
|
3171
|
+
fontFamily: "Sohne-Medium",
|
|
2928
3172
|
fontSize: ms(15),
|
|
2929
3173
|
lineHeight: mvs(22)
|
|
2930
3174
|
},
|
|
2931
3175
|
subtitle: {
|
|
2932
|
-
fontFamily: "
|
|
3176
|
+
fontFamily: "Sohne-Regular",
|
|
2933
3177
|
fontSize: ms(13),
|
|
2934
3178
|
lineHeight: mvs(18)
|
|
2935
3179
|
},
|
|
2936
3180
|
caption: {
|
|
2937
|
-
fontFamily: "
|
|
3181
|
+
fontFamily: "Sohne-Regular",
|
|
2938
3182
|
fontSize: ms(12),
|
|
2939
3183
|
lineHeight: mvs(16),
|
|
2940
3184
|
opacity: 0.7
|
|
@@ -2946,12 +3190,9 @@ var styles25 = reactNative.StyleSheet.create({
|
|
|
2946
3190
|
maxWidth: s(160)
|
|
2947
3191
|
},
|
|
2948
3192
|
rightText: {
|
|
2949
|
-
fontFamily: "
|
|
3193
|
+
fontFamily: "Sohne-Regular",
|
|
2950
3194
|
fontSize: ms(14)
|
|
2951
3195
|
},
|
|
2952
|
-
chevron: {
|
|
2953
|
-
marginLeft: s(4)
|
|
2954
|
-
},
|
|
2955
3196
|
separator: {
|
|
2956
3197
|
height: reactNative.StyleSheet.hairlineWidth,
|
|
2957
3198
|
marginRight: 0
|
|
@@ -2960,8 +3201,81 @@ var styles25 = reactNative.StyleSheet.create({
|
|
|
2960
3201
|
opacity: 0.45
|
|
2961
3202
|
}
|
|
2962
3203
|
});
|
|
2963
|
-
|
|
2964
|
-
|
|
3204
|
+
function ListGroup({ children, variant = "plain", style }) {
|
|
3205
|
+
const { colors } = useTheme();
|
|
3206
|
+
const processedChildren = React26__default.default.Children.map(children, (child, index) => {
|
|
3207
|
+
if (!React26__default.default.isValidElement(child)) return child;
|
|
3208
|
+
if (child.type === ListGroupHeader || child.type === ListGroupFooter) {
|
|
3209
|
+
return child;
|
|
3210
|
+
}
|
|
3211
|
+
const childProps = child.props;
|
|
3212
|
+
const isListItem = "title" in childProps;
|
|
3213
|
+
if (!isListItem) return child;
|
|
3214
|
+
const isLast = index === React26__default.default.Children.count(children) - 1;
|
|
3215
|
+
if (childProps["showSeparator"] === void 0 && !isLast) {
|
|
3216
|
+
return React26__default.default.cloneElement(child, {
|
|
3217
|
+
showSeparator: true
|
|
3218
|
+
});
|
|
3219
|
+
}
|
|
3220
|
+
return child;
|
|
3221
|
+
});
|
|
3222
|
+
const cardStyle = variant === "card" ? {
|
|
3223
|
+
backgroundColor: colors.card,
|
|
3224
|
+
borderRadius: RADIUS.md,
|
|
3225
|
+
borderWidth: 1,
|
|
3226
|
+
borderColor: colors.border,
|
|
3227
|
+
shadowColor: "#000",
|
|
3228
|
+
shadowOffset: { width: 0, height: 2 },
|
|
3229
|
+
shadowOpacity: 0.06,
|
|
3230
|
+
shadowRadius: 6,
|
|
3231
|
+
elevation: 2,
|
|
3232
|
+
paddingVertical: vs(4)
|
|
3233
|
+
} : {};
|
|
3234
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.container, cardStyle, style] }, processedChildren);
|
|
3235
|
+
}
|
|
3236
|
+
function ListGroupHeader({ children, style }) {
|
|
3237
|
+
const { colors } = useTheme();
|
|
3238
|
+
if (typeof children === "string") {
|
|
3239
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.header, { borderBottomColor: colors.separator }, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles26.headerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
|
|
3240
|
+
}
|
|
3241
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.header, { borderBottomColor: colors.separator }, style] }, children);
|
|
3242
|
+
}
|
|
3243
|
+
function ListGroupFooter({ children, style }) {
|
|
3244
|
+
const { colors } = useTheme();
|
|
3245
|
+
if (typeof children === "string") {
|
|
3246
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.footer, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles26.footerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
|
|
3247
|
+
}
|
|
3248
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles26.footer, style] }, children);
|
|
3249
|
+
}
|
|
3250
|
+
ListGroup.Header = ListGroupHeader;
|
|
3251
|
+
ListGroup.Footer = ListGroupFooter;
|
|
3252
|
+
var styles26 = reactNative.StyleSheet.create({
|
|
3253
|
+
container: {
|
|
3254
|
+
overflow: "hidden"
|
|
3255
|
+
},
|
|
3256
|
+
header: {
|
|
3257
|
+
paddingHorizontal: s(16),
|
|
3258
|
+
paddingTop: vs(12),
|
|
3259
|
+
paddingBottom: vs(8),
|
|
3260
|
+
borderBottomWidth: reactNative.StyleSheet.hairlineWidth
|
|
3261
|
+
},
|
|
3262
|
+
headerText: {
|
|
3263
|
+
fontFamily: "Sohne-SemiBold",
|
|
3264
|
+
fontSize: 13,
|
|
3265
|
+
letterSpacing: 0.32,
|
|
3266
|
+
textTransform: "uppercase"
|
|
3267
|
+
},
|
|
3268
|
+
footer: {
|
|
3269
|
+
paddingHorizontal: s(16),
|
|
3270
|
+
paddingTop: vs(8),
|
|
3271
|
+
paddingBottom: vs(12)
|
|
3272
|
+
},
|
|
3273
|
+
footerText: {
|
|
3274
|
+
fontFamily: "Sohne-Regular",
|
|
3275
|
+
fontSize: 12
|
|
3276
|
+
}
|
|
3277
|
+
});
|
|
3278
|
+
function MenuItemBase({
|
|
2965
3279
|
label,
|
|
2966
3280
|
subtitle,
|
|
2967
3281
|
iconName,
|
|
@@ -2974,29 +3288,16 @@ function MenuItem({
|
|
|
2974
3288
|
variant = "plain",
|
|
2975
3289
|
showSeparator = false,
|
|
2976
3290
|
style,
|
|
2977
|
-
labelStyle
|
|
3291
|
+
labelStyle,
|
|
3292
|
+
accessibilityLabel
|
|
2978
3293
|
}) {
|
|
2979
3294
|
const { colors } = useTheme();
|
|
2980
|
-
const
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
stiffness: 350,
|
|
2987
|
-
damping: 28,
|
|
2988
|
-
mass: 0.9
|
|
2989
|
-
}).start();
|
|
2990
|
-
};
|
|
2991
|
-
const handlePressOut = () => {
|
|
2992
|
-
reactNative.Animated.spring(scale2, {
|
|
2993
|
-
toValue: 1,
|
|
2994
|
-
useNativeDriver: nativeDriver11,
|
|
2995
|
-
stiffness: 220,
|
|
2996
|
-
damping: 20,
|
|
2997
|
-
mass: 0.9
|
|
2998
|
-
}).start();
|
|
2999
|
-
};
|
|
3295
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
3296
|
+
pressScale: PRESS_SCALE.row,
|
|
3297
|
+
pressInSpring: SPRINGS.surfacePressIn,
|
|
3298
|
+
pressOutSpring: SPRINGS.surfacePressOut,
|
|
3299
|
+
disabled
|
|
3300
|
+
});
|
|
3000
3301
|
const handlePress = () => {
|
|
3001
3302
|
selectionAsync();
|
|
3002
3303
|
onPress();
|
|
@@ -3013,22 +3314,26 @@ function MenuItem({
|
|
|
3013
3314
|
shadowRadius: 6,
|
|
3014
3315
|
elevation: 2
|
|
3015
3316
|
} : {};
|
|
3016
|
-
|
|
3317
|
+
const a11yLabel = accessibilityLabel ?? (subtitle ? `${label}. ${subtitle}` : label);
|
|
3318
|
+
return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [animatedStyle, disabled && styles27.disabled], ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3017
3319
|
reactNative.TouchableOpacity,
|
|
3018
3320
|
{
|
|
3019
|
-
style: [
|
|
3321
|
+
style: [styles27.container, cardStyle, style],
|
|
3020
3322
|
onPress: handlePress,
|
|
3021
|
-
onPressIn
|
|
3022
|
-
onPressOut
|
|
3323
|
+
onPressIn,
|
|
3324
|
+
onPressOut,
|
|
3023
3325
|
disabled,
|
|
3024
3326
|
activeOpacity: 1,
|
|
3025
|
-
touchSoundDisabled: true
|
|
3327
|
+
touchSoundDisabled: true,
|
|
3328
|
+
accessibilityRole: "button",
|
|
3329
|
+
accessibilityLabel: a11yLabel,
|
|
3330
|
+
accessibilityState: { disabled }
|
|
3026
3331
|
},
|
|
3027
|
-
resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style:
|
|
3028
|
-
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style:
|
|
3332
|
+
resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles27.iconContainer }, resolvedIcon) : null,
|
|
3333
|
+
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles27.labelContainer }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3029
3334
|
reactNative.Text,
|
|
3030
3335
|
{
|
|
3031
|
-
style: [
|
|
3336
|
+
style: [styles27.label, { color: colors.foreground }, labelStyle],
|
|
3032
3337
|
numberOfLines: 1,
|
|
3033
3338
|
allowFontScaling: true
|
|
3034
3339
|
},
|
|
@@ -3036,7 +3341,7 @@ function MenuItem({
|
|
|
3036
3341
|
), subtitle ? /* @__PURE__ */ React26__default.default.createElement(
|
|
3037
3342
|
reactNative.Text,
|
|
3038
3343
|
{
|
|
3039
|
-
style: [
|
|
3344
|
+
style: [styles27.subtitle, { color: colors.foregroundMuted }],
|
|
3040
3345
|
numberOfLines: 1,
|
|
3041
3346
|
allowFontScaling: true
|
|
3042
3347
|
},
|
|
@@ -3045,7 +3350,7 @@ function MenuItem({
|
|
|
3045
3350
|
rightRender !== void 0 ? /* @__PURE__ */ React26__default.default.createElement(
|
|
3046
3351
|
reactNative.View,
|
|
3047
3352
|
{
|
|
3048
|
-
style:
|
|
3353
|
+
style: styles27.rightContainer,
|
|
3049
3354
|
onStartShouldSetResponder: () => true,
|
|
3050
3355
|
onResponderRelease: () => {
|
|
3051
3356
|
}
|
|
@@ -3056,21 +3361,18 @@ function MenuItem({
|
|
|
3056
3361
|
reactNative.View,
|
|
3057
3362
|
{
|
|
3058
3363
|
style: [
|
|
3059
|
-
|
|
3060
|
-
{
|
|
3061
|
-
backgroundColor: colors.border,
|
|
3062
|
-
marginLeft: resolvedIcon ? s(22) + s(12) : 0,
|
|
3063
|
-
opacity: 0.6
|
|
3064
|
-
}
|
|
3364
|
+
styles27.separator,
|
|
3365
|
+
{ backgroundColor: colors.separator }
|
|
3065
3366
|
]
|
|
3066
3367
|
}
|
|
3067
3368
|
) : null);
|
|
3068
3369
|
}
|
|
3069
|
-
var
|
|
3370
|
+
var MenuItem = React26__default.default.memo(MenuItemBase);
|
|
3371
|
+
var styles27 = reactNative.StyleSheet.create({
|
|
3070
3372
|
container: {
|
|
3071
3373
|
flexDirection: "row",
|
|
3072
3374
|
alignItems: "center",
|
|
3073
|
-
paddingHorizontal:
|
|
3375
|
+
paddingHorizontal: s(16),
|
|
3074
3376
|
paddingVertical: vs(16),
|
|
3075
3377
|
minHeight: vs(54),
|
|
3076
3378
|
gap: s(12)
|
|
@@ -3086,11 +3388,11 @@ var styles26 = reactNative.StyleSheet.create({
|
|
|
3086
3388
|
justifyContent: "center"
|
|
3087
3389
|
},
|
|
3088
3390
|
label: {
|
|
3089
|
-
fontFamily: "
|
|
3391
|
+
fontFamily: "Sohne-Medium",
|
|
3090
3392
|
fontSize: ms(15)
|
|
3091
3393
|
},
|
|
3092
3394
|
subtitle: {
|
|
3093
|
-
fontFamily: "
|
|
3395
|
+
fontFamily: "Sohne-Regular",
|
|
3094
3396
|
fontSize: ms(12),
|
|
3095
3397
|
marginTop: vs(1)
|
|
3096
3398
|
},
|
|
@@ -3107,64 +3409,114 @@ var styles26 = reactNative.StyleSheet.create({
|
|
|
3107
3409
|
opacity: 0.45
|
|
3108
3410
|
}
|
|
3109
3411
|
});
|
|
3110
|
-
|
|
3111
|
-
function Chip({ label, selected = false, onPress, icon, iconName, style }) {
|
|
3412
|
+
function MenuGroup({ children, variant = "plain", style }) {
|
|
3112
3413
|
const { colors } = useTheme();
|
|
3113
|
-
const
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3414
|
+
const processedChildren = React26__default.default.Children.map(children, (child, index) => {
|
|
3415
|
+
if (!React26__default.default.isValidElement(child)) return child;
|
|
3416
|
+
if (child.type === MenuGroupHeader || child.type === MenuGroupFooter) {
|
|
3417
|
+
return child;
|
|
3418
|
+
}
|
|
3419
|
+
const childProps = child.props;
|
|
3420
|
+
const isMenuItem = "onPress" in childProps;
|
|
3421
|
+
if (!isMenuItem) return child;
|
|
3422
|
+
const isLast = index === React26__default.default.Children.count(children) - 1;
|
|
3423
|
+
if (childProps["showSeparator"] === void 0 && !isLast) {
|
|
3424
|
+
return React26__default.default.cloneElement(child, {
|
|
3425
|
+
showSeparator: true
|
|
3426
|
+
});
|
|
3427
|
+
}
|
|
3428
|
+
return child;
|
|
3429
|
+
});
|
|
3430
|
+
const cardStyle = variant === "card" ? {
|
|
3431
|
+
backgroundColor: colors.card,
|
|
3432
|
+
borderRadius: RADIUS.md,
|
|
3433
|
+
borderWidth: 1,
|
|
3434
|
+
borderColor: colors.border,
|
|
3435
|
+
shadowColor: "#000",
|
|
3436
|
+
shadowOffset: { width: 0, height: 2 },
|
|
3437
|
+
shadowOpacity: 0.06,
|
|
3438
|
+
shadowRadius: 6,
|
|
3439
|
+
elevation: 2,
|
|
3440
|
+
paddingVertical: vs(4)
|
|
3441
|
+
} : {};
|
|
3442
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.container, cardStyle, style] }, processedChildren);
|
|
3443
|
+
}
|
|
3444
|
+
function MenuGroupHeader({ children, style }) {
|
|
3445
|
+
const { colors } = useTheme();
|
|
3446
|
+
if (typeof children === "string") {
|
|
3447
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.header, { borderBottomColor: colors.separator }, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles28.headerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
|
|
3448
|
+
}
|
|
3449
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.header, { borderBottomColor: colors.separator }, style] }, children);
|
|
3450
|
+
}
|
|
3451
|
+
function MenuGroupFooter({ children, style }) {
|
|
3452
|
+
const { colors } = useTheme();
|
|
3453
|
+
if (typeof children === "string") {
|
|
3454
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.footer, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles28.footerText, { color: colors.foregroundMuted }], allowFontScaling: true }, children));
|
|
3455
|
+
}
|
|
3456
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles28.footer, style] }, children);
|
|
3457
|
+
}
|
|
3458
|
+
MenuGroup.Header = MenuGroupHeader;
|
|
3459
|
+
MenuGroup.Footer = MenuGroupFooter;
|
|
3460
|
+
var styles28 = reactNative.StyleSheet.create({
|
|
3461
|
+
container: {
|
|
3462
|
+
overflow: "hidden"
|
|
3463
|
+
},
|
|
3464
|
+
header: {
|
|
3465
|
+
paddingHorizontal: s(16),
|
|
3466
|
+
paddingTop: vs(12),
|
|
3467
|
+
paddingBottom: vs(8),
|
|
3468
|
+
borderBottomWidth: reactNative.StyleSheet.hairlineWidth
|
|
3469
|
+
},
|
|
3470
|
+
headerText: {
|
|
3471
|
+
fontFamily: "Sohne-SemiBold",
|
|
3472
|
+
fontSize: 13,
|
|
3473
|
+
letterSpacing: 0.32,
|
|
3474
|
+
textTransform: "uppercase"
|
|
3475
|
+
},
|
|
3476
|
+
footer: {
|
|
3477
|
+
paddingHorizontal: s(16),
|
|
3478
|
+
paddingTop: vs(8),
|
|
3479
|
+
paddingBottom: vs(12)
|
|
3480
|
+
},
|
|
3481
|
+
footerText: {
|
|
3482
|
+
fontFamily: "Sohne-Regular",
|
|
3483
|
+
fontSize: 12
|
|
3484
|
+
}
|
|
3485
|
+
});
|
|
3486
|
+
function ChipBase({ label, selected = false, onPress, icon, iconName, style, accessibilityLabel }) {
|
|
3487
|
+
const { colors } = useTheme();
|
|
3488
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
3489
|
+
pressScale: PRESS_SCALE.chip
|
|
3490
|
+
});
|
|
3491
|
+
const colorProgress = useColorTransition(selected);
|
|
3492
|
+
const surfaceStyle = Animated9.useAnimatedStyle(() => ({
|
|
3493
|
+
backgroundColor: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.surface, colors.primary]),
|
|
3494
|
+
borderColor: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.border, colors.primary])
|
|
3495
|
+
}));
|
|
3496
|
+
const textStyle = Animated9.useAnimatedStyle(() => ({
|
|
3497
|
+
color: Animated9.interpolateColor(colorProgress.value, [0, 1], [colors.foreground, colors.primaryForeground])
|
|
3498
|
+
}));
|
|
3139
3499
|
const handlePress = () => {
|
|
3140
3500
|
selectionAsync();
|
|
3141
3501
|
onPress?.();
|
|
3142
3502
|
};
|
|
3143
|
-
const backgroundColor = pressAnim.interpolate({
|
|
3144
|
-
inputRange: [0, 1],
|
|
3145
|
-
outputRange: [colors.surface, colors.primary]
|
|
3146
|
-
});
|
|
3147
|
-
const textColor = pressAnim.interpolate({
|
|
3148
|
-
inputRange: [0, 1],
|
|
3149
|
-
outputRange: [colors.foreground, colors.primaryForeground]
|
|
3150
|
-
});
|
|
3151
|
-
const borderColor = pressAnim.interpolate({
|
|
3152
|
-
inputRange: [0, 1],
|
|
3153
|
-
outputRange: [colors.border, colors.primary]
|
|
3154
|
-
});
|
|
3155
3503
|
const resolvedIcon = iconName ? renderIcon(iconName, ms(13), selected ? colors.primaryForeground : colors.foreground) : icon;
|
|
3156
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
3504
|
+
return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles29.wrapper, scaleStyle, style], ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3157
3505
|
reactNative.TouchableOpacity,
|
|
3158
3506
|
{
|
|
3159
3507
|
onPress: handlePress,
|
|
3160
|
-
onPressIn
|
|
3161
|
-
onPressOut
|
|
3508
|
+
onPressIn,
|
|
3509
|
+
onPressOut,
|
|
3162
3510
|
activeOpacity: 1,
|
|
3163
|
-
touchSoundDisabled: true
|
|
3511
|
+
touchSoundDisabled: true,
|
|
3512
|
+
accessibilityRole: "button",
|
|
3513
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
3514
|
+
accessibilityState: { selected }
|
|
3164
3515
|
},
|
|
3165
|
-
/* @__PURE__ */ React26__default.default.createElement(
|
|
3516
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles29.chip, surfaceStyle] }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles29.chipIcon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.Text, { style: [styles29.label, textStyle], allowFontScaling: true }, label))
|
|
3166
3517
|
));
|
|
3167
3518
|
}
|
|
3519
|
+
var Chip = React26__default.default.memo(ChipBase);
|
|
3168
3520
|
function ChipGroup({ options, value, onValueChange, multiSelect = false, style }) {
|
|
3169
3521
|
const handlePress = (optionValue) => {
|
|
3170
3522
|
if (!multiSelect) {
|
|
@@ -3173,21 +3525,14 @@ function ChipGroup({ options, value, onValueChange, multiSelect = false, style }
|
|
|
3173
3525
|
}
|
|
3174
3526
|
const currentArray = Array.isArray(value) ? value : value ? [value] : [];
|
|
3175
3527
|
const isSelected2 = currentArray.includes(optionValue);
|
|
3176
|
-
|
|
3177
|
-
if (isSelected2) {
|
|
3178
|
-
newArray = currentArray.filter((v) => v !== optionValue);
|
|
3179
|
-
} else {
|
|
3180
|
-
newArray = [...currentArray, optionValue];
|
|
3181
|
-
}
|
|
3528
|
+
const newArray = isSelected2 ? currentArray.filter((v) => v !== optionValue) : [...currentArray, optionValue];
|
|
3182
3529
|
onValueChange?.(newArray);
|
|
3183
3530
|
};
|
|
3184
3531
|
const isSelected = (optionValue) => {
|
|
3185
|
-
if (Array.isArray(value))
|
|
3186
|
-
return value.includes(optionValue);
|
|
3187
|
-
}
|
|
3532
|
+
if (Array.isArray(value)) return value.includes(optionValue);
|
|
3188
3533
|
return optionValue === value;
|
|
3189
3534
|
};
|
|
3190
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
3535
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles29.group, style] }, options.map((opt) => /* @__PURE__ */ React26__default.default.createElement(
|
|
3191
3536
|
Chip,
|
|
3192
3537
|
{
|
|
3193
3538
|
key: opt.value,
|
|
@@ -3195,28 +3540,35 @@ function ChipGroup({ options, value, onValueChange, multiSelect = false, style }
|
|
|
3195
3540
|
selected: isSelected(opt.value),
|
|
3196
3541
|
onPress: opt.disabled ? void 0 : () => handlePress(opt.value),
|
|
3197
3542
|
iconName: opt.iconName,
|
|
3198
|
-
style: opt.disabled ?
|
|
3543
|
+
style: opt.disabled ? styles29.chipDisabled : void 0,
|
|
3544
|
+
accessibilityLabel: opt.disabled ? `${opt.label}, unavailable` : opt.label
|
|
3199
3545
|
}
|
|
3200
3546
|
)));
|
|
3201
3547
|
}
|
|
3202
|
-
var
|
|
3548
|
+
var styles29 = reactNative.StyleSheet.create({
|
|
3203
3549
|
wrapper: {},
|
|
3204
3550
|
chip: {
|
|
3205
3551
|
borderRadius: 999,
|
|
3206
3552
|
paddingHorizontal: s(14),
|
|
3207
|
-
|
|
3553
|
+
// AUDIT FIX: was vs(5) → ~28px total height — below WCAG 44px tap target.
|
|
3554
|
+
// vs(10) → ~44px total height meets WCAG 2.5.5 (AAA) minimum.
|
|
3555
|
+
paddingVertical: vs(10),
|
|
3556
|
+
minHeight: 44,
|
|
3208
3557
|
borderWidth: 1,
|
|
3209
3558
|
alignItems: "center",
|
|
3210
3559
|
justifyContent: "center",
|
|
3211
3560
|
flexDirection: "row",
|
|
3212
3561
|
gap: s(5)
|
|
3213
3562
|
},
|
|
3563
|
+
chipDisabled: {
|
|
3564
|
+
opacity: 0.4
|
|
3565
|
+
},
|
|
3214
3566
|
chipIcon: {
|
|
3215
3567
|
alignItems: "center",
|
|
3216
3568
|
justifyContent: "center"
|
|
3217
3569
|
},
|
|
3218
3570
|
label: {
|
|
3219
|
-
fontFamily: "
|
|
3571
|
+
fontFamily: "Sohne-Medium",
|
|
3220
3572
|
fontSize: ms(13),
|
|
3221
3573
|
lineHeight: mvs(18)
|
|
3222
3574
|
},
|
|
@@ -3262,11 +3614,11 @@ function ConfirmDialog({
|
|
|
3262
3614
|
enableDynamicSizing: true,
|
|
3263
3615
|
onDismiss: onCancel,
|
|
3264
3616
|
backdropComponent: renderBackdrop,
|
|
3265
|
-
backgroundStyle: [
|
|
3266
|
-
handleIndicatorStyle: [
|
|
3617
|
+
backgroundStyle: [styles30.background, { backgroundColor: colors.card }],
|
|
3618
|
+
handleIndicatorStyle: [styles30.handle, { backgroundColor: colors.border }],
|
|
3267
3619
|
enablePanDownToClose: true
|
|
3268
3620
|
},
|
|
3269
|
-
/* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style:
|
|
3621
|
+
/* @__PURE__ */ React26__default.default.createElement(bottomSheet.BottomSheetView, { style: styles30.content }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles30.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles30.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles30.actions }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3270
3622
|
Button,
|
|
3271
3623
|
{
|
|
3272
3624
|
label: confirmLabel,
|
|
@@ -3300,7 +3652,7 @@ function ConfirmDialog({
|
|
|
3300
3652
|
)))
|
|
3301
3653
|
);
|
|
3302
3654
|
}
|
|
3303
|
-
var
|
|
3655
|
+
var styles30 = reactNative.StyleSheet.create({
|
|
3304
3656
|
background: {
|
|
3305
3657
|
borderTopLeftRadius: ms(16),
|
|
3306
3658
|
borderTopRightRadius: ms(16)
|
|
@@ -3316,12 +3668,12 @@ var styles28 = reactNative.StyleSheet.create({
|
|
|
3316
3668
|
gap: vs(12)
|
|
3317
3669
|
},
|
|
3318
3670
|
title: {
|
|
3319
|
-
fontFamily: "
|
|
3671
|
+
fontFamily: "Sohne-SemiBold",
|
|
3320
3672
|
fontSize: ms(18),
|
|
3321
3673
|
lineHeight: mvs(26)
|
|
3322
3674
|
},
|
|
3323
3675
|
description: {
|
|
3324
|
-
fontFamily: "
|
|
3676
|
+
fontFamily: "Sohne-Regular",
|
|
3325
3677
|
fontSize: ms(15),
|
|
3326
3678
|
lineHeight: mvs(22)
|
|
3327
3679
|
},
|
|
@@ -3330,12 +3682,13 @@ var styles28 = reactNative.StyleSheet.create({
|
|
|
3330
3682
|
marginTop: vs(8)
|
|
3331
3683
|
}
|
|
3332
3684
|
});
|
|
3333
|
-
function
|
|
3685
|
+
function LabelValueBase({ label, value, iconName, iconColor, style }) {
|
|
3334
3686
|
const { colors } = useTheme();
|
|
3335
3687
|
const resolvedIcon = iconName ? renderIcon(iconName, ms(14), iconColor ?? colors.foregroundMuted) : null;
|
|
3336
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
3688
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles31.container, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles31.labelSide }, resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles31.icon }, resolvedIcon) : null, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.label, { color: colors.foregroundMuted }], allowFontScaling: true }, label)), typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles31.value, { color: colors.foreground }], allowFontScaling: true }, value) : value);
|
|
3337
3689
|
}
|
|
3338
|
-
var
|
|
3690
|
+
var LabelValue = React26__default.default.memo(LabelValueBase);
|
|
3691
|
+
var styles31 = reactNative.StyleSheet.create({
|
|
3339
3692
|
container: {
|
|
3340
3693
|
flexDirection: "row",
|
|
3341
3694
|
justifyContent: "space-between",
|
|
@@ -3352,12 +3705,12 @@ var styles29 = reactNative.StyleSheet.create({
|
|
|
3352
3705
|
justifyContent: "center"
|
|
3353
3706
|
},
|
|
3354
3707
|
label: {
|
|
3355
|
-
fontFamily: "
|
|
3708
|
+
fontFamily: "Sohne-Regular",
|
|
3356
3709
|
fontSize: ms(13),
|
|
3357
3710
|
lineHeight: mvs(18)
|
|
3358
3711
|
},
|
|
3359
3712
|
value: {
|
|
3360
|
-
fontFamily: "
|
|
3713
|
+
fontFamily: "Sohne-Medium",
|
|
3361
3714
|
fontSize: ms(14),
|
|
3362
3715
|
lineHeight: mvs(20),
|
|
3363
3716
|
textAlign: "right"
|
|
@@ -3392,27 +3745,41 @@ function MonthPicker({ value, onChange, locale = "en", formatLabel, style }) {
|
|
|
3392
3745
|
onChange({ month: value.month + 1, year: value.year });
|
|
3393
3746
|
}
|
|
3394
3747
|
};
|
|
3395
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
3748
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles32.container, style], accessibilityRole: "adjustable", accessibilityLabel: getLabel() }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3396
3749
|
reactNative.TouchableOpacity,
|
|
3397
3750
|
{
|
|
3398
|
-
style:
|
|
3751
|
+
style: styles32.arrow,
|
|
3399
3752
|
onPress: handlePrev,
|
|
3400
3753
|
activeOpacity: 0.6,
|
|
3401
|
-
touchSoundDisabled: true
|
|
3754
|
+
touchSoundDisabled: true,
|
|
3755
|
+
accessibilityRole: "button",
|
|
3756
|
+
accessibilityLabel: "Previous month",
|
|
3757
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }
|
|
3402
3758
|
},
|
|
3403
3759
|
/* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-left", size: 22, color: colors.foreground })
|
|
3404
|
-
), /* @__PURE__ */ React26__default.default.createElement(
|
|
3760
|
+
), /* @__PURE__ */ React26__default.default.createElement(
|
|
3761
|
+
reactNative.Text,
|
|
3762
|
+
{
|
|
3763
|
+
style: [styles32.label, { color: colors.foreground }],
|
|
3764
|
+
allowFontScaling: true,
|
|
3765
|
+
accessibilityLiveRegion: "polite"
|
|
3766
|
+
},
|
|
3767
|
+
getLabel()
|
|
3768
|
+
), /* @__PURE__ */ React26__default.default.createElement(
|
|
3405
3769
|
reactNative.TouchableOpacity,
|
|
3406
3770
|
{
|
|
3407
|
-
style:
|
|
3771
|
+
style: styles32.arrow,
|
|
3408
3772
|
onPress: handleNext,
|
|
3409
3773
|
activeOpacity: 0.6,
|
|
3410
|
-
touchSoundDisabled: true
|
|
3774
|
+
touchSoundDisabled: true,
|
|
3775
|
+
accessibilityRole: "button",
|
|
3776
|
+
accessibilityLabel: "Next month",
|
|
3777
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }
|
|
3411
3778
|
},
|
|
3412
3779
|
/* @__PURE__ */ React26__default.default.createElement(vectorIcons.Entypo, { name: "chevron-right", size: 22, color: colors.foreground })
|
|
3413
3780
|
));
|
|
3414
3781
|
}
|
|
3415
|
-
var
|
|
3782
|
+
var styles32 = reactNative.StyleSheet.create({
|
|
3416
3783
|
container: {
|
|
3417
3784
|
flexDirection: "row",
|
|
3418
3785
|
alignItems: "center",
|
|
@@ -3425,25 +3792,13 @@ var styles30 = reactNative.StyleSheet.create({
|
|
|
3425
3792
|
justifyContent: "center"
|
|
3426
3793
|
},
|
|
3427
3794
|
label: {
|
|
3428
|
-
fontFamily: "
|
|
3795
|
+
fontFamily: "Sohne-Medium",
|
|
3429
3796
|
fontSize: ms(17),
|
|
3430
3797
|
lineHeight: mvs(24),
|
|
3431
3798
|
textAlign: "center",
|
|
3432
3799
|
minWidth: s(160)
|
|
3433
3800
|
}
|
|
3434
3801
|
});
|
|
3435
|
-
function useHover() {
|
|
3436
|
-
const [hovered, setHovered] = React26.useState(false);
|
|
3437
|
-
const onMouseEnter = React26.useCallback(() => setHovered(true), []);
|
|
3438
|
-
const onMouseLeave = React26.useCallback(() => setHovered(false), []);
|
|
3439
|
-
if (reactNative.Platform.OS !== "web") {
|
|
3440
|
-
return { hovered: false, hoverHandlers: {} };
|
|
3441
|
-
}
|
|
3442
|
-
return { hovered, hoverHandlers: { onMouseEnter, onMouseLeave } };
|
|
3443
|
-
}
|
|
3444
|
-
|
|
3445
|
-
// src/components/MediaCard/MediaCard.tsx
|
|
3446
|
-
var nativeDriver13 = reactNative.Platform.OS !== "web";
|
|
3447
3802
|
var aspectRatioMap = {
|
|
3448
3803
|
"1:1": 1,
|
|
3449
3804
|
"4:3": 3 / 4,
|
|
@@ -3451,7 +3806,7 @@ var aspectRatioMap = {
|
|
|
3451
3806
|
"4:5": 5 / 4,
|
|
3452
3807
|
"3:2": 2 / 3
|
|
3453
3808
|
};
|
|
3454
|
-
function
|
|
3809
|
+
function MediaCardBase({
|
|
3455
3810
|
imageSource,
|
|
3456
3811
|
aspectRatio = "4:3",
|
|
3457
3812
|
badge,
|
|
@@ -3465,19 +3820,17 @@ function MediaCard({
|
|
|
3465
3820
|
onPress,
|
|
3466
3821
|
style,
|
|
3467
3822
|
imageStyle,
|
|
3468
|
-
footer
|
|
3823
|
+
footer,
|
|
3824
|
+
accessibilityLabel
|
|
3469
3825
|
}) {
|
|
3470
3826
|
const { colors } = useTheme();
|
|
3471
|
-
const scale2 = React26.useRef(new reactNative.Animated.Value(1)).current;
|
|
3472
3827
|
const { hovered, hoverHandlers } = useHover();
|
|
3473
|
-
const
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
reactNative.Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver13, speed: 40, bounciness: 4 }).start();
|
|
3480
|
-
};
|
|
3828
|
+
const { animatedStyle, onPressIn, onPressOut } = usePressScale({
|
|
3829
|
+
pressScale: PRESS_SCALE.card,
|
|
3830
|
+
pressInSpring: SPRINGS.surfacePressIn,
|
|
3831
|
+
pressOutSpring: SPRINGS.surfacePressOut,
|
|
3832
|
+
disabled: !onPress
|
|
3833
|
+
});
|
|
3481
3834
|
const handlePress = () => {
|
|
3482
3835
|
if (!onPress) return;
|
|
3483
3836
|
impactLight();
|
|
@@ -3485,62 +3838,67 @@ function MediaCard({
|
|
|
3485
3838
|
};
|
|
3486
3839
|
const ratio = aspectRatioMap[aspectRatio];
|
|
3487
3840
|
const resolvedActionIcon = actionIconName ? renderIcon(actionIconName, 18, actionActive ? colors.primary : colors.background) : actionIcon ?? renderIcon("heart", 18, actionActive ? colors.primary : colors.background);
|
|
3841
|
+
const a11yLabel = accessibilityLabel ?? [title, subtitle].filter(Boolean).join(". ");
|
|
3488
3842
|
const cardContent = /* @__PURE__ */ React26__default.default.createElement(
|
|
3489
3843
|
reactNative.View,
|
|
3490
3844
|
{
|
|
3491
3845
|
style: [
|
|
3492
|
-
|
|
3493
|
-
hovered &&
|
|
3846
|
+
styles33.card,
|
|
3847
|
+
hovered && styles33.cardHovered,
|
|
3494
3848
|
style
|
|
3495
3849
|
],
|
|
3496
3850
|
...reactNative.Platform.OS === "web" ? hoverHandlers : {}
|
|
3497
3851
|
},
|
|
3498
|
-
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
3852
|
+
/* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles33.imageContainer, imageStyle] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: { paddingTop: `${ratio * 100}%` } }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: reactNative.StyleSheet.absoluteFill }, imageSource ? /* @__PURE__ */ React26__default.default.createElement(
|
|
3499
3853
|
reactNative.Image,
|
|
3500
3854
|
{
|
|
3501
3855
|
source: imageSource,
|
|
3502
|
-
style:
|
|
3856
|
+
style: styles33.image,
|
|
3503
3857
|
resizeMode: "cover"
|
|
3504
3858
|
}
|
|
3505
|
-
) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
3859
|
+
) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles33.imagePlaceholder, { backgroundColor: colors.surface }] }))), badge && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.badgeContainer }, badge), (onActionPress || actionIcon || actionIconName) && /* @__PURE__ */ React26__default.default.createElement(
|
|
3506
3860
|
reactNative.TouchableOpacity,
|
|
3507
3861
|
{
|
|
3508
|
-
style: [
|
|
3862
|
+
style: [styles33.actionButton, { backgroundColor: "rgba(0,0,0,0.24)" }],
|
|
3509
3863
|
onPress: () => {
|
|
3510
3864
|
impactLight();
|
|
3511
3865
|
onActionPress?.();
|
|
3512
3866
|
},
|
|
3513
3867
|
activeOpacity: 0.8,
|
|
3514
|
-
touchSoundDisabled: true
|
|
3868
|
+
touchSoundDisabled: true,
|
|
3869
|
+
accessibilityRole: "button",
|
|
3870
|
+
accessibilityLabel: actionIconName ?? "action",
|
|
3871
|
+
accessibilityState: { selected: actionActive }
|
|
3515
3872
|
},
|
|
3516
3873
|
resolvedActionIcon
|
|
3517
3874
|
)),
|
|
3518
|
-
(title || subtitle || caption || footer) && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style:
|
|
3875
|
+
(title || subtitle || caption || footer) && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.meta }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles33.title, { color: colors.foreground }], numberOfLines: 2, allowFontScaling: true }, title) : null, subtitle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles33.subtitle, { color: colors.foregroundSubtle }], numberOfLines: 1, allowFontScaling: true }, subtitle) : null, caption ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles33.caption, { color: colors.foregroundMuted }], numberOfLines: 1, allowFontScaling: true }, caption) : null, footer)
|
|
3519
3876
|
);
|
|
3520
3877
|
if (onPress) {
|
|
3521
|
-
return /* @__PURE__ */ React26__default.default.createElement(
|
|
3878
|
+
return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: animatedStyle }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3522
3879
|
reactNative.TouchableOpacity,
|
|
3523
3880
|
{
|
|
3524
3881
|
onPress: handlePress,
|
|
3525
|
-
onPressIn
|
|
3526
|
-
onPressOut
|
|
3882
|
+
onPressIn,
|
|
3883
|
+
onPressOut,
|
|
3527
3884
|
activeOpacity: 1,
|
|
3528
|
-
touchSoundDisabled: true
|
|
3885
|
+
touchSoundDisabled: true,
|
|
3886
|
+
accessibilityRole: "button",
|
|
3887
|
+
accessibilityLabel: a11yLabel
|
|
3529
3888
|
},
|
|
3530
3889
|
cardContent
|
|
3531
3890
|
));
|
|
3532
3891
|
}
|
|
3533
3892
|
return cardContent;
|
|
3534
3893
|
}
|
|
3535
|
-
var
|
|
3894
|
+
var MediaCard = React26__default.default.memo(MediaCardBase);
|
|
3895
|
+
var styles33 = reactNative.StyleSheet.create({
|
|
3536
3896
|
card: {
|
|
3537
3897
|
borderRadius: RADIUS.md,
|
|
3538
|
-
// 14px — Airbnb property card spec
|
|
3539
3898
|
overflow: "hidden",
|
|
3540
3899
|
backgroundColor: "transparent"
|
|
3541
3900
|
},
|
|
3542
3901
|
cardHovered: {
|
|
3543
|
-
// Web hover: lift shadow
|
|
3544
3902
|
...SHADOWS.md
|
|
3545
3903
|
},
|
|
3546
3904
|
imageContainer: {
|
|
@@ -3576,98 +3934,99 @@ var styles31 = reactNative.StyleSheet.create({
|
|
|
3576
3934
|
gap: vs(2)
|
|
3577
3935
|
},
|
|
3578
3936
|
title: {
|
|
3579
|
-
fontFamily: "
|
|
3937
|
+
fontFamily: "Sohne-SemiBold",
|
|
3580
3938
|
fontSize: ms(14),
|
|
3581
3939
|
lineHeight: mvs(20)
|
|
3582
3940
|
},
|
|
3583
3941
|
subtitle: {
|
|
3584
|
-
fontFamily: "
|
|
3942
|
+
fontFamily: "Sohne-Regular",
|
|
3585
3943
|
fontSize: ms(13),
|
|
3586
3944
|
lineHeight: mvs(18)
|
|
3587
3945
|
},
|
|
3588
3946
|
caption: {
|
|
3589
|
-
fontFamily: "
|
|
3947
|
+
fontFamily: "Sohne-Regular",
|
|
3590
3948
|
fontSize: ms(12),
|
|
3591
3949
|
lineHeight: mvs(16)
|
|
3592
3950
|
}
|
|
3593
3951
|
});
|
|
3594
|
-
var
|
|
3595
|
-
function CategoryChip({
|
|
3952
|
+
var CategoryChip = React26__default.default.memo(function CategoryChip2({
|
|
3596
3953
|
item,
|
|
3597
3954
|
selected,
|
|
3598
|
-
|
|
3955
|
+
onSelect
|
|
3599
3956
|
}) {
|
|
3600
3957
|
const { colors } = useTheme();
|
|
3601
|
-
const
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
const
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
const
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3958
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
3959
|
+
pressScale: PRESS_SCALE.chip
|
|
3960
|
+
});
|
|
3961
|
+
const progress = useColorTransition(selected);
|
|
3962
|
+
const surfaceStyle = Animated9.useAnimatedStyle(() => ({
|
|
3963
|
+
backgroundColor: Animated9.interpolateColor(progress.value, [0, 1], [colors.surface, colors.primary]),
|
|
3964
|
+
borderColor: Animated9.interpolateColor(progress.value, [0, 1], [colors.border, colors.primary])
|
|
3965
|
+
}));
|
|
3966
|
+
const textColorStyle = Animated9.useAnimatedStyle(() => ({
|
|
3967
|
+
color: Animated9.interpolateColor(progress.value, [0, 1], [colors.foregroundSubtle, colors.primaryForeground])
|
|
3968
|
+
}));
|
|
3969
|
+
const iconColor = selected ? colors.primaryForeground : colors.foregroundSubtle;
|
|
3970
|
+
const resolvedIcon = typeof item.icon === "string" ? renderIcon(item.icon, 16, iconColor) : item.icon ?? null;
|
|
3971
|
+
return /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: scaleStyle, ...hoverHandlers }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3613
3972
|
reactNative.TouchableOpacity,
|
|
3614
3973
|
{
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
backgroundColor: bgColor,
|
|
3619
|
-
borderColor
|
|
3620
|
-
}
|
|
3621
|
-
],
|
|
3622
|
-
onPress,
|
|
3623
|
-
onPressIn: handlePressIn,
|
|
3624
|
-
onPressOut: handlePressOut,
|
|
3974
|
+
onPress: () => onSelect(item.value),
|
|
3975
|
+
onPressIn,
|
|
3976
|
+
onPressOut,
|
|
3625
3977
|
activeOpacity: 1,
|
|
3626
|
-
touchSoundDisabled: true
|
|
3978
|
+
touchSoundDisabled: true,
|
|
3979
|
+
accessibilityRole: "button",
|
|
3980
|
+
accessibilityLabel: item.label,
|
|
3981
|
+
accessibilityState: { selected }
|
|
3627
3982
|
},
|
|
3628
|
-
resolvedIcon && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style:
|
|
3629
|
-
/* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles32.chipLabel, { color: textColor }], allowFontScaling: true }, item.label),
|
|
3630
|
-
item.badge !== void 0 && item.badge > 0 && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles32.chipBadge, { backgroundColor: colors.primary }] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles32.chipBadgeText, { color: colors.primaryForeground }] }, Math.min(item.badge, 99)))
|
|
3983
|
+
/* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.View, { style: [styles34.chip, surfaceStyle] }, resolvedIcon && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles34.chipIcon }, resolvedIcon), /* @__PURE__ */ React26__default.default.createElement(Animated9__default.default.Text, { style: [styles34.chipLabel, textColorStyle], allowFontScaling: true }, item.label), item.badge !== void 0 && item.badge > 0 && /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles34.chipBadge, { backgroundColor: colors.primary }] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles34.chipBadgeText, { color: colors.primaryForeground }] }, Math.min(item.badge, 99))))
|
|
3631
3984
|
));
|
|
3632
|
-
}
|
|
3985
|
+
});
|
|
3633
3986
|
function CategoryStrip({
|
|
3634
3987
|
categories,
|
|
3635
3988
|
value,
|
|
3636
3989
|
onValueChange,
|
|
3637
3990
|
multiSelect = false,
|
|
3638
3991
|
style,
|
|
3639
|
-
itemStyle
|
|
3992
|
+
itemStyle,
|
|
3993
|
+
accessibilityLabel
|
|
3640
3994
|
}) {
|
|
3641
3995
|
const selected = Array.isArray(value) ? value : value ? [value] : [];
|
|
3642
|
-
const handlePress = (
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3996
|
+
const handlePress = React26.useCallback(
|
|
3997
|
+
(v) => {
|
|
3998
|
+
selectionAsync();
|
|
3999
|
+
if (multiSelect) {
|
|
4000
|
+
const current = Array.isArray(value) ? value : value ? [value] : [];
|
|
4001
|
+
const next = current.includes(v) ? current.filter((x) => x !== v) : [...current, v];
|
|
4002
|
+
onValueChange?.(next);
|
|
4003
|
+
} else {
|
|
4004
|
+
onValueChange?.(v === value ? "" : v);
|
|
4005
|
+
}
|
|
4006
|
+
},
|
|
4007
|
+
[multiSelect, value, onValueChange]
|
|
4008
|
+
);
|
|
3652
4009
|
return /* @__PURE__ */ React26__default.default.createElement(
|
|
3653
4010
|
reactNative.ScrollView,
|
|
3654
4011
|
{
|
|
3655
4012
|
horizontal: true,
|
|
3656
4013
|
showsHorizontalScrollIndicator: false,
|
|
3657
|
-
contentContainerStyle: [
|
|
3658
|
-
style:
|
|
4014
|
+
contentContainerStyle: [styles34.container, style],
|
|
4015
|
+
style: styles34.scroll,
|
|
4016
|
+
accessibilityRole: multiSelect ? void 0 : "radiogroup",
|
|
4017
|
+
accessibilityLabel
|
|
3659
4018
|
},
|
|
3660
4019
|
categories.map((cat) => /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { key: cat.value, style: itemStyle }, /* @__PURE__ */ React26__default.default.createElement(
|
|
3661
4020
|
CategoryChip,
|
|
3662
4021
|
{
|
|
3663
4022
|
item: cat,
|
|
3664
4023
|
selected: selected.includes(cat.value),
|
|
3665
|
-
|
|
4024
|
+
onSelect: handlePress
|
|
3666
4025
|
}
|
|
3667
4026
|
)))
|
|
3668
4027
|
);
|
|
3669
4028
|
}
|
|
3670
|
-
var
|
|
4029
|
+
var styles34 = reactNative.StyleSheet.create({
|
|
3671
4030
|
scroll: {
|
|
3672
4031
|
flexGrow: 0
|
|
3673
4032
|
},
|
|
@@ -3691,7 +4050,7 @@ var styles32 = reactNative.StyleSheet.create({
|
|
|
3691
4050
|
justifyContent: "center"
|
|
3692
4051
|
},
|
|
3693
4052
|
chipLabel: {
|
|
3694
|
-
fontFamily: "
|
|
4053
|
+
fontFamily: "Sohne-Medium",
|
|
3695
4054
|
fontSize: ms(13)
|
|
3696
4055
|
},
|
|
3697
4056
|
chipBadge: {
|
|
@@ -3703,67 +4062,50 @@ var styles32 = reactNative.StyleSheet.create({
|
|
|
3703
4062
|
justifyContent: "center"
|
|
3704
4063
|
},
|
|
3705
4064
|
chipBadgeText: {
|
|
3706
|
-
fontFamily: "
|
|
4065
|
+
fontFamily: "Sohne-Bold",
|
|
3707
4066
|
fontSize: ms(9),
|
|
3708
4067
|
lineHeight: 14
|
|
3709
4068
|
}
|
|
3710
4069
|
});
|
|
3711
|
-
var nativeDriver15 = reactNative.Platform.OS !== "web";
|
|
3712
4070
|
function Pressable2({
|
|
3713
4071
|
children,
|
|
3714
4072
|
onPress,
|
|
3715
|
-
pressScale =
|
|
3716
|
-
bounciness = 4,
|
|
4073
|
+
pressScale = PRESS_SCALE.card,
|
|
3717
4074
|
haptics = true,
|
|
3718
4075
|
style,
|
|
3719
4076
|
disabled,
|
|
3720
4077
|
hoverScale = 1.02,
|
|
3721
4078
|
...touchableProps
|
|
3722
4079
|
}) {
|
|
3723
|
-
const
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
speed: 40,
|
|
3731
|
-
bounciness: 0
|
|
3732
|
-
}).start();
|
|
3733
|
-
};
|
|
3734
|
-
const handlePressOut = () => {
|
|
3735
|
-
if (disabled) return;
|
|
3736
|
-
reactNative.Animated.spring(scale2, {
|
|
3737
|
-
toValue: 1,
|
|
3738
|
-
useNativeDriver: nativeDriver15,
|
|
3739
|
-
speed: 40,
|
|
3740
|
-
bounciness
|
|
3741
|
-
}).start();
|
|
3742
|
-
};
|
|
4080
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
4081
|
+
pressScale,
|
|
4082
|
+
hoverScale,
|
|
4083
|
+
pressInSpring: SPRINGS.surfacePressIn,
|
|
4084
|
+
pressOutSpring: SPRINGS.surfacePressOut,
|
|
4085
|
+
disabled
|
|
4086
|
+
});
|
|
3743
4087
|
const handlePress = () => {
|
|
3744
4088
|
if (disabled || !onPress) return;
|
|
3745
4089
|
if (haptics) impactLight();
|
|
3746
4090
|
onPress();
|
|
3747
4091
|
};
|
|
3748
|
-
const hoverScaleValue = hovered && hoverScale !== 1 ? hoverScale : 1;
|
|
3749
4092
|
return /* @__PURE__ */ React26__default.default.createElement(
|
|
3750
|
-
|
|
4093
|
+
Animated9__default.default.View,
|
|
3751
4094
|
{
|
|
3752
|
-
style: [
|
|
3753
|
-
{ transform: [{ scale: reactNative.Animated.multiply(scale2, hoverScaleValue) }] },
|
|
3754
|
-
style
|
|
3755
|
-
],
|
|
4095
|
+
style: [animatedStyle, style],
|
|
3756
4096
|
...reactNative.Platform.OS === "web" ? hoverHandlers : {}
|
|
3757
4097
|
},
|
|
3758
4098
|
/* @__PURE__ */ React26__default.default.createElement(
|
|
3759
4099
|
reactNative.TouchableOpacity,
|
|
3760
4100
|
{
|
|
3761
4101
|
onPress: handlePress,
|
|
3762
|
-
onPressIn
|
|
3763
|
-
onPressOut
|
|
4102
|
+
onPressIn,
|
|
4103
|
+
onPressOut,
|
|
3764
4104
|
activeOpacity: 1,
|
|
3765
4105
|
disabled,
|
|
3766
4106
|
touchSoundDisabled: true,
|
|
4107
|
+
accessibilityRole: "button",
|
|
4108
|
+
accessibilityState: { disabled: !!disabled },
|
|
3767
4109
|
...touchableProps
|
|
3768
4110
|
},
|
|
3769
4111
|
children
|
|
@@ -3771,12 +4113,12 @@ function Pressable2({
|
|
|
3771
4113
|
);
|
|
3772
4114
|
}
|
|
3773
4115
|
var weightMap = {
|
|
3774
|
-
normal: "
|
|
3775
|
-
medium: "
|
|
3776
|
-
semibold: "
|
|
3777
|
-
bold: "
|
|
4116
|
+
normal: "Sohne-Regular",
|
|
4117
|
+
medium: "Sohne-Medium",
|
|
4118
|
+
semibold: "Sohne-SemiBold",
|
|
4119
|
+
bold: "Sohne-Bold"
|
|
3778
4120
|
};
|
|
3779
|
-
function
|
|
4121
|
+
function DetailRowBase({
|
|
3780
4122
|
label,
|
|
3781
4123
|
value,
|
|
3782
4124
|
separator = "dotted",
|
|
@@ -3802,23 +4144,24 @@ function DetailRow({
|
|
|
3802
4144
|
borderColor: "rgba(128,128,128,0.3)",
|
|
3803
4145
|
marginHorizontal: s(4)
|
|
3804
4146
|
};
|
|
3805
|
-
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [
|
|
4147
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles35.row, style] }, /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.labelSide }, resolvedLeftIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.icon }, resolvedLeftIcon) : null, typeof label === "string" ? /* @__PURE__ */ React26__default.default.createElement(
|
|
3806
4148
|
reactNative.Text,
|
|
3807
4149
|
{
|
|
3808
|
-
style: [
|
|
4150
|
+
style: [styles35.labelText, { color: colors.foregroundMuted, fontFamily: weightMap[labelWeight] }, labelStyle],
|
|
3809
4151
|
allowFontScaling: true
|
|
3810
4152
|
},
|
|
3811
4153
|
label
|
|
3812
|
-
) : label), separatorStyle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: separatorStyle }) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style:
|
|
4154
|
+
) : label), separatorStyle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: separatorStyle }) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.spacer }), /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.valueSide }, typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(
|
|
3813
4155
|
reactNative.Text,
|
|
3814
4156
|
{
|
|
3815
|
-
style: [
|
|
4157
|
+
style: [styles35.valueText, { color: valueColor ?? colors.foreground }, valueStyle],
|
|
3816
4158
|
allowFontScaling: true
|
|
3817
4159
|
},
|
|
3818
4160
|
value
|
|
3819
|
-
) : value, resolvedRightIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style:
|
|
4161
|
+
) : value, resolvedRightIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles35.icon }, resolvedRightIcon) : null));
|
|
3820
4162
|
}
|
|
3821
|
-
var
|
|
4163
|
+
var DetailRow = React26__default.default.memo(DetailRowBase);
|
|
4164
|
+
var styles35 = reactNative.StyleSheet.create({
|
|
3822
4165
|
row: {
|
|
3823
4166
|
flexDirection: "row",
|
|
3824
4167
|
alignItems: "center",
|
|
@@ -3848,11 +4191,101 @@ var styles33 = reactNative.StyleSheet.create({
|
|
|
3848
4191
|
flexShrink: 0
|
|
3849
4192
|
},
|
|
3850
4193
|
valueText: {
|
|
3851
|
-
fontFamily: "
|
|
4194
|
+
fontFamily: "Sohne-SemiBold",
|
|
3852
4195
|
fontSize: ms(13),
|
|
3853
4196
|
lineHeight: mvs(18)
|
|
3854
4197
|
}
|
|
3855
4198
|
});
|
|
4199
|
+
function Form({ children, style }) {
|
|
4200
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.form, style] }, children);
|
|
4201
|
+
}
|
|
4202
|
+
function FormField({
|
|
4203
|
+
children,
|
|
4204
|
+
label,
|
|
4205
|
+
error,
|
|
4206
|
+
required,
|
|
4207
|
+
style,
|
|
4208
|
+
labelStyle,
|
|
4209
|
+
errorStyle
|
|
4210
|
+
}) {
|
|
4211
|
+
const { colors } = useTheme();
|
|
4212
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.field, style] }, label ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.label, { color: colors.foreground }, labelStyle], allowFontScaling: true }, label, required ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: { color: colors.destructive } }, " *") : null) : null, children, error ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.error, { color: colors.destructive }, errorStyle], allowFontScaling: true }, error) : null);
|
|
4213
|
+
}
|
|
4214
|
+
function FormSection({ children, title, description, style }) {
|
|
4215
|
+
const { colors } = useTheme();
|
|
4216
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.section, style] }, title ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles36.sectionHeader }, /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.sectionTitle, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React26__default.default.createElement(reactNative.Text, { style: [styles36.sectionDescription, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null) : null, children);
|
|
4217
|
+
}
|
|
4218
|
+
function FormFooter({ children, style }) {
|
|
4219
|
+
return /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: [styles36.footer, style] }, children);
|
|
4220
|
+
}
|
|
4221
|
+
Form.Field = FormField;
|
|
4222
|
+
Form.Section = FormSection;
|
|
4223
|
+
Form.Footer = FormFooter;
|
|
4224
|
+
var styles36 = reactNative.StyleSheet.create({
|
|
4225
|
+
form: {
|
|
4226
|
+
gap: vs(16)
|
|
4227
|
+
},
|
|
4228
|
+
field: {
|
|
4229
|
+
gap: vs(6)
|
|
4230
|
+
},
|
|
4231
|
+
label: {
|
|
4232
|
+
fontFamily: "Sohne-Medium",
|
|
4233
|
+
fontSize: 14,
|
|
4234
|
+
lineHeight: 20
|
|
4235
|
+
},
|
|
4236
|
+
error: {
|
|
4237
|
+
fontFamily: "Sohne-Regular",
|
|
4238
|
+
fontSize: 12,
|
|
4239
|
+
lineHeight: 16
|
|
4240
|
+
},
|
|
4241
|
+
section: {
|
|
4242
|
+
gap: vs(16)
|
|
4243
|
+
},
|
|
4244
|
+
sectionHeader: {
|
|
4245
|
+
gap: vs(4)
|
|
4246
|
+
},
|
|
4247
|
+
sectionTitle: {
|
|
4248
|
+
fontFamily: "Sohne-SemiBold",
|
|
4249
|
+
fontSize: 16,
|
|
4250
|
+
lineHeight: 24
|
|
4251
|
+
},
|
|
4252
|
+
sectionDescription: {
|
|
4253
|
+
fontFamily: "Sohne-Regular",
|
|
4254
|
+
fontSize: 14,
|
|
4255
|
+
lineHeight: 20
|
|
4256
|
+
},
|
|
4257
|
+
footer: {
|
|
4258
|
+
flexDirection: "row",
|
|
4259
|
+
gap: s(12),
|
|
4260
|
+
paddingTop: vs(8)
|
|
4261
|
+
}
|
|
4262
|
+
});
|
|
4263
|
+
var defaultKeyExtractor = (item, index) => {
|
|
4264
|
+
const id = item?.id;
|
|
4265
|
+
return id !== void 0 ? String(id) : String(index);
|
|
4266
|
+
};
|
|
4267
|
+
function VirtualListInner({ itemHeight, keyExtractor, renderItem, ...props }, ref) {
|
|
4268
|
+
const getItemLayout = React26.useCallback(
|
|
4269
|
+
(_data, index) => ({
|
|
4270
|
+
length: itemHeight ?? 0,
|
|
4271
|
+
offset: (itemHeight ?? 0) * index,
|
|
4272
|
+
index
|
|
4273
|
+
}),
|
|
4274
|
+
[itemHeight]
|
|
4275
|
+
);
|
|
4276
|
+
return /* @__PURE__ */ React26__default.default.createElement(
|
|
4277
|
+
reactNative.FlatList,
|
|
4278
|
+
{
|
|
4279
|
+
ref,
|
|
4280
|
+
keyExtractor: keyExtractor ?? defaultKeyExtractor,
|
|
4281
|
+
renderItem,
|
|
4282
|
+
getItemLayout: itemHeight !== void 0 ? getItemLayout : void 0,
|
|
4283
|
+
removeClippedSubviews: true,
|
|
4284
|
+
...props
|
|
4285
|
+
}
|
|
4286
|
+
);
|
|
4287
|
+
}
|
|
4288
|
+
var VirtualList = React26__default.default.forwardRef(VirtualListInner);
|
|
3856
4289
|
|
|
3857
4290
|
// src/utils/typography.ts
|
|
3858
4291
|
function getResponsiveFontSize(text, maxSize, steps = [
|
|
@@ -3903,13 +4336,23 @@ exports.CurrencyInput = CurrencyInput;
|
|
|
3903
4336
|
exports.CurrencyInputLarge = CurrencyInput;
|
|
3904
4337
|
exports.DetailRow = DetailRow;
|
|
3905
4338
|
exports.EmptyState = EmptyState;
|
|
4339
|
+
exports.Form = Form;
|
|
4340
|
+
exports.FormField = FormField;
|
|
4341
|
+
exports.FormFooter = FormFooter;
|
|
4342
|
+
exports.FormSection = FormSection;
|
|
3906
4343
|
exports.ICON_SIZES = ICON_SIZES;
|
|
3907
4344
|
exports.Icon = Icon;
|
|
3908
4345
|
exports.IconButton = IconButton;
|
|
3909
4346
|
exports.Input = Input;
|
|
3910
4347
|
exports.LabelValue = LabelValue;
|
|
4348
|
+
exports.ListGroup = ListGroup;
|
|
4349
|
+
exports.ListGroupFooter = ListGroupFooter;
|
|
4350
|
+
exports.ListGroupHeader = ListGroupHeader;
|
|
3911
4351
|
exports.ListItem = ListItem;
|
|
3912
4352
|
exports.MediaCard = MediaCard;
|
|
4353
|
+
exports.MenuGroup = MenuGroup;
|
|
4354
|
+
exports.MenuGroupFooter = MenuGroupFooter;
|
|
4355
|
+
exports.MenuGroupHeader = MenuGroupHeader;
|
|
3913
4356
|
exports.MenuItem = MenuItem;
|
|
3914
4357
|
exports.MonthPicker = MonthPicker;
|
|
3915
4358
|
exports.Pressable = Pressable2;
|
|
@@ -3933,6 +4376,8 @@ exports.Textarea = Textarea;
|
|
|
3933
4376
|
exports.ThemeProvider = ThemeProvider;
|
|
3934
4377
|
exports.ToastProvider = ToastProvider;
|
|
3935
4378
|
exports.Toggle = Toggle;
|
|
4379
|
+
exports.VirtualList = VirtualList;
|
|
4380
|
+
exports.configureIconFamilies = configureIconFamilies;
|
|
3936
4381
|
exports.defaultDark = defaultDark;
|
|
3937
4382
|
exports.defaultLight = defaultLight;
|
|
3938
4383
|
exports.deriveColors = deriveColors;
|