@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/src/tokens.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// ─── Spacing ─────────────────────────────────────────────────────────────────
|
|
2
|
-
// 8pt grid with 2pt micro-step. `section` for major band separators (Airbnb: 64px).
|
|
3
2
|
export const SPACING = {
|
|
4
3
|
xxs: 2,
|
|
5
4
|
xs: 4,
|
|
@@ -22,8 +21,6 @@ export const ICON_SIZES = {
|
|
|
22
21
|
} as const
|
|
23
22
|
|
|
24
23
|
// ─── Border radius ────────────────────────────────────────────────────────────
|
|
25
|
-
// Airbnb-aligned shape language — soft everywhere, no hard corners on interactive elements.
|
|
26
|
-
// xs: micro chips/tags sm: inputs/forms md: cards lg: sheet corners xl: primary CTAs (pill)
|
|
27
24
|
export const RADIUS = {
|
|
28
25
|
none: 0,
|
|
29
26
|
xs: 4,
|
|
@@ -35,7 +32,6 @@ export const RADIUS = {
|
|
|
35
32
|
} as const
|
|
36
33
|
|
|
37
34
|
// ─── Shadows ──────────────────────────────────────────────────────────────────
|
|
38
|
-
// Multi-tier. Default card usage = sm. Hover float = md. Modals = lg/xl.
|
|
39
35
|
export const SHADOWS = {
|
|
40
36
|
sm: {
|
|
41
37
|
shadowColor: '#000',
|
|
@@ -73,118 +69,132 @@ export const BREAKPOINTS = {
|
|
|
73
69
|
} as const
|
|
74
70
|
|
|
75
71
|
// ─── Typography ───────────────────────────────────────────────────────────────
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
72
|
+
// AUDIT FIX: Rationalised display scale — removed weight inversions and size
|
|
73
|
+
// collisions. display-lg/md separated by 4px with matching weights. title-md/sm
|
|
74
|
+
// now actually differ in size. uppercase-tag raised from 10px → 11px for
|
|
75
|
+
// minimum mobile readability (Apple HIG: 11pt floor).
|
|
79
76
|
export const TYPOGRAPHY = {
|
|
80
77
|
'display-hero': {
|
|
81
|
-
fontFamily: '
|
|
78
|
+
fontFamily: 'Sohne-Bold',
|
|
82
79
|
fontSize: 64,
|
|
83
80
|
fontWeight: '700' as const,
|
|
84
81
|
lineHeight: 70,
|
|
85
82
|
letterSpacing: -1,
|
|
86
83
|
},
|
|
87
84
|
'display-xl': {
|
|
88
|
-
fontFamily: '
|
|
85
|
+
fontFamily: 'Sohne-Bold',
|
|
89
86
|
fontSize: 28,
|
|
90
87
|
fontWeight: '700' as const,
|
|
91
88
|
lineHeight: 40,
|
|
92
89
|
letterSpacing: 0,
|
|
93
90
|
},
|
|
91
|
+
// AUDIT FIX: was 22px/500 — raised to 24px/600; removes weight inversion vs display-md
|
|
94
92
|
'display-lg': {
|
|
95
|
-
fontFamily: '
|
|
96
|
-
fontSize:
|
|
97
|
-
fontWeight: '
|
|
98
|
-
lineHeight:
|
|
99
|
-
letterSpacing: -0.
|
|
93
|
+
fontFamily: 'Sohne-SemiBold',
|
|
94
|
+
fontSize: 24,
|
|
95
|
+
fontWeight: '600' as const,
|
|
96
|
+
lineHeight: 32,
|
|
97
|
+
letterSpacing: -0.3,
|
|
100
98
|
},
|
|
99
|
+
// AUDIT FIX: was 21px/700 — lowered to 20px/600; weight normalised, 4px gap preserved
|
|
101
100
|
'display-md': {
|
|
102
|
-
fontFamily: '
|
|
103
|
-
fontSize:
|
|
104
|
-
fontWeight: '
|
|
105
|
-
lineHeight:
|
|
101
|
+
fontFamily: 'Sohne-SemiBold',
|
|
102
|
+
fontSize: 20,
|
|
103
|
+
fontWeight: '600' as const,
|
|
104
|
+
lineHeight: 28,
|
|
106
105
|
letterSpacing: 0,
|
|
107
106
|
},
|
|
108
107
|
'display-sm': {
|
|
109
|
-
fontFamily: '
|
|
110
|
-
fontSize:
|
|
108
|
+
fontFamily: 'Sohne-SemiBold',
|
|
109
|
+
fontSize: 18,
|
|
111
110
|
fontWeight: '600' as const,
|
|
112
111
|
lineHeight: 24,
|
|
113
112
|
letterSpacing: -0.18,
|
|
114
113
|
},
|
|
114
|
+
// AUDIT FIX: was 16px — raised to 17px so title-md > title-sm is size-visible
|
|
115
115
|
'title-md': {
|
|
116
|
-
fontFamily: '
|
|
117
|
-
fontSize:
|
|
116
|
+
fontFamily: 'Sohne-SemiBold',
|
|
117
|
+
fontSize: 17,
|
|
118
118
|
fontWeight: '600' as const,
|
|
119
|
-
lineHeight:
|
|
119
|
+
lineHeight: 22,
|
|
120
120
|
letterSpacing: 0,
|
|
121
121
|
},
|
|
122
|
+
// AUDIT FIX: was 16px — lowered to 15px; now distinct from title-md
|
|
122
123
|
'title-sm': {
|
|
123
|
-
fontFamily: '
|
|
124
|
-
fontSize:
|
|
124
|
+
fontFamily: 'Sohne-Medium',
|
|
125
|
+
fontSize: 15,
|
|
125
126
|
fontWeight: '500' as const,
|
|
126
127
|
lineHeight: 20,
|
|
127
128
|
letterSpacing: 0,
|
|
128
129
|
},
|
|
129
130
|
'body-md': {
|
|
130
|
-
fontFamily: '
|
|
131
|
+
fontFamily: 'Sohne-Regular',
|
|
131
132
|
fontSize: 16,
|
|
132
133
|
fontWeight: '400' as const,
|
|
133
134
|
lineHeight: 24,
|
|
134
135
|
letterSpacing: 0,
|
|
135
136
|
},
|
|
136
137
|
'body-sm': {
|
|
137
|
-
fontFamily: '
|
|
138
|
+
fontFamily: 'Sohne-Regular',
|
|
138
139
|
fontSize: 14,
|
|
139
140
|
fontWeight: '400' as const,
|
|
140
141
|
lineHeight: 20,
|
|
141
142
|
letterSpacing: 0,
|
|
142
143
|
},
|
|
143
|
-
caption: {
|
|
144
|
-
fontFamily: '
|
|
144
|
+
'caption': {
|
|
145
|
+
fontFamily: 'Sohne-Medium',
|
|
145
146
|
fontSize: 14,
|
|
146
147
|
fontWeight: '500' as const,
|
|
147
148
|
lineHeight: 18,
|
|
148
149
|
letterSpacing: 0,
|
|
149
150
|
},
|
|
150
151
|
'caption-sm': {
|
|
151
|
-
fontFamily: '
|
|
152
|
+
fontFamily: 'Sohne-Regular',
|
|
152
153
|
fontSize: 13,
|
|
153
154
|
fontWeight: '400' as const,
|
|
154
155
|
lineHeight: 16,
|
|
155
156
|
letterSpacing: 0,
|
|
156
157
|
},
|
|
157
158
|
'badge-text': {
|
|
158
|
-
fontFamily: '
|
|
159
|
+
fontFamily: 'Sohne-SemiBold',
|
|
159
160
|
fontSize: 11,
|
|
160
161
|
fontWeight: '600' as const,
|
|
161
|
-
lineHeight:
|
|
162
|
+
lineHeight: 14,
|
|
163
|
+
letterSpacing: 0,
|
|
164
|
+
},
|
|
165
|
+
// AUDIT FIX: added badge-text-md so Badge md size has a canonical token
|
|
166
|
+
'badge-text-md': {
|
|
167
|
+
fontFamily: 'Sohne-SemiBold',
|
|
168
|
+
fontSize: 13,
|
|
169
|
+
fontWeight: '600' as const,
|
|
170
|
+
lineHeight: 16,
|
|
162
171
|
letterSpacing: 0,
|
|
163
172
|
},
|
|
164
173
|
'micro-label': {
|
|
165
|
-
fontFamily: '
|
|
174
|
+
fontFamily: 'Sohne-Bold',
|
|
166
175
|
fontSize: 12,
|
|
167
176
|
fontWeight: '700' as const,
|
|
168
177
|
lineHeight: 16,
|
|
169
178
|
letterSpacing: 0,
|
|
170
179
|
},
|
|
180
|
+
// AUDIT FIX: was 10px/0.8 letterSpacing — raised to 11px/0.6; minimum mobile readability
|
|
171
181
|
'uppercase-tag': {
|
|
172
|
-
fontFamily: '
|
|
173
|
-
fontSize:
|
|
182
|
+
fontFamily: 'Sohne-Bold',
|
|
183
|
+
fontSize: 11,
|
|
174
184
|
fontWeight: '700' as const,
|
|
175
|
-
lineHeight:
|
|
176
|
-
letterSpacing: 0.
|
|
185
|
+
lineHeight: 14,
|
|
186
|
+
letterSpacing: 0.6,
|
|
177
187
|
textTransform: 'uppercase' as const,
|
|
178
188
|
},
|
|
179
189
|
'button-lg': {
|
|
180
|
-
fontFamily: '
|
|
190
|
+
fontFamily: 'Sohne-Medium',
|
|
181
191
|
fontSize: 16,
|
|
182
192
|
fontWeight: '500' as const,
|
|
183
193
|
lineHeight: 22,
|
|
184
194
|
letterSpacing: 0,
|
|
185
195
|
},
|
|
186
196
|
'button-sm': {
|
|
187
|
-
fontFamily: '
|
|
197
|
+
fontFamily: 'Sohne-Medium',
|
|
188
198
|
fontSize: 14,
|
|
189
199
|
fontWeight: '500' as const,
|
|
190
200
|
lineHeight: 18,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Easing } from 'react-native-reanimated'
|
|
2
|
+
|
|
3
|
+
// ─── Spring presets ──────────────────────────────────────────────────────────
|
|
4
|
+
// Tuned for the "Apple HIG / Airbnb" press-feel: snap inward fast, settle out elastically.
|
|
5
|
+
// `stiffness`/`damping`/`mass` model — Reanimated v4 default physics units.
|
|
6
|
+
//
|
|
7
|
+
// pressIn: high stiffness, heavy damping → fast, controlled compression
|
|
8
|
+
// pressOut: lower stiffness, less damping → soft, elastic rebound
|
|
9
|
+
// settle: pillows / drawers / large surfaces → calm, never twitchy
|
|
10
|
+
export const SPRINGS = {
|
|
11
|
+
/** Tight, premium press feel — Buttons, Toggle, Tabs triggers. */
|
|
12
|
+
pressIn: { stiffness: 600, damping: 35, mass: 0.8 },
|
|
13
|
+
pressOut: { stiffness: 280, damping: 22, mass: 0.8 },
|
|
14
|
+
|
|
15
|
+
/** Slightly softer for larger surfaces — Card, ListItem, MenuItem. */
|
|
16
|
+
surfacePressIn: { stiffness: 380, damping: 30, mass: 0.95 },
|
|
17
|
+
surfacePressOut: { stiffness: 220, damping: 20, mass: 0.95 },
|
|
18
|
+
|
|
19
|
+
/** Settled transitions for moving indicators — Tabs pill, Switch thumb. */
|
|
20
|
+
glide: { stiffness: 380, damping: 38, mass: 1.0 },
|
|
21
|
+
|
|
22
|
+
/** Elastic indicator — Switch thumb, RadioGroup dot. */
|
|
23
|
+
elastic: { stiffness: 320, damping: 22, mass: 0.7 },
|
|
24
|
+
} as const
|
|
25
|
+
|
|
26
|
+
// ─── Timing presets ──────────────────────────────────────────────────────────
|
|
27
|
+
// All timings target the UI thread via Reanimated `withTiming`.
|
|
28
|
+
export const TIMINGS = {
|
|
29
|
+
/** Color/opacity transitions on toggles, checkboxes, switches. */
|
|
30
|
+
state: { duration: 160 },
|
|
31
|
+
/** Focus ring on inputs. */
|
|
32
|
+
focusIn: { duration: 140 },
|
|
33
|
+
focusOut: { duration: 100 },
|
|
34
|
+
/** Accordion / collapsible content. */
|
|
35
|
+
expand: { duration: 240 },
|
|
36
|
+
collapse: { duration: 200 },
|
|
37
|
+
/** Skeleton shimmer cycle (full pass). */
|
|
38
|
+
shimmer: { duration: 1400 },
|
|
39
|
+
} as const
|
|
40
|
+
|
|
41
|
+
// ─── Easing presets ──────────────────────────────────────────────────────────
|
|
42
|
+
export const EASINGS = {
|
|
43
|
+
/** Material-style ease-out — natural deceleration for state changes. */
|
|
44
|
+
standard: Easing.bezier(0.2, 0, 0, 1),
|
|
45
|
+
/** Strong ease-out for expanding surfaces (Accordion open). */
|
|
46
|
+
expand: Easing.bezier(0.23, 1, 0.32, 1),
|
|
47
|
+
/** Quick ease-in for collapsing. */
|
|
48
|
+
collapse: Easing.in(Easing.ease),
|
|
49
|
+
} as const
|
|
50
|
+
|
|
51
|
+
// ─── Press scale tokens ──────────────────────────────────────────────────────
|
|
52
|
+
// Per-component press intensities — taken from DESIGN.md.
|
|
53
|
+
export const PRESS_SCALE = {
|
|
54
|
+
button: 0.95,
|
|
55
|
+
card: 0.98,
|
|
56
|
+
row: 0.97,
|
|
57
|
+
chip: 0.94,
|
|
58
|
+
} as const
|
package/src/utils/icons.ts
CHANGED
|
@@ -17,36 +17,63 @@ export interface IconProps {
|
|
|
17
17
|
family?: IconFamily
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
type
|
|
20
|
+
type IconComponentType = React.ComponentType<{ name: string; size: number; color: string }>
|
|
21
|
+
type IconFamilyEntry = {
|
|
21
22
|
name: IconFamily
|
|
22
|
-
component:
|
|
23
|
-
glyphMap
|
|
23
|
+
component: IconComponentType
|
|
24
|
+
/** Deferred — glyphMap is only read when the resolution cache is first built. */
|
|
25
|
+
getGlyphMap: () => Record<string, number>
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{ name: '
|
|
28
|
+
type WithGlyphMap = { glyphMap?: Record<string, number> }
|
|
29
|
+
|
|
30
|
+
const glyphMapOf = (mod: unknown): Record<string, number> =>
|
|
31
|
+
(mod as WithGlyphMap).glyphMap ?? {}
|
|
32
|
+
|
|
33
|
+
// Priority order: highest-priority family LAST so it overwrites lower-priority entries in the cache.
|
|
34
|
+
const ALL_FAMILIES: IconFamilyEntry[] = [
|
|
35
|
+
{ name: 'Ionicons', component: Ionicons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Ionicons) },
|
|
36
|
+
{ name: 'MaterialIcons', component: MaterialIcons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(MaterialIcons) },
|
|
37
|
+
{ name: 'FontAwesome5', component: FontAwesome5 as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(FontAwesome5) },
|
|
38
|
+
{ name: 'Entypo', component: Entypo as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Entypo) },
|
|
39
|
+
{ name: 'AntDesign', component: AntDesign as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(AntDesign) },
|
|
40
|
+
{ name: 'Feather', component: Feather as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Feather) },
|
|
34
41
|
]
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
// Active families participating in name resolution. Defaults to all six.
|
|
44
|
+
let activeFamilies: IconFamilyEntry[] = ALL_FAMILIES
|
|
45
|
+
let resolvedCache: Map<string, IconFamilyEntry> | null = null
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Restrict which icon families participate in automatic name resolution.
|
|
49
|
+
* Narrowing to the families you actually use shrinks the resolution cache and
|
|
50
|
+
* speeds up the first `renderIcon` call (no scanning thousands of unused glyphs).
|
|
51
|
+
*
|
|
52
|
+
* Note: all six families are still statically imported by this module — Metro
|
|
53
|
+
* bundles them regardless. This controls *resolution scope*, not bundle size.
|
|
54
|
+
*
|
|
55
|
+
* @example configureIconFamilies(['Feather', 'MaterialIcons'])
|
|
56
|
+
*/
|
|
57
|
+
export function configureIconFamilies(families: IconFamily[]): void {
|
|
58
|
+
const order = families
|
|
59
|
+
.map((n) => ALL_FAMILIES.find((f) => f.name === n))
|
|
60
|
+
.filter((f): f is IconFamilyEntry => f !== undefined)
|
|
61
|
+
activeFamilies = order.length > 0 ? order : ALL_FAMILIES
|
|
62
|
+
resolvedCache = null // invalidate — rebuilt lazily on next resolve
|
|
63
|
+
}
|
|
37
64
|
|
|
38
|
-
function buildCache(): Map<string,
|
|
39
|
-
const cache = new Map<string,
|
|
40
|
-
for (const family of
|
|
41
|
-
|
|
42
|
-
for (const iconName of Object.keys(
|
|
65
|
+
function buildCache(): Map<string, IconFamilyEntry> {
|
|
66
|
+
const cache = new Map<string, IconFamilyEntry>()
|
|
67
|
+
for (const family of activeFamilies) {
|
|
68
|
+
const glyphMap = family.getGlyphMap()
|
|
69
|
+
for (const iconName of Object.keys(glyphMap)) {
|
|
43
70
|
cache.set(iconName, family)
|
|
44
71
|
}
|
|
45
72
|
}
|
|
46
73
|
return cache
|
|
47
74
|
}
|
|
48
75
|
|
|
49
|
-
function resolveFamily(name: string):
|
|
76
|
+
function resolveFamily(name: string): IconFamilyEntry | null {
|
|
50
77
|
if (!resolvedCache) {
|
|
51
78
|
resolvedCache = buildCache()
|
|
52
79
|
}
|
|
@@ -54,10 +81,10 @@ function resolveFamily(name: string): ResolvedFamily | null {
|
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
export function Icon({ name, size, color, family }: IconProps): React.ReactElement | null {
|
|
57
|
-
let resolved:
|
|
84
|
+
let resolved: IconFamilyEntry | null = null
|
|
58
85
|
|
|
59
86
|
if (family) {
|
|
60
|
-
resolved =
|
|
87
|
+
resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null
|
|
61
88
|
} else {
|
|
62
89
|
resolved = resolveFamily(name)
|
|
63
90
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
useSharedValue,
|
|
4
|
+
withTiming,
|
|
5
|
+
interpolateColor,
|
|
6
|
+
type SharedValue,
|
|
7
|
+
} from 'react-native-reanimated'
|
|
8
|
+
import { TIMINGS, EASINGS } from './animations'
|
|
9
|
+
|
|
10
|
+
export interface UseColorTransitionOptions {
|
|
11
|
+
/** Animation duration in ms. Defaults to `160`. */
|
|
12
|
+
duration?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Drives a 0→1 `SharedValue` based on a boolean state, animated via `withTiming` on the UI thread.
|
|
17
|
+
* Use with Reanimated's `interpolateColor` inside a `useAnimatedStyle` to drive borderColor/backgroundColor/etc.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const progress = useColorTransition(focused)
|
|
21
|
+
* const animatedStyle = useAnimatedStyle(() => ({
|
|
22
|
+
* borderColor: interpolateColor(progress.value, [0, 1], [colors.border, colors.primary]),
|
|
23
|
+
* }))
|
|
24
|
+
*/
|
|
25
|
+
export function useColorTransition(
|
|
26
|
+
active: boolean,
|
|
27
|
+
options: UseColorTransitionOptions = {},
|
|
28
|
+
): SharedValue<number> {
|
|
29
|
+
const { duration = TIMINGS.state.duration } = options
|
|
30
|
+
const progress = useSharedValue(active ? 1 : 0)
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
progress.value = withTiming(active ? 1 : 0, { duration, easing: EASINGS.standard })
|
|
34
|
+
}, [active, duration, progress])
|
|
35
|
+
|
|
36
|
+
return progress
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Re-export interpolateColor for ergonomic consumer access
|
|
40
|
+
export { interpolateColor }
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { Platform } from 'react-native'
|
|
3
|
+
import {
|
|
4
|
+
useSharedValue,
|
|
5
|
+
useAnimatedStyle,
|
|
6
|
+
withSpring,
|
|
7
|
+
} from 'react-native-reanimated'
|
|
8
|
+
import { SPRINGS, PRESS_SCALE } from './animations'
|
|
9
|
+
import { useHover } from './hover'
|
|
10
|
+
|
|
11
|
+
export interface SpringConfig {
|
|
12
|
+
stiffness?: number
|
|
13
|
+
damping?: number
|
|
14
|
+
mass?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface UsePressScaleOptions {
|
|
18
|
+
/** Scale value while pressed. Defaults to `0.95` (button). */
|
|
19
|
+
pressScale?: number
|
|
20
|
+
/** Scale value while hovered on web. Defaults to `1.02`. Set to `1` to disable. */
|
|
21
|
+
hoverScale?: number
|
|
22
|
+
/** Spring config for press-in. Defaults to `SPRINGS.pressIn`. */
|
|
23
|
+
pressInSpring?: SpringConfig
|
|
24
|
+
/** Spring config for press-out. Defaults to `SPRINGS.pressOut`. */
|
|
25
|
+
pressOutSpring?: SpringConfig
|
|
26
|
+
/** Disable all interaction animations (still returns stable handlers). */
|
|
27
|
+
disabled?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Unified press + hover scale primitive.
|
|
32
|
+
* All animation lives on the UI thread via Reanimated v4 worklets — zero JS-thread cost.
|
|
33
|
+
*
|
|
34
|
+
* Returns:
|
|
35
|
+
* - `animatedStyle`: spread onto an `Animated.View` (from `react-native-reanimated`)
|
|
36
|
+
* - `onPressIn` / `onPressOut`: bind to a `TouchableOpacity`
|
|
37
|
+
* - `hoverHandlers`: spread for web hover scaling (no-op on native)
|
|
38
|
+
*/
|
|
39
|
+
export function usePressScale({
|
|
40
|
+
pressScale = PRESS_SCALE.button,
|
|
41
|
+
hoverScale = 1.02,
|
|
42
|
+
pressInSpring = SPRINGS.pressIn,
|
|
43
|
+
pressOutSpring = SPRINGS.pressOut,
|
|
44
|
+
disabled = false,
|
|
45
|
+
}: UsePressScaleOptions = {}) {
|
|
46
|
+
const scale = useSharedValue(1)
|
|
47
|
+
const { hovered, hoverHandlers } = useHover()
|
|
48
|
+
|
|
49
|
+
const onPressIn = useCallback(() => {
|
|
50
|
+
if (disabled) return
|
|
51
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
52
|
+
scale.value = withSpring(pressScale, pressInSpring)
|
|
53
|
+
}, [disabled, pressScale, pressInSpring, scale])
|
|
54
|
+
|
|
55
|
+
const onPressOut = useCallback(() => {
|
|
56
|
+
if (disabled) return
|
|
57
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
58
|
+
scale.value = withSpring(1, pressOutSpring)
|
|
59
|
+
}, [disabled, pressOutSpring, scale])
|
|
60
|
+
|
|
61
|
+
const hoverActive = Platform.OS === 'web' && hovered && hoverScale !== 1 && !disabled
|
|
62
|
+
|
|
63
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
64
|
+
transform: [
|
|
65
|
+
{ scale: scale.value * (hoverActive ? hoverScale : 1) },
|
|
66
|
+
],
|
|
67
|
+
}))
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
animatedStyle,
|
|
71
|
+
onPressIn,
|
|
72
|
+
onPressOut,
|
|
73
|
+
hoverHandlers,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|