@retray-dev/ui-kit 12.1.0 → 12.2.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 (190) hide show
  1. package/COMPONENTS.md +98 -4
  2. package/README.md +4 -4
  3. package/dist/Accordion.d.mts +6 -0
  4. package/dist/Accordion.d.ts +6 -0
  5. package/dist/Accordion.js +16 -0
  6. package/dist/Accordion.mjs +2 -2
  7. package/dist/AlertBanner.js +2 -0
  8. package/dist/AlertBanner.mjs +2 -2
  9. package/dist/AppHeader.js +2 -0
  10. package/dist/AppHeader.mjs +3 -3
  11. package/dist/Avatar.js +2 -0
  12. package/dist/Avatar.mjs +2 -2
  13. package/dist/Badge.js +2 -0
  14. package/dist/Badge.mjs +2 -2
  15. package/dist/Button.js +17 -17
  16. package/dist/Button.mjs +2 -2
  17. package/dist/Card.js +2 -0
  18. package/dist/Card.mjs +2 -2
  19. package/dist/CategoryStrip.js +2 -0
  20. package/dist/CategoryStrip.mjs +2 -2
  21. package/dist/Checkbox.js +2 -0
  22. package/dist/Checkbox.mjs +2 -2
  23. package/dist/Chip.js +2 -0
  24. package/dist/Chip.mjs +2 -2
  25. package/dist/ConfirmDialog.js +26 -20
  26. package/dist/ConfirmDialog.mjs +3 -3
  27. package/dist/CurrencyDisplay.js +2 -0
  28. package/dist/CurrencyDisplay.mjs +2 -2
  29. package/dist/CurrencyInput.js +2 -0
  30. package/dist/CurrencyInput.mjs +3 -3
  31. package/dist/DetailRow.js +2 -0
  32. package/dist/DetailRow.mjs +2 -2
  33. package/dist/EmptyState.js +17 -17
  34. package/dist/EmptyState.mjs +3 -3
  35. package/dist/ErrorBoundary.js +2 -0
  36. package/dist/ErrorBoundary.mjs +2 -2
  37. package/dist/Form.js +2 -0
  38. package/dist/Form.mjs +2 -2
  39. package/dist/IconButton.js +2 -0
  40. package/dist/IconButton.mjs +2 -2
  41. package/dist/IconPicker.js +2 -0
  42. package/dist/IconPicker.mjs +3 -3
  43. package/dist/ImageUpload.d.mts +3 -1
  44. package/dist/ImageUpload.d.ts +3 -1
  45. package/dist/ImageUpload.js +10 -3
  46. package/dist/ImageUpload.mjs +3 -3
  47. package/dist/ImageViewer.js +2 -0
  48. package/dist/ImageViewer.mjs +4 -4
  49. package/dist/Input.js +2 -0
  50. package/dist/Input.mjs +2 -2
  51. package/dist/LabelValue.js +2 -0
  52. package/dist/LabelValue.mjs +2 -2
  53. package/dist/ListGroup.js +2 -0
  54. package/dist/ListGroup.mjs +2 -2
  55. package/dist/ListItem.js +2 -0
  56. package/dist/ListItem.mjs +2 -2
  57. package/dist/MediaCard.js +2 -0
  58. package/dist/MediaCard.mjs +2 -2
  59. package/dist/MenuGroup.js +2 -0
  60. package/dist/MenuGroup.mjs +2 -2
  61. package/dist/MenuItem.js +2 -0
  62. package/dist/MenuItem.mjs +2 -2
  63. package/dist/MonthPicker.js +2 -0
  64. package/dist/MonthPicker.mjs +2 -2
  65. package/dist/NumberStepper.js +2 -0
  66. package/dist/NumberStepper.mjs +2 -2
  67. package/dist/PagerDots.js +2 -0
  68. package/dist/PagerDots.mjs +2 -2
  69. package/dist/PricingCard.js +17 -17
  70. package/dist/PricingCard.mjs +4 -4
  71. package/dist/Progress.js +2 -0
  72. package/dist/Progress.mjs +2 -2
  73. package/dist/RadioGroup.js +2 -0
  74. package/dist/RadioGroup.mjs +2 -2
  75. package/dist/RetrayProvider.d.mts +1 -1
  76. package/dist/RetrayProvider.d.ts +1 -1
  77. package/dist/RetrayProvider.js +2 -0
  78. package/dist/RetrayProvider.mjs +3 -3
  79. package/dist/Select.js +2 -0
  80. package/dist/Select.mjs +2 -2
  81. package/dist/SelectableCard.d.mts +27 -0
  82. package/dist/SelectableCard.d.ts +27 -0
  83. package/dist/SelectableCard.js +511 -0
  84. package/dist/SelectableCard.mjs +8 -0
  85. package/dist/SelectableGrid.js +2 -0
  86. package/dist/SelectableGrid.mjs +2 -2
  87. package/dist/Separator.js +2 -0
  88. package/dist/Separator.mjs +2 -2
  89. package/dist/Sheet.js +11 -3
  90. package/dist/Sheet.mjs +2 -2
  91. package/dist/SheetSelect.js +2 -0
  92. package/dist/SheetSelect.mjs +2 -2
  93. package/dist/Skeleton.d.mts +3 -1
  94. package/dist/Skeleton.d.ts +3 -1
  95. package/dist/Skeleton.js +5 -2
  96. package/dist/Skeleton.mjs +2 -2
  97. package/dist/Slider.js +2 -0
  98. package/dist/Slider.mjs +2 -2
  99. package/dist/Spinner.js +2 -0
  100. package/dist/Spinner.mjs +2 -2
  101. package/dist/Stats.d.mts +4 -1
  102. package/dist/Stats.d.ts +4 -1
  103. package/dist/Stats.js +27 -3
  104. package/dist/Stats.mjs +2 -2
  105. package/dist/Switch.js +2 -0
  106. package/dist/Switch.mjs +2 -2
  107. package/dist/TabBar.js +2 -0
  108. package/dist/TabBar.mjs +2 -2
  109. package/dist/Tabs.js +2 -0
  110. package/dist/Tabs.mjs +2 -2
  111. package/dist/Text.js +2 -0
  112. package/dist/Text.mjs +2 -2
  113. package/dist/Textarea.js +2 -0
  114. package/dist/Textarea.mjs +2 -2
  115. package/dist/Toast.js +2 -0
  116. package/dist/Toast.mjs +2 -2
  117. package/dist/Toggle.js +2 -0
  118. package/dist/Toggle.mjs +2 -2
  119. package/dist/{chunk-JNVAIDLK.mjs → chunk-2BA3JMKK.mjs} +1 -1
  120. package/dist/{chunk-X26S5EVZ.mjs → chunk-2HFD4IHU.mjs} +1 -1
  121. package/dist/{chunk-ZHMSAYLT.mjs → chunk-2LG326TT.mjs} +1 -1
  122. package/dist/chunk-2P2CB235.mjs +236 -0
  123. package/dist/{chunk-MYZ2EDYU.mjs → chunk-3XCFYSX4.mjs} +1 -1
  124. package/dist/{chunk-DOGIPOF5.mjs → chunk-4J2PXL36.mjs} +16 -18
  125. package/dist/{chunk-V6NFJXKO.mjs → chunk-4OORJ2DY.mjs} +1 -1
  126. package/dist/{chunk-5OLNXP3S.mjs → chunk-4XOB5TTD.mjs} +26 -4
  127. package/dist/{chunk-P64WHW4A.mjs → chunk-57V2LXCK.mjs} +1 -1
  128. package/dist/{chunk-HJ46DTJE.mjs → chunk-7AFZWSCI.mjs} +1 -1
  129. package/dist/{chunk-AQEVCEXV.mjs → chunk-7ELGZ66G.mjs} +1 -1
  130. package/dist/{chunk-I4V5XZPS.mjs → chunk-AENAVIKT.mjs} +1 -1
  131. package/dist/{chunk-2CBQKU7H.mjs → chunk-BXF4AMHY.mjs} +1 -1
  132. package/dist/{chunk-JULSIZDM.mjs → chunk-C43HRKXH.mjs} +1 -1
  133. package/dist/{chunk-GK4VRMNE.mjs → chunk-CF27NBXO.mjs} +11 -6
  134. package/dist/{chunk-PGERH3P7.mjs → chunk-DF7JA72E.mjs} +1 -1
  135. package/dist/{chunk-F4V6XLP4.mjs → chunk-E5UKLSJZ.mjs} +3 -3
  136. package/dist/{chunk-FUVYSVGR.mjs → chunk-EDLCGYIO.mjs} +1 -1
  137. package/dist/{chunk-N4ZPVCJH.mjs → chunk-ELGEOM7I.mjs} +1 -1
  138. package/dist/{chunk-FA2KMTH5.mjs → chunk-F3YTWO3T.mjs} +1 -1
  139. package/dist/{chunk-3UYAZ7I4.mjs → chunk-GH67YXG6.mjs} +1 -1
  140. package/dist/{chunk-357YO24D.mjs → chunk-GUTDFUNF.mjs} +1 -1
  141. package/dist/{chunk-7HSILTC4.mjs → chunk-HC4VVCWY.mjs} +2 -2
  142. package/dist/{chunk-WOEWGSTU.mjs → chunk-HEDQPK4I.mjs} +1 -1
  143. package/dist/{chunk-3GEYJ7I5.mjs → chunk-IVSRW4HS.mjs} +1 -1
  144. package/dist/{chunk-P73V2EKS.mjs → chunk-KSUWPU2F.mjs} +1 -1
  145. package/dist/{chunk-BCWEHE34.mjs → chunk-LIS6I5UP.mjs} +1 -1
  146. package/dist/{chunk-J6Q2YJEV.mjs → chunk-LNPKGWBG.mjs} +1 -1
  147. package/dist/{chunk-DF6DU42P.mjs → chunk-LOBLCFMN.mjs} +1 -1
  148. package/dist/{chunk-2A2LEFZG.mjs → chunk-LPV4NJJK.mjs} +2 -2
  149. package/dist/{chunk-FFTYLPSB.mjs → chunk-M3C7XM2M.mjs} +11 -5
  150. package/dist/{chunk-BQZE3HAW.mjs → chunk-MEPSKGBO.mjs} +1 -1
  151. package/dist/{chunk-ISY26JQJ.mjs → chunk-MVMGPZN6.mjs} +2 -2
  152. package/dist/{chunk-265G6A46.mjs → chunk-NHDI3VQB.mjs} +15 -1
  153. package/dist/{chunk-D3Y2T42P.mjs → chunk-NJG7DHVF.mjs} +1 -1
  154. package/dist/{chunk-LRM4AVYY.mjs → chunk-NLZY4TXU.mjs} +1 -1
  155. package/dist/{chunk-OULVKTWL.mjs → chunk-OLVJFKXS.mjs} +1 -1
  156. package/dist/{chunk-BOVUP27T.mjs → chunk-QDAZGZUF.mjs} +4 -3
  157. package/dist/{chunk-S3KJCPEJ.mjs → chunk-QOLWA2PW.mjs} +1 -1
  158. package/dist/{chunk-JCZQOY4O.mjs → chunk-QXDGGOLC.mjs} +12 -6
  159. package/dist/{chunk-4WFMPFZB.mjs → chunk-RJNLAH76.mjs} +1 -1
  160. package/dist/{chunk-HLMPMUK2.mjs → chunk-RMRS44MQ.mjs} +1 -1
  161. package/dist/{chunk-KHYX4IOM.mjs → chunk-SAWUXP3A.mjs} +2 -2
  162. package/dist/{chunk-2I2AYECM.mjs → chunk-TS7DGUIR.mjs} +1 -1
  163. package/dist/{chunk-3N2M3WZL.mjs → chunk-UBUXUMER.mjs} +1 -1
  164. package/dist/{chunk-AKM4EPOT.mjs → chunk-ULGNQPNE.mjs} +1 -1
  165. package/dist/{chunk-FVTVCJAH.mjs → chunk-UNNRUJTM.mjs} +1 -1
  166. package/dist/{chunk-DI7CBDL6.mjs → chunk-UQ4742ET.mjs} +1 -1
  167. package/dist/{chunk-EFLFRAHD.mjs → chunk-VJBUCITV.mjs} +1 -1
  168. package/dist/{chunk-QSFV2P7O.mjs → chunk-YMYIEVZP.mjs} +1 -1
  169. package/dist/{chunk-EMUWGDWC.mjs → chunk-YTXRIXNZ.mjs} +2 -0
  170. package/dist/{chunk-XBAGGKLW.mjs → chunk-ZIMY2QUM.mjs} +2 -2
  171. package/dist/{chunk-NXI4YDZ2.mjs → chunk-ZR6HSEAB.mjs} +1 -1
  172. package/dist/{index-wt-orHUi.d.ts → index-CY34hxPN.d.mts} +1 -0
  173. package/dist/{index-wt-orHUi.d.mts → index-CY34hxPN.d.ts} +1 -0
  174. package/dist/index.d.mts +3 -2
  175. package/dist/index.d.ts +3 -2
  176. package/dist/index.js +733 -453
  177. package/dist/index.mjs +53 -52
  178. package/package.json +1 -1
  179. package/src/components/Accordion/Accordion.tsx +20 -0
  180. package/src/components/Button/Button.tsx +29 -26
  181. package/src/components/ConfirmDialog/ConfirmDialog.tsx +10 -3
  182. package/src/components/ImageUpload/ImageUpload.tsx +10 -3
  183. package/src/components/SelectableCard/SelectableCard.tsx +304 -0
  184. package/src/components/SelectableCard/index.ts +1 -0
  185. package/src/components/Sheet/Sheet.tsx +10 -3
  186. package/src/components/Skeleton/Skeleton.tsx +5 -2
  187. package/src/components/Stats/Stats.tsx +35 -7
  188. package/src/index.ts +1 -0
  189. package/src/theme/colors.ts +7 -0
  190. package/src/theme/types.ts +4 -1
@@ -99,14 +99,21 @@ export function Sheet({
99
99
  const insets = useSafeAreaInsets()
100
100
  const ref = useRef<BottomSheetModal>(null)
101
101
  const wasOpened = useRef(false)
102
+ const isPresentedRef = useRef(false)
102
103
  const name = useId()
103
104
 
105
+ const handleDismiss = useCallback(() => {
106
+ isPresentedRef.current = false
107
+ onClose?.()
108
+ }, [onClose])
109
+
104
110
  useEffect(() => {
105
- if (open) {
111
+ if (open && !isPresentedRef.current) {
106
112
  impactMedium()
107
113
  ref.current?.present()
108
114
  wasOpened.current = true
109
- } else if (wasOpened.current) {
115
+ isPresentedRef.current = true
116
+ } else if (!open && wasOpened.current && isPresentedRef.current) {
110
117
  ref.current?.dismiss()
111
118
  }
112
119
  }, [open])
@@ -188,7 +195,7 @@ export function Sheet({
188
195
  <BottomSheetModal
189
196
  ref={ref}
190
197
  name={name}
191
- onDismiss={onClose}
198
+ onDismiss={handleDismiss}
192
199
  enableDynamicSizing={useDynamicSizing}
193
200
  snapPoints={snapPoints}
194
201
  maxDynamicContentSize={useDynamicSizing && maxHeight ? maxHeight : undefined}
@@ -24,6 +24,8 @@ export interface SkeletonProps {
24
24
  preset?: SkeletonPreset
25
25
  /** Only used with `preset='circle'` — overrides the diameter. Defaults to 40. */
26
26
  diameter?: number
27
+ /** Override the skeleton background color. Defaults to `colors.skeleton`. */
28
+ backgroundColor?: string
27
29
  style?: ViewStyle
28
30
  }
29
31
 
@@ -33,6 +35,7 @@ export function Skeleton({
33
35
  borderRadius = 6,
34
36
  preset = 'base',
35
37
  diameter = 40,
38
+ backgroundColor,
36
39
  style,
37
40
  }: SkeletonProps) {
38
41
  const { colors, colorScheme } = useTheme()
@@ -40,7 +43,7 @@ export function Skeleton({
40
43
  const [containerWidth, setContainerWidth] = useState(300)
41
44
 
42
45
  const shimmerHighlight =
43
- colorScheme === 'dark' ? 'rgba(255,255,255,0.08)' : 'rgba(255,255,255,0.7)'
46
+ colorScheme === 'dark' ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.07)'
44
47
 
45
48
  useEffect(() => {
46
49
  // Repeats indefinitely on the UI thread — zero JS bridge cost per frame.
@@ -75,7 +78,7 @@ export function Skeleton({
75
78
  <View
76
79
  style={[
77
80
  styles.base,
78
- { width: resolvedWidth as number | `${number}%`, height: resolvedHeight, borderRadius: resolvedRadius, backgroundColor: colors.surface },
81
+ { width: resolvedWidth as number | `${number}%`, height: resolvedHeight, borderRadius: resolvedRadius, backgroundColor: backgroundColor ?? colors.skeleton },
79
82
  style,
80
83
  ]}
81
84
  onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}
@@ -8,6 +8,7 @@ import { renderIcon } from '../../utils/icons'
8
8
  import { PressableCard } from '../../utils/pressable'
9
9
 
10
10
  export type StatsVariant = 'elevated' | 'outlined' | 'filled'
11
+ export type StatsSize = 'default' | 'compact'
11
12
 
12
13
  export interface StatsProps {
13
14
  value: string
@@ -17,6 +18,8 @@ export interface StatsProps {
17
18
  iconName?: string
18
19
  iconColor?: string
19
20
  variant?: StatsVariant
21
+ /** `'compact'` reduces everything proportionally for tight grids. */
22
+ size?: StatsSize
20
23
  onPress?: () => void
21
24
  style?: ViewStyle
22
25
  accessibilityLabel?: string
@@ -38,6 +41,7 @@ function StatsComponent({
38
41
  iconName,
39
42
  iconColor,
40
43
  variant = 'elevated',
44
+ size = 'default',
41
45
  onPress,
42
46
  style,
43
47
  accessibilityLabel,
@@ -60,6 +64,30 @@ function StatsComponent({
60
64
 
61
65
  const isCompact = containerWidth > 0 && containerWidth < COMPACT_THRESHOLD && !!(icon ?? iconName)
62
66
 
67
+ const sizeStyles = size === 'compact'
68
+ ? {
69
+ valueFontFamily: 'Sohne-SemiBold' as const,
70
+ valueFontSize: ms(16),
71
+ valueLineHeight: mvs(20),
72
+ labelFontSize: ms(11),
73
+ labelLineHeight: mvs(14),
74
+ descriptionFontSize: ms(10),
75
+ descriptionLineHeight: mvs(14),
76
+ iconSize: ms(18),
77
+ padding: s(12),
78
+ }
79
+ : {
80
+ valueFontFamily: 'Sohne-Bold' as const,
81
+ valueFontSize: ms(21),
82
+ valueLineHeight: mvs(25),
83
+ labelFontSize: ms(13),
84
+ labelLineHeight: mvs(18),
85
+ descriptionFontSize: ms(12),
86
+ descriptionLineHeight: mvs(16),
87
+ iconSize: ms(20),
88
+ padding: s(16),
89
+ }
90
+
63
91
  const variantStyle: ViewStyle = {
64
92
  elevated: {
65
93
  backgroundColor: colors.card,
@@ -86,29 +114,29 @@ function StatsComponent({
86
114
 
87
115
  const iconColorResolved = iconColor ?? colors.primary
88
116
 
89
- const resolvedIcon = iconName ? renderIcon(iconName, ms(22), iconColorResolved) : icon
117
+ const resolvedIcon = iconName ? renderIcon(iconName, sizeStyles.iconSize, iconColorResolved) : icon
90
118
 
91
119
  const iconElement = resolvedIcon ? (
92
120
  <View style={styles.iconWrapper}>{resolvedIcon}</View>
93
121
  ) : null
94
122
 
95
123
  const valueElement = (
96
- <Text style={[styles.value, { color: colors.foreground }]} allowFontScaling={true}>
124
+ <Text style={[styles.value, { color: colors.foreground, fontFamily: sizeStyles.valueFontFamily, fontSize: sizeStyles.valueFontSize, lineHeight: sizeStyles.valueLineHeight }]} allowFontScaling={true}>
97
125
  {value}
98
126
  </Text>
99
127
  )
100
128
 
101
129
  const cardContent = (
102
- <View style={[styles.card, variantStyle, style]} onLayout={handleLayout}>
130
+ <View style={[styles.card, variantStyle, { padding: sizeStyles.padding }, style]} onLayout={handleLayout}>
103
131
  {isCompact ? (
104
132
  <>
105
133
  {iconElement}
106
134
  <View style={styles.compactValue}>{valueElement}</View>
107
- <Text style={[styles.label, { color: colors.foregroundSubtle }]} allowFontScaling={true}>
135
+ <Text style={[styles.label, { color: colors.foregroundSubtle, fontSize: sizeStyles.labelFontSize, lineHeight: sizeStyles.labelLineHeight }]} allowFontScaling={true}>
108
136
  {label}
109
137
  </Text>
110
138
  {description ? (
111
- <Text style={[styles.description, { color: colors.foregroundMuted }]} allowFontScaling={true}>
139
+ <Text style={[styles.description, { color: colors.foregroundMuted, fontSize: sizeStyles.descriptionFontSize, lineHeight: sizeStyles.descriptionLineHeight }]} allowFontScaling={true}>
112
140
  {description}
113
141
  </Text>
114
142
  ) : null}
@@ -119,11 +147,11 @@ function StatsComponent({
119
147
  {iconElement}
120
148
  {valueElement}
121
149
  </View>
122
- <Text style={[styles.label, { color: colors.foregroundSubtle }]} allowFontScaling={true}>
150
+ <Text style={[styles.label, { color: colors.foregroundSubtle, fontSize: sizeStyles.labelFontSize, lineHeight: sizeStyles.labelLineHeight }]} allowFontScaling={true}>
123
151
  {label}
124
152
  </Text>
125
153
  {description ? (
126
- <Text style={[styles.description, { color: colors.foregroundMuted }]} allowFontScaling={true}>
154
+ <Text style={[styles.description, { color: colors.foregroundMuted, fontSize: sizeStyles.descriptionFontSize, lineHeight: sizeStyles.descriptionLineHeight }]} allowFontScaling={true}>
127
155
  {description}
128
156
  </Text>
129
157
  ) : null}
package/src/index.ts CHANGED
@@ -50,6 +50,7 @@ export * from './components/ErrorBoundary'
50
50
  export * from './components/PagerDots'
51
51
  export * from './components/AppHeader'
52
52
  export * from './components/SelectableGrid'
53
+ export * from './components/SelectableCard'
53
54
  export * from './components/PricingCard'
54
55
  export * from './components/TabBar'
55
56
  export * from './components/ImageViewer'
@@ -69,6 +69,12 @@ export function deriveColors(t: ThemeColors, scheme: 'light' | 'dark'): Resolved
69
69
  ? lighten(bg, -0.12)
70
70
  : darken(bg, 0.08)
71
71
 
72
+ // Skeleton needs higher contrast than surface to be visible.
73
+ // Light: 10% darken (was 4% via surface — invisible). Dark: 10% lighten.
74
+ const skeleton = dark
75
+ ? lighten(bg, -0.10)
76
+ : darken(bg, 0.10)
77
+
72
78
  const destructiveTint = dark
73
79
  ? withAlphaOnDark(t.destructive, 0.15, bg)
74
80
  : withAlphaOnWhite(t.destructive, 0.08)
@@ -96,6 +102,7 @@ export function deriveColors(t: ThemeColors, scheme: 'light' | 'dark'): Resolved
96
102
  foregroundMuted,
97
103
  surface,
98
104
  surfaceStrong,
105
+ skeleton,
99
106
  destructiveTint,
100
107
  destructiveBorder,
101
108
  successTint,
@@ -29,10 +29,13 @@ export type ResolvedColors = ThemeColors & {
29
29
  foregroundSubtle: string // ~55% — body text, subtitles
30
30
  foregroundMuted: string // ~35% — captions, timestamps, placeholders
31
31
 
32
- // Surface fills (chips unselected, input bg, tag bg, skeleton)
32
+ // Surface fills (chips unselected, input bg, tag bg)
33
33
  surface: string // background slightly off-canvas
34
34
  surfaceStrong: string // slightly stronger fill for pressed/hover states
35
35
 
36
+ // Skeleton placeholder — higher contrast than surface for visibility
37
+ skeleton: string
38
+
36
39
  // Semantic tints (light bg for alert banners, toast backgrounds)
37
40
  destructiveTint: string
38
41
  destructiveBorder: string