@retray-dev/ui-kit 6.0.0 → 6.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.
package/COMPONENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # @retray-dev/ui-kit — Component Reference (v6.0.0)
1
+ # @retray-dev/ui-kit — Component Reference (v6.1.0)
2
2
 
3
3
  This file is the AI reference for this package. It is shipped inside the npm package so consuming projects can import it into their `CLAUDE.md` with:
4
4
 
@@ -359,7 +359,7 @@ const styles = StyleSheet.create({
359
359
  ```tsx
360
360
  import { MenuItem } from '@retray-dev/ui-kit'
361
361
  // variants: 'plain' (default) | 'card'
362
- <MenuItem label="Profile" iconName="user" onPress={() => {}} />
362
+ <MenuItem label="Profile" subtitle="Edit your details" iconName="user" onPress={() => {}} />
363
363
  <MenuItem label="Notifications" iconName="bell" rightRender={<Switch value={on} onValueChange={setOn} />} showChevron={false} onPress={() => {}} />
364
364
  ```
365
365
 
@@ -2301,13 +2301,14 @@ dismiss(id)
2301
2301
 
2302
2302
  **Import:** `import { MenuItem } from '@retray-dev/ui-kit'`
2303
2303
 
2304
- **When to use:** Settings screens, navigation lists, menu entries — icon + label + optional right content. Purpose-built for Airbnb-style settings rows. Use `ListItem` when you need subtitle, caption, or more complex layouts.
2304
+ **When to use:** Settings screens, navigation lists, menu entries — icon + label + optional subtitle + optional right content. Purpose-built for Airbnb-style settings rows. Use `ListItem` when you need caption, metadata rows, or more complex layouts beyond label+subtitle.
2305
2305
 
2306
2306
  **Important:** MenuItem has **zero horizontal padding** by design — the consumer controls spacing. Wrap in a container with padding for standalone use, or use `variant="card"` for auto-styled surfaces.
2307
2307
 
2308
2308
  | Prop | Type | Default | Notes |
2309
2309
  |------|------|---------|-------|
2310
2310
  | label | `string` | required | Row label |
2311
+ | subtitle | `string` | — | Secondary text below label. Uses `mutedForeground` color |
2311
2312
  | iconName | `string` | — | Icon from `@expo/vector-icons`. Auto-resolved across all 6 families |
2312
2313
  | icon | `ReactNode` | — | Custom icon (used if `iconName` not set) |
2313
2314
  | iconColor | `string` | — | Override icon color. Defaults to `foreground` |
@@ -2331,7 +2332,7 @@ dismiss(id)
2331
2332
  ```tsx
2332
2333
  // Settings screen (wrap in container with padding)
2333
2334
  <View style={{ padding: 16, backgroundColor: colors.card, borderRadius: 12 }}>
2334
- <MenuItem label="Personal info" iconName="user" onPress={() => navigate('profile')} showSeparator />
2335
+ <MenuItem label="Personal info" subtitle="Name, email, phone" iconName="user" onPress={() => navigate('profile')} showSeparator />
2335
2336
  <MenuItem label="Security" iconName="shield" onPress={() => navigate('security')} showSeparator />
2336
2337
  <MenuItem label="Privacy" iconName="lock" onPress={() => navigate('privacy')} showSeparator />
2337
2338
  <MenuItem
package/dist/index.d.mts CHANGED
@@ -679,6 +679,8 @@ declare function ListItem({ leftRender, rightRender, trailing, icon, leftIcon, r
679
679
  type MenuItemVariant = 'plain' | 'card';
680
680
  interface MenuItemProps {
681
681
  label: string;
682
+ /** Secondary text rendered below the label. */
683
+ subtitle?: string;
682
684
  /**
683
685
  * Icon name from `@expo/vector-icons` rendered on the left.
684
686
  * See https://icons.expo.fyi.
@@ -713,7 +715,7 @@ interface MenuItemProps {
713
715
  /** Style applied to the label Text. */
714
716
  labelStyle?: TextStyle;
715
717
  }
716
- declare function MenuItem({ label, iconName, icon, iconColor, rightRender, showChevron, onPress, disabled, variant, showSeparator, style, labelStyle, }: MenuItemProps): React.JSX.Element;
718
+ declare function MenuItem({ label, subtitle, iconName, icon, iconColor, rightRender, showChevron, onPress, disabled, variant, showSeparator, style, labelStyle, }: MenuItemProps): React.JSX.Element;
717
719
 
718
720
  interface ChipProps {
719
721
  label: string;
@@ -865,11 +867,11 @@ type DetailRowSeparator = 'dotted' | 'solid' | 'dashed' | 'none';
865
867
  type DetailRowLabelWeight = 'normal' | 'medium' | 'semibold' | 'bold';
866
868
  interface DetailRowProps {
867
869
  label: React.ReactNode;
868
- value: string;
870
+ value: string | React.ReactNode;
869
871
  /** Dotted/dashed/solid line between label and value. Defaults to 'dotted'. */
870
872
  separator?: DetailRowSeparator;
871
873
  labelWeight?: DetailRowLabelWeight;
872
- /** Semantic color key or hex string for value text. */
874
+ /** Semantic color key or hex string for value text. Only applies when value is a string. */
873
875
  valueColor?: string;
874
876
  /** Node rendered left of the label (e.g. Avatar, Icon). */
875
877
  leftIcon?: React.ReactNode;
@@ -883,6 +885,7 @@ interface DetailRowProps {
883
885
  rightIconColor?: string;
884
886
  style?: ViewStyle;
885
887
  labelStyle?: TextStyle;
888
+ /** Only applies when value is a string. */
886
889
  valueStyle?: TextStyle;
887
890
  }
888
891
  declare function DetailRow({ label, value, separator, labelWeight, valueColor, leftIcon, leftIconName, leftIconColor, rightIconName, rightIconColor, style, labelStyle, valueStyle, }: DetailRowProps): React.JSX.Element;
package/dist/index.d.ts CHANGED
@@ -679,6 +679,8 @@ declare function ListItem({ leftRender, rightRender, trailing, icon, leftIcon, r
679
679
  type MenuItemVariant = 'plain' | 'card';
680
680
  interface MenuItemProps {
681
681
  label: string;
682
+ /** Secondary text rendered below the label. */
683
+ subtitle?: string;
682
684
  /**
683
685
  * Icon name from `@expo/vector-icons` rendered on the left.
684
686
  * See https://icons.expo.fyi.
@@ -713,7 +715,7 @@ interface MenuItemProps {
713
715
  /** Style applied to the label Text. */
714
716
  labelStyle?: TextStyle;
715
717
  }
716
- declare function MenuItem({ label, iconName, icon, iconColor, rightRender, showChevron, onPress, disabled, variant, showSeparator, style, labelStyle, }: MenuItemProps): React.JSX.Element;
718
+ declare function MenuItem({ label, subtitle, iconName, icon, iconColor, rightRender, showChevron, onPress, disabled, variant, showSeparator, style, labelStyle, }: MenuItemProps): React.JSX.Element;
717
719
 
718
720
  interface ChipProps {
719
721
  label: string;
@@ -865,11 +867,11 @@ type DetailRowSeparator = 'dotted' | 'solid' | 'dashed' | 'none';
865
867
  type DetailRowLabelWeight = 'normal' | 'medium' | 'semibold' | 'bold';
866
868
  interface DetailRowProps {
867
869
  label: React.ReactNode;
868
- value: string;
870
+ value: string | React.ReactNode;
869
871
  /** Dotted/dashed/solid line between label and value. Defaults to 'dotted'. */
870
872
  separator?: DetailRowSeparator;
871
873
  labelWeight?: DetailRowLabelWeight;
872
- /** Semantic color key or hex string for value text. */
874
+ /** Semantic color key or hex string for value text. Only applies when value is a string. */
873
875
  valueColor?: string;
874
876
  /** Node rendered left of the label (e.g. Avatar, Icon). */
875
877
  leftIcon?: React.ReactNode;
@@ -883,6 +885,7 @@ interface DetailRowProps {
883
885
  rightIconColor?: string;
884
886
  style?: ViewStyle;
885
887
  labelStyle?: TextStyle;
888
+ /** Only applies when value is a string. */
886
889
  valueStyle?: TextStyle;
887
890
  }
888
891
  declare function DetailRow({ label, value, separator, labelWeight, valueColor, leftIcon, leftIconName, leftIconColor, rightIconName, rightIconColor, style, labelStyle, valueStyle, }: DetailRowProps): React.JSX.Element;
package/dist/index.js CHANGED
@@ -2963,6 +2963,7 @@ var styles25 = reactNative.StyleSheet.create({
2963
2963
  var nativeDriver11 = reactNative.Platform.OS !== "web";
2964
2964
  function MenuItem({
2965
2965
  label,
2966
+ subtitle,
2966
2967
  iconName,
2967
2968
  icon,
2968
2969
  iconColor,
@@ -3024,7 +3025,7 @@ function MenuItem({
3024
3025
  touchSoundDisabled: true
3025
3026
  },
3026
3027
  resolvedIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles26.iconContainer }, resolvedIcon) : null,
3027
- /* @__PURE__ */ React26__default.default.createElement(
3028
+ /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles26.labelContainer }, /* @__PURE__ */ React26__default.default.createElement(
3028
3029
  reactNative.Text,
3029
3030
  {
3030
3031
  style: [styles26.label, { color: colors.foreground }, labelStyle],
@@ -3032,7 +3033,15 @@ function MenuItem({
3032
3033
  allowFontScaling: true
3033
3034
  },
3034
3035
  label
3035
- ),
3036
+ ), subtitle ? /* @__PURE__ */ React26__default.default.createElement(
3037
+ reactNative.Text,
3038
+ {
3039
+ style: [styles26.subtitle, { color: colors.foregroundMuted }],
3040
+ numberOfLines: 1,
3041
+ allowFontScaling: true
3042
+ },
3043
+ subtitle
3044
+ ) : null),
3036
3045
  rightRender !== void 0 ? /* @__PURE__ */ React26__default.default.createElement(
3037
3046
  reactNative.View,
3038
3047
  {
@@ -3072,10 +3081,18 @@ var styles26 = reactNative.StyleSheet.create({
3072
3081
  justifyContent: "center",
3073
3082
  flexShrink: 0
3074
3083
  },
3084
+ labelContainer: {
3085
+ flex: 1,
3086
+ justifyContent: "center"
3087
+ },
3075
3088
  label: {
3076
3089
  fontFamily: "Poppins-Medium",
3077
- fontSize: ms(15),
3078
- flex: 1
3090
+ fontSize: ms(15)
3091
+ },
3092
+ subtitle: {
3093
+ fontFamily: "Poppins-Regular",
3094
+ fontSize: ms(12),
3095
+ marginTop: vs(1)
3079
3096
  },
3080
3097
  rightContainer: {
3081
3098
  alignItems: "flex-end",
@@ -3792,14 +3809,14 @@ function DetailRow({
3792
3809
  allowFontScaling: true
3793
3810
  },
3794
3811
  label
3795
- ) : label), separatorStyle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: separatorStyle }) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.spacer }), /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.valueSide }, /* @__PURE__ */ React26__default.default.createElement(
3812
+ ) : label), separatorStyle ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: separatorStyle }) : /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.spacer }), /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.valueSide }, typeof value === "string" ? /* @__PURE__ */ React26__default.default.createElement(
3796
3813
  reactNative.Text,
3797
3814
  {
3798
3815
  style: [styles33.valueText, { color: valueColor ?? colors.foreground }, valueStyle],
3799
3816
  allowFontScaling: true
3800
3817
  },
3801
3818
  value
3802
- ), resolvedRightIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.icon }, resolvedRightIcon) : null));
3819
+ ) : value, resolvedRightIcon ? /* @__PURE__ */ React26__default.default.createElement(reactNative.View, { style: styles33.icon }, resolvedRightIcon) : null));
3803
3820
  }
3804
3821
  var styles33 = reactNative.StyleSheet.create({
3805
3822
  row: {
package/dist/index.mjs CHANGED
@@ -2951,6 +2951,7 @@ var styles25 = StyleSheet.create({
2951
2951
  var nativeDriver11 = Platform.OS !== "web";
2952
2952
  function MenuItem({
2953
2953
  label,
2954
+ subtitle,
2954
2955
  iconName,
2955
2956
  icon,
2956
2957
  iconColor,
@@ -3012,7 +3013,7 @@ function MenuItem({
3012
3013
  touchSoundDisabled: true
3013
3014
  },
3014
3015
  resolvedIcon ? /* @__PURE__ */ React26.createElement(View, { style: styles26.iconContainer }, resolvedIcon) : null,
3015
- /* @__PURE__ */ React26.createElement(
3016
+ /* @__PURE__ */ React26.createElement(View, { style: styles26.labelContainer }, /* @__PURE__ */ React26.createElement(
3016
3017
  Text,
3017
3018
  {
3018
3019
  style: [styles26.label, { color: colors.foreground }, labelStyle],
@@ -3020,7 +3021,15 @@ function MenuItem({
3020
3021
  allowFontScaling: true
3021
3022
  },
3022
3023
  label
3023
- ),
3024
+ ), subtitle ? /* @__PURE__ */ React26.createElement(
3025
+ Text,
3026
+ {
3027
+ style: [styles26.subtitle, { color: colors.foregroundMuted }],
3028
+ numberOfLines: 1,
3029
+ allowFontScaling: true
3030
+ },
3031
+ subtitle
3032
+ ) : null),
3024
3033
  rightRender !== void 0 ? /* @__PURE__ */ React26.createElement(
3025
3034
  View,
3026
3035
  {
@@ -3060,10 +3069,18 @@ var styles26 = StyleSheet.create({
3060
3069
  justifyContent: "center",
3061
3070
  flexShrink: 0
3062
3071
  },
3072
+ labelContainer: {
3073
+ flex: 1,
3074
+ justifyContent: "center"
3075
+ },
3063
3076
  label: {
3064
3077
  fontFamily: "Poppins-Medium",
3065
- fontSize: ms(15),
3066
- flex: 1
3078
+ fontSize: ms(15)
3079
+ },
3080
+ subtitle: {
3081
+ fontFamily: "Poppins-Regular",
3082
+ fontSize: ms(12),
3083
+ marginTop: vs(1)
3067
3084
  },
3068
3085
  rightContainer: {
3069
3086
  alignItems: "flex-end",
@@ -3780,14 +3797,14 @@ function DetailRow({
3780
3797
  allowFontScaling: true
3781
3798
  },
3782
3799
  label
3783
- ) : label), separatorStyle ? /* @__PURE__ */ React26.createElement(View, { style: separatorStyle }) : /* @__PURE__ */ React26.createElement(View, { style: styles33.spacer }), /* @__PURE__ */ React26.createElement(View, { style: styles33.valueSide }, /* @__PURE__ */ React26.createElement(
3800
+ ) : label), separatorStyle ? /* @__PURE__ */ React26.createElement(View, { style: separatorStyle }) : /* @__PURE__ */ React26.createElement(View, { style: styles33.spacer }), /* @__PURE__ */ React26.createElement(View, { style: styles33.valueSide }, typeof value === "string" ? /* @__PURE__ */ React26.createElement(
3784
3801
  Text,
3785
3802
  {
3786
3803
  style: [styles33.valueText, { color: valueColor ?? colors.foreground }, valueStyle],
3787
3804
  allowFontScaling: true
3788
3805
  },
3789
3806
  value
3790
- ), resolvedRightIcon ? /* @__PURE__ */ React26.createElement(View, { style: styles33.icon }, resolvedRightIcon) : null));
3807
+ ) : value, resolvedRightIcon ? /* @__PURE__ */ React26.createElement(View, { style: styles33.icon }, resolvedRightIcon) : null));
3791
3808
  }
3792
3809
  var styles33 = StyleSheet.create({
3793
3810
  row: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retray-dev/ui-kit",
3
- "version": "6.0.0",
3
+ "version": "6.1.0",
4
4
  "description": "Personal UI Kit for React Native / Expo",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -16,11 +16,11 @@ const weightMap: Record<DetailRowLabelWeight, string> = {
16
16
 
17
17
  export interface DetailRowProps {
18
18
  label: React.ReactNode
19
- value: string
19
+ value: string | React.ReactNode
20
20
  /** Dotted/dashed/solid line between label and value. Defaults to 'dotted'. */
21
21
  separator?: DetailRowSeparator
22
22
  labelWeight?: DetailRowLabelWeight
23
- /** Semantic color key or hex string for value text. */
23
+ /** Semantic color key or hex string for value text. Only applies when value is a string. */
24
24
  valueColor?: string
25
25
  /** Node rendered left of the label (e.g. Avatar, Icon). */
26
26
  leftIcon?: React.ReactNode
@@ -34,6 +34,7 @@ export interface DetailRowProps {
34
34
  rightIconColor?: string
35
35
  style?: ViewStyle
36
36
  labelStyle?: TextStyle
37
+ /** Only applies when value is a string. */
37
38
  valueStyle?: TextStyle
38
39
  }
39
40
 
@@ -91,12 +92,16 @@ export function DetailRow({
91
92
  </View>
92
93
  {separatorStyle ? <View style={separatorStyle} /> : <View style={styles.spacer} />}
93
94
  <View style={styles.valueSide}>
94
- <Text
95
- style={[styles.valueText, { color: valueColor ?? colors.foreground }, valueStyle]}
96
- allowFontScaling={true}
97
- >
98
- {value}
99
- </Text>
95
+ {typeof value === 'string' ? (
96
+ <Text
97
+ style={[styles.valueText, { color: valueColor ?? colors.foreground }, valueStyle]}
98
+ allowFontScaling={true}
99
+ >
100
+ {value}
101
+ </Text>
102
+ ) : (
103
+ value
104
+ )}
100
105
  {resolvedRightIcon ? <View style={styles.icon}>{resolvedRightIcon}</View> : null}
101
106
  </View>
102
107
  </View>
@@ -22,6 +22,8 @@ export type MenuItemVariant = 'plain' | 'card'
22
22
 
23
23
  export interface MenuItemProps {
24
24
  label: string
25
+ /** Secondary text rendered below the label. */
26
+ subtitle?: string
25
27
  /**
26
28
  * Icon name from `@expo/vector-icons` rendered on the left.
27
29
  * See https://icons.expo.fyi.
@@ -59,6 +61,7 @@ export interface MenuItemProps {
59
61
 
60
62
  export function MenuItem({
61
63
  label,
64
+ subtitle,
62
65
  iconName,
63
66
  icon,
64
67
  iconColor,
@@ -134,13 +137,24 @@ export function MenuItem({
134
137
  <View style={styles.iconContainer}>{resolvedIcon}</View>
135
138
  ) : null}
136
139
 
137
- <Text
138
- style={[styles.label, { color: colors.foreground }, labelStyle]}
139
- numberOfLines={1}
140
- allowFontScaling={true}
141
- >
142
- {label}
143
- </Text>
140
+ <View style={styles.labelContainer}>
141
+ <Text
142
+ style={[styles.label, { color: colors.foreground }, labelStyle]}
143
+ numberOfLines={1}
144
+ allowFontScaling={true}
145
+ >
146
+ {label}
147
+ </Text>
148
+ {subtitle ? (
149
+ <Text
150
+ style={[styles.subtitle, { color: colors.foregroundMuted }]}
151
+ numberOfLines={1}
152
+ allowFontScaling={true}
153
+ >
154
+ {subtitle}
155
+ </Text>
156
+ ) : null}
157
+ </View>
144
158
 
145
159
  {rightRender !== undefined ? (
146
160
  <View
@@ -186,10 +200,18 @@ const styles = StyleSheet.create({
186
200
  justifyContent: 'center',
187
201
  flexShrink: 0,
188
202
  },
203
+ labelContainer: {
204
+ flex: 1,
205
+ justifyContent: 'center',
206
+ },
189
207
  label: {
190
208
  fontFamily: 'Poppins-Medium',
191
209
  fontSize: ms(15),
192
- flex: 1,
210
+ },
211
+ subtitle: {
212
+ fontFamily: 'Poppins-Regular',
213
+ fontSize: ms(12),
214
+ marginTop: vs(1),
193
215
  },
194
216
  rightContainer: {
195
217
  alignItems: 'flex-end',