@retray-dev/ui-kit 10.2.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/COMPONENTS.md +287 -37
  2. package/README.md +11 -2
  3. package/dist/Accordion.mjs +2 -2
  4. package/dist/AlertBanner.mjs +2 -2
  5. package/dist/AppHeader.mjs +3 -3
  6. package/dist/Avatar.mjs +2 -2
  7. package/dist/Badge.mjs +2 -2
  8. package/dist/Button.mjs +2 -2
  9. package/dist/Card.mjs +2 -2
  10. package/dist/CategoryStrip.mjs +2 -2
  11. package/dist/Checkbox.mjs +2 -2
  12. package/dist/Chip.mjs +2 -2
  13. package/dist/ConfirmDialog.d.mts +1 -6
  14. package/dist/ConfirmDialog.d.ts +1 -6
  15. package/dist/ConfirmDialog.js +29 -23
  16. package/dist/ConfirmDialog.mjs +3 -3
  17. package/dist/CurrencyDisplay.mjs +2 -2
  18. package/dist/CurrencyInput.d.mts +3 -8
  19. package/dist/CurrencyInput.d.ts +3 -8
  20. package/dist/CurrencyInput.js +3 -1
  21. package/dist/CurrencyInput.mjs +3 -3
  22. package/dist/DetailRow.mjs +2 -2
  23. package/dist/EmptyState.mjs +3 -3
  24. package/dist/ErrorBoundary.mjs +2 -2
  25. package/dist/Form.mjs +2 -2
  26. package/dist/IconButton.mjs +2 -2
  27. package/dist/IconPicker.js +675 -248
  28. package/dist/IconPicker.mjs +3 -2
  29. package/dist/ImageUpload.mjs +3 -3
  30. package/dist/ImageViewer.mjs +4 -4
  31. package/dist/Input.mjs +2 -2
  32. package/dist/LabelValue.mjs +2 -2
  33. package/dist/ListGroup.mjs +2 -2
  34. package/dist/ListItem.d.mts +7 -7
  35. package/dist/ListItem.d.ts +7 -7
  36. package/dist/ListItem.js +12 -7
  37. package/dist/ListItem.mjs +2 -2
  38. package/dist/MediaCard.mjs +2 -2
  39. package/dist/MenuGroup.mjs +2 -2
  40. package/dist/MenuItem.mjs +2 -2
  41. package/dist/MonthPicker.mjs +2 -2
  42. package/dist/NumberStepper.mjs +2 -2
  43. package/dist/PagerDots.mjs +2 -2
  44. package/dist/Pressable.d.mts +15 -7
  45. package/dist/Pressable.d.ts +15 -7
  46. package/dist/Pressable.js +7 -3
  47. package/dist/Pressable.mjs +1 -1
  48. package/dist/PricingCard.mjs +4 -4
  49. package/dist/Progress.mjs +2 -2
  50. package/dist/RadioGroup.mjs +2 -2
  51. package/dist/RetrayProvider.mjs +3 -3
  52. package/dist/Select.mjs +2 -2
  53. package/dist/SelectableGrid.mjs +2 -2
  54. package/dist/Separator.mjs +2 -2
  55. package/dist/Sheet.d.mts +4 -46
  56. package/dist/Sheet.d.ts +4 -46
  57. package/dist/Sheet.js +46 -114
  58. package/dist/Sheet.mjs +2 -3
  59. package/dist/SheetSelect.mjs +2 -2
  60. package/dist/Skeleton.mjs +2 -2
  61. package/dist/Slider.mjs +2 -2
  62. package/dist/Spinner.mjs +2 -2
  63. package/dist/Stats.d.mts +30 -0
  64. package/dist/Stats.d.ts +30 -0
  65. package/dist/Stats.js +429 -0
  66. package/dist/Stats.mjs +9 -0
  67. package/dist/Switch.mjs +2 -2
  68. package/dist/TabBar.mjs +2 -2
  69. package/dist/Tabs.mjs +2 -2
  70. package/dist/Text.d.mts +3 -1
  71. package/dist/Text.d.ts +3 -1
  72. package/dist/Text.js +3 -3
  73. package/dist/Text.mjs +2 -2
  74. package/dist/Textarea.mjs +2 -2
  75. package/dist/Toast.mjs +2 -2
  76. package/dist/Toggle.mjs +2 -2
  77. package/dist/{chunk-YJ7I257J.mjs → chunk-265G6A46.mjs} +1 -1
  78. package/dist/{chunk-ELXBDILQ.mjs → chunk-2A2LEFZG.mjs} +2 -2
  79. package/dist/{chunk-ID72TK46.mjs → chunk-2CBQKU7H.mjs} +1 -1
  80. package/dist/{chunk-OB4JUQ3O.mjs → chunk-2I2AYECM.mjs} +1 -1
  81. package/dist/{chunk-WJLKJMKR.mjs → chunk-357YO24D.mjs} +4 -4
  82. package/dist/{chunk-GQYFLP3D.mjs → chunk-3GEYJ7I5.mjs} +1 -1
  83. package/dist/{chunk-AV4EMIRH.mjs → chunk-3N2M3WZL.mjs} +1 -1
  84. package/dist/{chunk-VF2ATYN3.mjs → chunk-3UYAZ7I4.mjs} +1 -1
  85. package/dist/{chunk-JMOZEC77.mjs → chunk-4WFMPFZB.mjs} +1 -1
  86. package/dist/chunk-5OLNXP3S.mjs +144 -0
  87. package/dist/{chunk-6SECQ2ZF.mjs → chunk-7HSILTC4.mjs} +2 -2
  88. package/dist/{chunk-IRRY3CRZ.mjs → chunk-AKM4EPOT.mjs} +1 -1
  89. package/dist/{chunk-IX3NYLYQ.mjs → chunk-AQEVCEXV.mjs} +1 -1
  90. package/dist/{chunk-WBOOUHSS.mjs → chunk-BCWEHE34.mjs} +1 -1
  91. package/dist/{chunk-AJ7ZDNBT.mjs → chunk-BOVUP27T.mjs} +1 -1
  92. package/dist/{chunk-BRKYVJVV.mjs → chunk-BQZE3HAW.mjs} +1 -1
  93. package/dist/{chunk-Z6SFHN6T.mjs → chunk-D3Y2T42P.mjs} +1 -1
  94. package/dist/{chunk-T2KCAHOS.mjs → chunk-DF6DU42P.mjs} +1 -1
  95. package/dist/{chunk-TB6SD2FT.mjs → chunk-DI7CBDL6.mjs} +1 -1
  96. package/dist/{chunk-HTHGSXFG.mjs → chunk-DOGIPOF5.mjs} +1 -1
  97. package/dist/{chunk-MBMXYJJV.mjs → chunk-E7NEHHXV.mjs} +7 -3
  98. package/dist/{chunk-MX6HRKMI.mjs → chunk-EFLFRAHD.mjs} +1 -1
  99. package/dist/{chunk-SOYNZDVY.mjs → chunk-EMUWGDWC.mjs} +6 -1
  100. package/dist/{chunk-AJRVDP2H.mjs → chunk-F4V6XLP4.mjs} +3 -3
  101. package/dist/{chunk-DYT7BG5I.mjs → chunk-FA2KMTH5.mjs} +1 -1
  102. package/dist/{chunk-Y2NS74WS.mjs → chunk-FFTYLPSB.mjs} +46 -98
  103. package/dist/{chunk-VKID2D2I.mjs → chunk-FUVYSVGR.mjs} +13 -8
  104. package/dist/{chunk-7LWRKMF5.mjs → chunk-FVTVCJAH.mjs} +1 -1
  105. package/dist/{chunk-TZDGAP5N.mjs → chunk-GK4VRMNE.mjs} +2 -2
  106. package/dist/{chunk-6Q64UFIA.mjs → chunk-HJ46DTJE.mjs} +1 -1
  107. package/dist/{chunk-WF2XDFRK.mjs → chunk-HLMPMUK2.mjs} +1 -1
  108. package/dist/{chunk-GD6KXMG5.mjs → chunk-I4V5XZPS.mjs} +1 -1
  109. package/dist/{chunk-TBNZHU6C.mjs → chunk-ISY26JQJ.mjs} +2 -2
  110. package/dist/{chunk-X4G6APW6.mjs → chunk-J6Q2YJEV.mjs} +1 -1
  111. package/dist/{chunk-WYEUNUTP.mjs → chunk-JCZQOY4O.mjs} +31 -24
  112. package/dist/{chunk-U2XJFYED.mjs → chunk-JNVAIDLK.mjs} +1 -1
  113. package/dist/{chunk-SOA2Z4RB.mjs → chunk-JULSIZDM.mjs} +1 -1
  114. package/dist/chunk-KHYX4IOM.mjs +1114 -0
  115. package/dist/{chunk-RYZC432S.mjs → chunk-LRM4AVYY.mjs} +1 -1
  116. package/dist/{chunk-6L4G6PBT.mjs → chunk-MYZ2EDYU.mjs} +1 -1
  117. package/dist/{chunk-BUMAMSTZ.mjs → chunk-N4ZPVCJH.mjs} +1 -1
  118. package/dist/{chunk-Z4VHZ7B5.mjs → chunk-NXI4YDZ2.mjs} +1 -1
  119. package/dist/{chunk-ZZ2R6KZ3.mjs → chunk-OULVKTWL.mjs} +1 -1
  120. package/dist/{chunk-FCSSQK3L.mjs → chunk-P64WHW4A.mjs} +1 -1
  121. package/dist/{chunk-KOO4WITD.mjs → chunk-P73V2EKS.mjs} +1 -1
  122. package/dist/{chunk-SXLKNTA4.mjs → chunk-PGERH3P7.mjs} +1 -1
  123. package/dist/{chunk-2UYENBLV.mjs → chunk-QSFV2P7O.mjs} +1 -1
  124. package/dist/{chunk-JT7HKXRB.mjs → chunk-S3KJCPEJ.mjs} +1 -1
  125. package/dist/{chunk-BEMIQXXU.mjs → chunk-V6NFJXKO.mjs} +1 -1
  126. package/dist/{chunk-A3A6KNQN.mjs → chunk-WOEWGSTU.mjs} +1 -1
  127. package/dist/{chunk-NMU5FMQJ.mjs → chunk-X26S5EVZ.mjs} +4 -2
  128. package/dist/{chunk-YFZ3ELX5.mjs → chunk-XBAGGKLW.mjs} +2 -2
  129. package/dist/{chunk-S2R7UVOE.mjs → chunk-ZHMSAYLT.mjs} +1 -1
  130. package/dist/fonts.d.mts +1 -7
  131. package/dist/fonts.d.ts +1 -7
  132. package/dist/fonts.js +0 -2
  133. package/dist/fonts.mjs +1 -2
  134. package/dist/index.d.mts +4 -1
  135. package/dist/index.d.ts +4 -1
  136. package/dist/index.js +1184 -708
  137. package/dist/index.mjs +53 -52
  138. package/package.json +3 -3
  139. package/src/components/ConfirmDialog/ConfirmDialog.tsx +39 -30
  140. package/src/components/CurrencyInput/CurrencyInput.tsx +4 -7
  141. package/src/components/IconPicker/IconPicker.tsx +124 -112
  142. package/src/components/ListItem/ListItem.tsx +43 -28
  143. package/src/components/Pressable/Pressable.tsx +20 -8
  144. package/src/components/Sheet/Sheet.tsx +64 -172
  145. package/src/components/Stats/Stats.tsx +226 -0
  146. package/src/components/Stats/index.ts +2 -0
  147. package/src/components/Text/Text.tsx +4 -2
  148. package/src/fonts.ts +0 -7
  149. package/src/index.ts +4 -0
  150. package/src/theme/colorUtils.ts +9 -0
  151. package/src/utils/curatedIcons.ts +698 -135
  152. package/src/utils/fontGuard.ts +2 -1
  153. package/dist/chunk-53Z3NYGE.mjs +0 -742
@@ -0,0 +1,226 @@
1
+ import React, { useState, useCallback } from 'react'
2
+ import { View, Text, StyleSheet, ViewStyle, LayoutChangeEvent } from 'react-native'
3
+ import { impactLight } from '../../utils/haptics'
4
+ import { useTheme } from '../../theme'
5
+ import { s, vs, ms, mvs } from '../../utils/scaling'
6
+ import { RADIUS } from '../../tokens'
7
+ import { renderIcon } from '../../utils/icons'
8
+ import { PressableCard } from '../../utils/pressable'
9
+
10
+ export type StatsVariant = 'elevated' | 'outlined' | 'filled'
11
+
12
+ export interface StatsProps {
13
+ value: string
14
+ label: string
15
+ description?: string
16
+ icon?: React.ReactNode
17
+ iconName?: string
18
+ iconColor?: string
19
+ variant?: StatsVariant
20
+ onPress?: () => void
21
+ style?: ViewStyle
22
+ accessibilityLabel?: string
23
+ }
24
+
25
+ export interface StatsGroupProps {
26
+ children: React.ReactNode
27
+ gap?: number
28
+ style?: ViewStyle
29
+ }
30
+
31
+ const COMPACT_THRESHOLD = s(150)
32
+
33
+ function StatsComponent({
34
+ value,
35
+ label,
36
+ description,
37
+ icon,
38
+ iconName,
39
+ iconColor,
40
+ variant = 'elevated',
41
+ onPress,
42
+ style,
43
+ accessibilityLabel,
44
+ }: StatsProps) {
45
+ const { colors } = useTheme()
46
+ const [containerWidth, setContainerWidth] = useState(0)
47
+
48
+ const handleLayout = useCallback((e: LayoutChangeEvent) => {
49
+ const w = e.nativeEvent.layout.width
50
+ if (w > 0 && w !== containerWidth) {
51
+ setContainerWidth(w)
52
+ }
53
+ }, [containerWidth])
54
+
55
+ const handlePress = () => {
56
+ if (!onPress) return
57
+ impactLight()
58
+ onPress()
59
+ }
60
+
61
+ const isCompact = containerWidth > 0 && containerWidth < COMPACT_THRESHOLD && !!(icon ?? iconName)
62
+
63
+ const variantStyle: ViewStyle = {
64
+ elevated: {
65
+ backgroundColor: colors.card,
66
+ borderWidth: 0,
67
+ shadowColor: '#000',
68
+ shadowOffset: { width: 0, height: 4 },
69
+ shadowOpacity: 0.09,
70
+ shadowRadius: 14,
71
+ elevation: 4,
72
+ },
73
+ outlined: {
74
+ backgroundColor: colors.card,
75
+ borderColor: colors.border,
76
+ shadowOpacity: 0,
77
+ elevation: 0,
78
+ },
79
+ filled: {
80
+ backgroundColor: colors.surfaceStrong,
81
+ borderColor: colors.border,
82
+ shadowOpacity: 0,
83
+ elevation: 0,
84
+ },
85
+ }[variant]
86
+
87
+ const iconColorResolved = iconColor ?? colors.primary
88
+
89
+ const resolvedIcon = iconName ? renderIcon(iconName, ms(22), iconColorResolved) : icon
90
+
91
+ const iconElement = resolvedIcon ? (
92
+ <View style={styles.iconWrapper}>{resolvedIcon}</View>
93
+ ) : null
94
+
95
+ const valueElement = (
96
+ <Text style={[styles.value, { color: colors.foreground }]} allowFontScaling={true}>
97
+ {value}
98
+ </Text>
99
+ )
100
+
101
+ const cardContent = (
102
+ <View style={[styles.card, variantStyle, style]} onLayout={handleLayout}>
103
+ {isCompact ? (
104
+ <>
105
+ {iconElement}
106
+ <View style={styles.compactValue}>{valueElement}</View>
107
+ <Text style={[styles.label, { color: colors.foregroundSubtle }]} allowFontScaling={true}>
108
+ {label}
109
+ </Text>
110
+ {description ? (
111
+ <Text style={[styles.description, { color: colors.foregroundMuted }]} allowFontScaling={true}>
112
+ {description}
113
+ </Text>
114
+ ) : null}
115
+ </>
116
+ ) : (
117
+ <>
118
+ <View style={styles.valueRow}>
119
+ {iconElement}
120
+ {valueElement}
121
+ </View>
122
+ <Text style={[styles.label, { color: colors.foregroundSubtle }]} allowFontScaling={true}>
123
+ {label}
124
+ </Text>
125
+ {description ? (
126
+ <Text style={[styles.description, { color: colors.foregroundMuted }]} allowFontScaling={true}>
127
+ {description}
128
+ </Text>
129
+ ) : null}
130
+ </>
131
+ )}
132
+ </View>
133
+ )
134
+
135
+ if (onPress) {
136
+ return (
137
+ <PressableCard
138
+ onPress={handlePress}
139
+ rippleColor="transparent"
140
+ touchSoundDisabled
141
+ activateOnHover
142
+ accessibilityRole="button"
143
+ accessibilityLabel={accessibilityLabel}
144
+ >
145
+ {cardContent}
146
+ </PressableCard>
147
+ )
148
+ }
149
+
150
+ return cardContent
151
+ }
152
+
153
+ function StatsGroup({ children, gap = s(12), style }: StatsGroupProps) {
154
+ return (
155
+ <View style={[styles.group, { gap }, style]}>
156
+ {React.Children.map(children, (child) => {
157
+ if (!React.isValidElement(child)) return child
158
+ const childStyle = (child.props as { style?: ViewStyle }).style
159
+ const mergedStyle = childStyle
160
+ ? [childStyle, { alignSelf: 'stretch' as const }]
161
+ : [{ alignSelf: 'stretch' as const }]
162
+ return (
163
+ <View style={styles.groupItem}>
164
+ {React.cloneElement(
165
+ child as React.ReactElement<{ style?: ViewStyle }>,
166
+ { style: mergedStyle as unknown as ViewStyle },
167
+ )}
168
+ </View>
169
+ )
170
+ })}
171
+ </View>
172
+ )
173
+ }
174
+
175
+ export const Stats = Object.assign(React.memo(StatsComponent), { Group: StatsGroup })
176
+
177
+ const styles = StyleSheet.create({
178
+ card: {
179
+ borderRadius: RADIUS.md,
180
+ borderWidth: 1,
181
+ padding: s(16),
182
+ alignSelf: 'flex-start',
183
+ alignItems: 'center',
184
+ justifyContent: 'center',
185
+ },
186
+ valueRow: {
187
+ flexDirection: 'row',
188
+ alignItems: 'center',
189
+ justifyContent: 'center',
190
+ gap: s(8),
191
+ },
192
+ iconWrapper: {
193
+ alignItems: 'center',
194
+ justifyContent: 'center',
195
+ },
196
+ compactValue: {
197
+ marginTop: vs(8),
198
+ },
199
+ value: {
200
+ fontFamily: 'Sohne-Bold',
201
+ fontSize: ms(28),
202
+ lineHeight: mvs(32),
203
+ textAlign: 'center',
204
+ },
205
+ label: {
206
+ fontFamily: 'Sohne-Regular',
207
+ fontSize: ms(13),
208
+ lineHeight: mvs(18),
209
+ marginTop: vs(8),
210
+ textAlign: 'center',
211
+ },
212
+ description: {
213
+ fontFamily: 'Sohne-Regular',
214
+ fontSize: ms(12),
215
+ lineHeight: mvs(16),
216
+ marginTop: vs(4),
217
+ textAlign: 'center',
218
+ },
219
+ group: {
220
+ flexDirection: 'row',
221
+ width: '100%',
222
+ },
223
+ groupItem: {
224
+ flex: 1,
225
+ },
226
+ })
@@ -0,0 +1,2 @@
1
+ export { Stats } from './Stats'
2
+ export type { StatsProps, StatsVariant, StatsGroupProps } from './Stats'
@@ -26,6 +26,8 @@ export type TextVariant =
26
26
  export interface TextProps extends RNTextProps {
27
27
  variant?: TextVariant
28
28
  color?: string
29
+ /** Force uppercase text transformation. Useful for labels, headers, and buttons. */
30
+ uppercase?: boolean
29
31
  }
30
32
 
31
33
  // Apply scaling to font/line-height values while preserving all other token props
@@ -68,7 +70,7 @@ const defaultColorVariant: Partial<Record<TextVariant, 'foreground' | 'foregroun
68
70
  'button-sm': 'foreground',
69
71
  }
70
72
 
71
- function TextBase({ variant = 'body-md', color, style, children, ...props }: TextProps) {
73
+ function TextBase({ variant = 'body-md', color, style, uppercase, children, ...props }: TextProps) {
72
74
  warnIfFontsMissing()
73
75
  const { colors } = useTheme()
74
76
 
@@ -77,7 +79,7 @@ function TextBase({ variant = 'body-md', color, style, children, ...props }: Tex
77
79
 
78
80
  return (
79
81
  <RNText
80
- style={[variantStyles[variant], { color: resolvedColor }, style]}
82
+ style={[variantStyles[variant], { color: resolvedColor }, uppercase && { textTransform: 'uppercase' }, style]}
81
83
  allowFontScaling={true}
82
84
  {...props}
83
85
  >
package/src/fonts.ts CHANGED
@@ -63,10 +63,3 @@ export const SohneFontNames = [
63
63
 
64
64
  /** Type for any valid Sohne font family name */
65
65
  export type SohneFontName = (typeof SohneFontNames)[number]
66
-
67
- /**
68
- * @deprecated SohneFonts export removed in v10.0.0.
69
- * Metro cannot resolve require() calls from node_modules reliably.
70
- * Copy the static SohneFonts boilerplate from CONSUMER.md into your App.tsx instead.
71
- */
72
- export const SohneFonts = undefined
package/src/index.ts CHANGED
@@ -57,6 +57,7 @@ export * from './components/SheetSelect'
57
57
  export * from './components/ImageUpload'
58
58
  export * from './components/IconPicker'
59
59
  export * from './components/NumberStepper'
60
+ export * from './components/Stats'
60
61
  // HolographicCard is intentionally NOT re-exported here — it depends on the
61
62
  // optional peer @shopify/react-native-skia, so it must stay out of the main
62
63
  // barrel's module graph. Deep-import it: '@retray-dev/ui-kit/HolographicCard'.
@@ -64,6 +65,9 @@ export * from './components/NumberStepper'
64
65
  // Icon utility
65
66
  export { Icon, renderIcon, configureIconFamilies, getValidIconNames } from './utils/icons'
66
67
 
68
+ // Color utilities
69
+ export { withAlpha } from './theme/colorUtils'
70
+
67
71
  // Typography utilities
68
72
  export { getResponsiveFontSize } from './utils/typography'
69
73
  export type { IconProps, IconFamily } from './utils/icons'
@@ -78,3 +78,12 @@ export function isDark(hex: string): boolean {
78
78
  const L = 0.2126 * toLinear(rgb.r) + 0.7152 * toLinear(rgb.g) + 0.0722 * toLinear(rgb.b)
79
79
  return L < 0.5
80
80
  }
81
+
82
+ // Convert a hex color to rgba with the given alpha.
83
+ // Returns an rgba() string suitable for use with semi-transparent backgrounds,
84
+ // borders, and overlays.
85
+ export function withAlpha(hex: string, alpha: number): string {
86
+ const rgb = hexToRgb(hex)
87
+ if (!rgb) return hex
88
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`
89
+ }