@retray-dev/ui-kit 1.7.0 → 2.3.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 (40) hide show
  1. package/COMPONENTS.md +258 -54
  2. package/README.md +6 -5
  3. package/dist/index.d.mts +113 -44
  4. package/dist/index.d.ts +113 -44
  5. package/dist/index.js +802 -324
  6. package/dist/index.mjs +794 -323
  7. package/package.json +6 -2
  8. package/src/components/Alert/Alert.tsx +24 -12
  9. package/src/components/AlertBanner/AlertBanner.tsx +83 -0
  10. package/src/components/AlertBanner/index.ts +2 -0
  11. package/src/components/Avatar/Avatar.tsx +1 -0
  12. package/src/components/Badge/Badge.tsx +44 -8
  13. package/src/components/Button/Button.tsx +12 -5
  14. package/src/components/Card/Card.tsx +86 -9
  15. package/src/components/Chip/Chip.tsx +173 -0
  16. package/src/components/Chip/index.ts +2 -0
  17. package/src/components/ConfirmDialog/ConfirmDialog.tsx +87 -0
  18. package/src/components/ConfirmDialog/index.ts +2 -0
  19. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
  20. package/src/components/CurrencyInput/CurrencyInput.tsx +9 -1
  21. package/src/components/EmptyState/EmptyState.tsx +42 -7
  22. package/src/components/Input/Input.tsx +102 -21
  23. package/src/components/LabelValue/LabelValue.tsx +47 -0
  24. package/src/components/LabelValue/index.ts +2 -0
  25. package/src/components/ListItem/ListItem.tsx +121 -0
  26. package/src/components/ListItem/index.ts +2 -0
  27. package/src/components/MonthPicker/MonthPicker.tsx +92 -0
  28. package/src/components/MonthPicker/index.ts +2 -0
  29. package/src/components/Select/Select.tsx +189 -125
  30. package/src/components/Slider/Slider.tsx +64 -100
  31. package/src/components/Switch/Switch.tsx +25 -21
  32. package/src/components/Textarea/Textarea.tsx +12 -2
  33. package/src/components/Toggle/Toggle.tsx +13 -6
  34. package/src/index.ts +8 -2
  35. package/src/theme/ThemeProvider.tsx +11 -8
  36. package/src/theme/colors.ts +19 -18
  37. package/src/theme/types.ts +2 -0
  38. package/src/components/Alert/index.ts +0 -2
  39. package/src/components/CurrencyInputLarge/CurrencyInputLarge.tsx +0 -66
  40. package/src/components/CurrencyInputLarge/index.ts +0 -1
package/COMPONENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # @retray-dev/ui-kit — Component Reference (v1.7.0)
1
+ # @retray-dev/ui-kit — Component Reference (v2.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
 
@@ -74,29 +74,34 @@ function MyComponent() {
74
74
 
75
75
  ## Theme Tokens
76
76
 
77
- All 20 tokens are available via `useTheme().colors`.
77
+ All 20 tokens are available via `useTheme().colors` and are applied exactly as provided — there is no automatic color derivation or forced contrast applied by the library. Consumers may pass partial overrides for `light` and/or `dark` and the values are used as-is.
78
+
79
+ The `ThemeColors` type (and `Theme`, `ColorScheme`) are exported directly from the package:
80
+ ```ts
81
+ import type { ThemeColors } from '@retray-dev/ui-kit'
82
+ ```
78
83
 
79
84
  | Token | Light | Dark | Semantic Role |
80
85
  |-------|-------|------|---------------|
81
86
  | `background` | `#ffffff` | `#171717` | Screen / page background |
82
87
  | `foreground` | `#171717` | `#fafafa` | Primary text color |
83
- | `card` | `#ffffff` | `#1f1f1f` | Card / surface background |
88
+ | `card` | `#ffffff` | `#222222` | Card / surface background |
84
89
  | `cardForeground` | `#171717` | `#fafafa` | Text on cards |
85
90
  | `primary` | `#1a1a1a` | `#fafafa` | Primary action (buttons, selected states) |
86
- | `primaryForeground` | `#fafafa` | `#1a1a1a` | Text/icon on primary background |
87
- | `secondary` | `#f5f5f5` | `#2a2a2a` | Secondary surfaces |
88
- | `secondaryForeground` | `#1a1a1a` | `#fafafa` | Text on secondary |
89
- | `muted` | `#f5f5f5` | `#2a2a2a` | Muted backgrounds, skeleton fills, track fills |
90
- | `mutedForeground` | `#646464` | `#a3a3a3` | Placeholder text, helper text, captions (WCAG AA ≥4.5:1) |
91
- | `accent` | `#f5f5f5` | `#2a2a2a` | Hover / pressed state fills |
92
- | `accentForeground` | `#1a1a1a` | `#fafafa` | Text on accent |
91
+ | `primaryForeground` | `#ffffff` | `#1a1a1a` | Text/icon on primary background |
92
+ | `secondary` | `#f1f1f1` | `#323232` | Secondary surfaces |
93
+ | `secondaryForeground` | `#171717` | `#fafafa` | Text on secondary |
94
+ | `muted` | `#f1f1f1` | `#323232` | Muted backgrounds, skeleton fills, track fills |
95
+ | `mutedForeground` | `#a2a2a2` | `#888888` | Placeholder text, helper text, captions |
96
+ | `accent` | `#e4e4e4` | `#323232` | Hover / pressed state fills |
97
+ | `accentForeground` | `#171717` | `#fafafa` | Text on accent |
93
98
  | `destructive` | `#ef4444` | `#dc2626` | Error / danger / delete actions |
94
- | `destructiveForeground` | `#fafafa` | `#fafafa` | Text on destructive |
99
+ | `destructiveForeground` | `#1a1a1a` | `#1a1a1a` | Text on destructive |
95
100
  | `border` | `#e5e5e5` | `#2a2a2a` | Borders and dividers |
96
101
  | `input` | `#e5e5e5` | `#2a2a2a` | Input field border color |
97
- | `ring` | `#a3a3a3` | `#d4d4d4` | Focus ring color |
102
+ | `ring` | `#1a1a1a` | `#fafafa` | Optional focus ring token (components may use `primary` by default) |
98
103
  | `success` | `#16a34a` | `#22c55e` | Success state (Toast success variant) |
99
- | `successForeground` | `#ffffff` | `#ffffff` | Text on success background |
104
+ | `successForeground` | `#1a1a1a` | `#1a1a1a` | Text on success background |
100
105
 
101
106
  ---
102
107
 
@@ -142,11 +147,11 @@ All 20 tokens are available via `useTheme().colors`.
142
147
  | Prop | Type | Default | Notes |
143
148
  |------|------|---------|-------|
144
149
  | label | `string` | required | Button text |
145
- | variant | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Visual style |
150
+ | variant | `'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'destructive'` | `'primary'` | Visual style |
146
151
  | size | `'sm' \| 'md' \| 'lg'` | `'md'` | — |
147
152
  | loading | `boolean` | `false` | Replaces label with a spinner and forces disabled state |
148
153
  | fullWidth | `boolean` | `false` | Stretches to container width (`alignSelf: 'stretch'`) |
149
- | disabled | `boolean` | — | Reduces opacity to 0.45 |
154
+ | disabled | `boolean` | — | Reduces opacity to 0.5 |
150
155
  | icon | `React.ReactNode` | — | Icon rendered alongside the label |
151
156
  | iconPosition | `'left' \| 'right'` | `'left'` | Side the icon appears on |
152
157
 
@@ -155,6 +160,7 @@ All 20 tokens are available via `useTheme().colors`.
155
160
  - `secondary`: filled with `secondary` token — less prominent actions
156
161
  - `outline`: transparent with `border` — alternative without fill
157
162
  - `ghost`: fully transparent — in-context or low-emphasis actions
163
+ - `destructive`: filled with `destructive` token — irreversible or dangerous actions
158
164
 
159
165
  **Animations:** Scale springs to 0.97 on `onPressIn`, back to 1.0 on `onPressOut`.
160
166
 
@@ -180,14 +186,19 @@ All 20 tokens are available via `useTheme().colors`.
180
186
  | label | `string` | — | Label above the input |
181
187
  | error | `string` | — | Shows error text below; turns border red (`destructive` token) |
182
188
  | hint | `string` | — | Helper text below (hidden when `error` is set) |
189
+ | prefix | `string \| ReactNode` | — | Content rendered before the input field (e.g., `"$"` or an icon) |
190
+ | suffix | `string \| ReactNode` | — | Content rendered after the input field (e.g., `"kg"` or a button) |
191
+ | type | `'text' \| 'password'` | `'text'` | When `'password'`, shows a visibility toggle button in the suffix slot |
183
192
 
184
193
  **Border colors:** `destructive` when `error` is set, `ring` when focused, `border` otherwise.
185
194
 
186
195
  **Example:**
187
196
  ```tsx
188
197
  <Input label="Email" placeholder="you@example.com" keyboardType="email-address" />
189
- <Input label="Password" secureTextEntry error="Incorrect password" />
198
+ <Input label="Password" type="password" error="Incorrect password" />
190
199
  <Input label="Username" hint="Must be at least 4 characters" />
200
+ <Input label="Amount" prefix="$" placeholder="0.00" keyboardType="numeric" />
201
+ <Input label="Weight" suffix="kg" placeholder="0" />
191
202
  ```
192
203
 
193
204
  ---
@@ -204,6 +215,7 @@ All 20 tokens are available via `useTheme().colors`.
204
215
  | onChangeValue | `(raw: number) => void` | — | Called with the parsed number (no separators, no prefix) |
205
216
  | prefix | `string` | `'$'` | Symbol prepended to the formatted value |
206
217
  | thousandsSeparator | `'.' \| ','` | `'.'` | Character used to separate groups of three digits |
218
+ | size | `'default' \| 'large'` | `'default'` | `'large'` uses 36px font size (previously `CurrencyInputLarge`) |
207
219
  | label | `string` | — | Label above the input |
208
220
  | error | `string` | — | Error text below; turns border red |
209
221
  | hint | `string` | — | Helper text below (hidden when `error` is set) |
@@ -264,16 +276,20 @@ const [amount, setAmount] = useState(0)
264
276
 
265
277
  | Prop | Type | Default | Notes |
266
278
  |------|------|---------|-------|
267
- | label | `string` | required | — |
279
+ | label | `string` | | Badge text can be omitted if using `children` |
280
+ | children | `ReactNode` | — | Alternative to `label` for custom content |
268
281
  | variant | `'default' \| 'secondary' \| 'destructive' \| 'outline'` | `'default'` | — |
282
+ | size | `'sm' \| 'md' \| 'lg'` | `'md'` | Controls padding and font size |
283
+ | icon | `ReactNode` | — | Icon rendered before the label/children |
269
284
  | style | `ViewStyle` | — | — |
270
285
 
271
286
  **Example:**
272
287
  ```tsx
273
288
  <Badge label="New" />
274
289
  <Badge label="Error" variant="destructive" />
275
- <Badge label="Draft" variant="secondary" />
290
+ <Badge label="Draft" variant="secondary" size="sm" />
276
291
  <Badge label="Beta" variant="outline" />
292
+ <Badge icon={<CheckIcon size={12} />} size="sm">Verified</Badge>
277
293
  ```
278
294
 
279
295
  ---
@@ -380,29 +396,6 @@ const [amount, setAmount] = useState(0)
380
396
 
381
397
  ---
382
398
 
383
- ### Card
384
-
385
- **Import:** `import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@retray-dev/ui-kit'`
386
- **When to use:** Grouped content with a surface background, border, and shadow.
387
-
388
- All sub-components accept a `style` prop for overrides.
389
-
390
- **Example:**
391
- ```tsx
392
- <Card>
393
- <CardHeader>
394
- <CardTitle>Account</CardTitle>
395
- <CardDescription>Manage your profile settings</CardDescription>
396
- </CardHeader>
397
- <CardContent>
398
- <Input label="Name" />
399
- </CardContent>
400
- <CardFooter>
401
- <Button label="Save" fullWidth />
402
- </CardFooter>
403
-
404
- ---
405
-
406
399
  ### CurrencyDisplay
407
400
 
408
401
  **Import:** `import { CurrencyDisplay } from '@retray-dev/ui-kit'`
@@ -413,6 +406,7 @@ All sub-components accept a `style` prop for overrides.
413
406
  | value | `number \| string` | required | Numeric value to display |
414
407
  | prefix | `string` | `'$'` | Symbol prepended to the formatted value |
415
408
  | showDecimals | `boolean` | `false` | When `true`, shows two decimal places separated by a comma (e.g. `$25.000,00`) |
409
+ | textColor | `string` | — | Override the color of the formatted text. Defaults to the `foreground` token |
416
410
  | style | `ViewStyle` | — | Style override for outer container |
417
411
 
418
412
  **Example:**
@@ -474,11 +468,20 @@ const [amount, setAmount] = useState(0)
474
468
  **Import:** `import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@retray-dev/ui-kit'`
475
469
  **When to use:** Grouped content with a surface background, border, and shadow.
476
470
 
477
- All sub-components accept a `style` prop for overrides.
471
+ **`Card` Props:**
472
+
473
+ | Prop | Type | Default | Notes |
474
+ |------|------|---------|-------|
475
+ | variant | `'elevated' \| 'outlined' \| 'filled'` | `'elevated'` | `elevated`: shadow + border; `outlined`: border only; `filled`: background fill, no border |
476
+ | onPress | `() => void` | — | Makes the card pressable with scale animation + haptics |
477
+ | children | `ReactNode` | — | — |
478
+ | style | `ViewStyle` | — | — |
479
+
480
+ All sub-components (`CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`) accept a `style` prop for overrides.
478
481
 
479
482
  **Example:**
480
483
  ```tsx
481
- <Card>
484
+ <Card variant="elevated">
482
485
  <CardHeader>
483
486
  <CardTitle>Account</CardTitle>
484
487
  <CardDescription>Manage your profile settings</CardDescription>
@@ -490,33 +493,44 @@ All sub-components accept a `style` prop for overrides.
490
493
  <Button label="Save" fullWidth />
491
494
  </CardFooter>
492
495
  </Card>
496
+
497
+ // Pressable card
498
+ <Card variant="outlined" onPress={() => navigate('detail')}>
499
+ <CardContent>
500
+ <Text>Tap me</Text>
501
+ </CardContent>
502
+ </Card>
493
503
  ```
494
504
 
495
505
  **Notes:**
496
- - `CardHeader` and `CardContent` have `padding: 24`
506
+ - `CardHeader` and `CardContent` have `padding: 24`. Override via the `style` prop: `<CardContent style={{ padding: 16 }}>`
497
507
  - `CardFooter` has `paddingTop: 0` so it connects naturally to `CardContent`
498
508
  - `CardTitle`: 18px / 600 weight, `cardForeground` color
499
509
  - `CardDescription`: 14px, `mutedForeground` color
510
+ - Press animation scales to 0.98 via `Animated.spring` when `onPress` is provided
500
511
 
501
512
  ---
502
513
 
503
- ### Alert
514
+ ### AlertBanner
504
515
 
505
- **Import:** `import { Alert } from '@retray-dev/ui-kit'`
506
- **When to use:** Inline feedback messages (info, success, warning, error). Not for transient toasts.
516
+ **Import:** `import { AlertBanner } from '@retray-dev/ui-kit'`
517
+ **When to use:** Inline feedback messages (info, success, error). Not for transient toasts — use `Toast` for ephemeral feedback.
518
+
519
+ > **Note:** Named `AlertBanner` (not `Alert`) to avoid collision with React Native's built-in `Alert` module.
507
520
 
508
521
  | Prop | Type | Default | Notes |
509
522
  |------|------|---------|-------|
510
523
  | title | `string` | — | Bold heading |
511
524
  | description | `string` | — | Detail text |
512
- | variant | `'default' \| 'destructive'` | `'default'` | `destructive` turns border and text to `destructive` token |
513
- | icon | `ReactNode` | — | Icon placed to the left of the text content |
525
+ | variant | `'default' \| 'destructive' \| 'success'` | `'default'` | Controls border/text color |
526
+ | icon | `ReactNode` | — | Icon placed to the left of the text content. Defaults to a variant-appropriate symbol (`ℹ`, `⚠`, `✓`) |
514
527
  | style | `ViewStyle` | — | — |
515
528
 
516
529
  **Example:**
517
530
  ```tsx
518
- <Alert title="Success" description="Your profile has been updated." />
519
- <Alert variant="destructive" title="Error" description="Failed to save. Try again." />
531
+ <AlertBanner title="Info" description="Your session will expire in 5 minutes." />
532
+ <AlertBanner variant="destructive" title="Error" description="Failed to save. Try again." />
533
+ <AlertBanner variant="success" title="Done" description="Your changes have been saved." />
520
534
  ```
521
535
 
522
536
  ---
@@ -532,6 +546,7 @@ All sub-components accept a `style` prop for overrides.
532
546
  | description | `string` | — | — |
533
547
  | icon | `ReactNode` | — | Shown in a 48×48 muted square above the text |
534
548
  | action | `ReactNode` | — | Usually a `Button`, placed below the text |
549
+ | size | `'default' \| 'compact'` | `'default'` | `compact` hides description/action, uses a 36×36 icon, smaller title (15px), and tighter spacing |
535
550
  | style | `ViewStyle` | — | — |
536
551
 
537
552
  **Example:**
@@ -577,7 +592,7 @@ const [accepted, setAccepted] = useState(false)
577
592
  | disabled | `boolean` | — | Reduces opacity to 0.45 |
578
593
  | style | `ViewStyle` | — | — |
579
594
 
580
- **Dimensions:** Track 56×32pt, Thumb 24×24pt with 4pt offset from edges (`top: 4, left: 4`). Thumb uses `position: 'absolute'` inside the track.
595
+ **Dimensions:** Track 60×36pt, Thumb 28×28pt with 4pt offset from edges (`top: 4, left: 4`). Thumb uses `position: 'absolute'` inside the track.
581
596
 
582
597
  **Animation:** Thumb translates via spring (bounciness: 4); track color transitions via opacity timing (150ms).
583
598
 
@@ -650,7 +665,7 @@ const [accepted, setAccepted] = useState(false)
650
665
  ### Select
651
666
 
652
667
  **Import:** `import { Select } from '@retray-dev/ui-kit'`
653
- **When to use:** Dropdown picker. Tapping the trigger opens a modal with a scrollable list.
668
+ **When to use:** Dropdown picker. Uses the native system picker UI on each platform — wheel modal on iOS (confirm with "Done"), spinner dialog on Android, native `<select>` on web (full keyboard support). Requires `@react-native-picker/picker` installed in the consuming app.
654
669
 
655
670
  | Prop | Type | Default | Notes |
656
671
  |------|------|---------|-------|
@@ -690,13 +705,27 @@ const [accepted, setAccepted] = useState(false)
690
705
  | onValueChange | `(value: number) => void` | — | Fires while dragging |
691
706
  | onSlidingComplete | `(value: number) => void` | — | Fires on finger release |
692
707
  | disabled | `boolean` | — | — |
708
+ | label | `string` | — | Label text displayed above the slider |
709
+ | showValue | `boolean` | `false` | When `true`, displays the current value at the top right |
710
+ | formatValue | `(value: number) => string` | — | Custom formatter for the displayed value |
711
+ | accessibilityLabel | `string` | — | Accessibility label for screen readers |
693
712
  | style | `ViewStyle` | — | — |
694
713
 
695
- **Dimensions:** Container height=32pt, track height=6pt, thumb 28×28pt. Uses `PanResponder` internally.
714
+ **Notes:** Uses `@react-native-community/slider` natively — theming applied via `minimumTrackTintColor` (primary), `maximumTrackTintColor` (muted), `thumbTintColor` (primary). Requires `@react-native-community/slider` installed in the consuming app.
696
715
 
697
716
  **Example:**
698
717
  ```tsx
699
718
  <Slider value={volume} minimumValue={0} maximumValue={100} step={1} onValueChange={setVolume} />
719
+ <Slider
720
+ label="Volume"
721
+ showValue
722
+ value={volume}
723
+ minimumValue={0}
724
+ maximumValue={100}
725
+ step={5}
726
+ formatValue={(v) => `${v}%`}
727
+ onValueChange={setVolume}
728
+ />
700
729
  ```
701
730
 
702
731
  ---
@@ -795,6 +824,11 @@ pnpm add @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handl
795
824
  ```
796
825
  Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to your `babel.config.js` plugins.
797
826
 
827
+ > **Important — Expo managed workflow:** Expo's install tool may downgrade `@gorhom/bottom-sheet` to an incompatible version (v4). Pin it in `app.json` to prevent this:
828
+ > ```json
829
+ > { "expo": { "install": { "exclude": ["@gorhom/bottom-sheet"] } } }
830
+ > ```
831
+
798
832
  | Prop | Type | Default | Notes |
799
833
  |------|------|---------|-------|
800
834
  | open | `boolean` | required | `true` presents the sheet, `false` dismisses it |
@@ -859,3 +893,173 @@ function MyComponent() {
859
893
  - Entrance: `withTiming(120ms, Easing.out(Easing.exp))` slide-down + opacity fade — fast, sharp feel
860
894
  - Exit: `withTiming(200ms)` slide-up + opacity fade
861
895
  - Swipe left or right to dismiss early (threshold: 80px or 800 pt/s velocity)
896
+
897
+ ---
898
+
899
+ ### ListItem
900
+
901
+ **Import:** `import { ListItem } from '@retray-dev/ui-kit'`
902
+ **When to use:** Rows in a list or menu. Composes icon, title, subtitle, and trailing content in a standard horizontal layout.
903
+
904
+ | Prop | Type | Default | Notes |
905
+ |------|------|---------|-------|
906
+ | title | `string` | required | Primary label |
907
+ | subtitle | `string` | — | Secondary label below the title |
908
+ | icon | `ReactNode` | — | Node rendered to the left of the text content |
909
+ | trailing | `string \| ReactNode` | — | Content on the right edge. Strings are styled as muted caption |
910
+ | onPress | `() => void` | — | Makes the row pressable. Scale animation + haptics are only active when provided |
911
+ | disabled | `boolean` | — | Reduces opacity to 0.45 |
912
+ | style | `ViewStyle` | — | — |
913
+
914
+ **Example:**
915
+ ```tsx
916
+ <ListItem
917
+ icon={<Ionicons name="receipt-outline" size={18} />}
918
+ title="Mercado"
919
+ subtitle="12 mar 2025"
920
+ trailing="$45.000"
921
+ onPress={() => navigate('detail')}
922
+ />
923
+
924
+ // Non-interactive row
925
+ <ListItem title="Account number" trailing="**** 4321" />
926
+ ```
927
+
928
+ ---
929
+
930
+ ### Chip / ChipGroup
931
+
932
+ **Import:** `import { Chip, ChipGroup } from '@retray-dev/ui-kit'`
933
+ **When to use:** Filter pills, single-select options displayed inline. Use `ChipGroup` for managed single-selection; use `Chip` standalone for custom logic.
934
+
935
+ **`Chip` Props:**
936
+
937
+ | Prop | Type | Default | Notes |
938
+ |------|------|---------|-------|
939
+ | label | `string` | required | — |
940
+ | selected | `boolean` | `false` | Controls fill color |
941
+ | onPress | `() => void` | — | — |
942
+ | style | `ViewStyle` | — | — |
943
+
944
+ **`ChipGroup` Props:**
945
+
946
+ | Prop | Type | Default | Notes |
947
+ |------|------|---------|-------|
948
+ | options | `ChipOption[]` | required | Each: `{ label: string, value: string \| number }` |
949
+ | value | `string \| number \| (string \| number)[]` | — | Currently selected value (single mode) or array of selected values (multi mode) |
950
+ | onValueChange | `(value: string \| number \| (string \| number)[]) => void` | — | — |
951
+ | multiSelect | `boolean` | `false` | When `true`, allows multiple chips to be selected simultaneously |
952
+ | style | `ViewStyle` | — | Applied to the wrapping row |
953
+
954
+ **Animation:** Background, text, and border colors animate via `Animated.timing` (150ms) between unselected (`secondary`/`border`/`foreground`) and selected (`primary`/`primary`/`primaryForeground`) states.
955
+
956
+ **Example:**
957
+ ```tsx
958
+ // Single select
959
+ const [pct, setPct] = useState(50)
960
+
961
+ <ChipGroup
962
+ options={[
963
+ { label: '40%', value: 40 },
964
+ { label: '50%', value: 50 },
965
+ { label: '100%', value: 100 },
966
+ ]}
967
+ value={pct}
968
+ onValueChange={setPct}
969
+ />
970
+
971
+ // Multi select
972
+ const [categories, setCategories] = useState<number[]>([1, 3])
973
+
974
+ <ChipGroup
975
+ multiSelect
976
+ options={[
977
+ { label: 'Food', value: 1 },
978
+ { label: 'Transport', value: 2 },
979
+ { label: 'Entertainment', value: 3 },
980
+ ]}
981
+ value={categories}
982
+ onValueChange={setCategories}
983
+ />
984
+ ```
985
+
986
+ ---
987
+
988
+ ### ConfirmDialog
989
+
990
+ **Import:** `import { ConfirmDialog } from '@retray-dev/ui-kit'`
991
+ **When to use:** Confirmation prompts before irreversible or destructive actions (delete, send, discard).
992
+
993
+ | Prop | Type | Default | Notes |
994
+ |------|------|---------|-------|
995
+ | visible | `boolean` | required | Controls modal visibility |
996
+ | title | `string` | required | Dialog heading |
997
+ | description | `string` | — | Supporting text below the title |
998
+ | confirmLabel | `string` | `'Confirm'` | Label for the confirm button |
999
+ | cancelLabel | `string` | `'Cancel'` | Label for the cancel button |
1000
+ | confirmVariant | `'primary' \| 'destructive'` | `'primary'` | Button variant for the confirm action |
1001
+ | onConfirm | `() => void` | required | Called when confirm is tapped |
1002
+ | onCancel | `() => void` | required | Called when cancel is tapped or backdrop is pressed |
1003
+
1004
+ **Notes:**
1005
+ - Uses React Native `Modal` with `animationType="fade"` — no bottom-sheet dependency.
1006
+ - Tapping outside the dialog card calls `onCancel`.
1007
+ - The cancel and confirm buttons are full-width stacked vertically.
1008
+
1009
+ **Example:**
1010
+ ```tsx
1011
+ <ConfirmDialog
1012
+ visible={showDelete}
1013
+ title="¿Eliminar gasto?"
1014
+ description="$45.000 · Mercado · 12 mar"
1015
+ confirmLabel="Eliminar"
1016
+ confirmVariant="destructive"
1017
+ onConfirm={handleDelete}
1018
+ onCancel={() => setShowDelete(false)}
1019
+ />
1020
+ ```
1021
+
1022
+ ---
1023
+
1024
+ ### LabelValue
1025
+
1026
+ **Import:** `import { LabelValue } from '@retray-dev/ui-kit'`
1027
+ **When to use:** Key-value display rows in receipts, summaries, and detail screens. Label on the left (muted caption), value on the right (medium weight).
1028
+
1029
+ | Prop | Type | Default | Notes |
1030
+ |------|------|---------|-------|
1031
+ | label | `string` | required | Caption text on the left |
1032
+ | value | `string \| ReactNode` | required | Value on the right. Strings are auto-styled; pass `ReactNode` for custom rendering |
1033
+ | style | `ViewStyle` | — | — |
1034
+
1035
+ **Example:**
1036
+ ```tsx
1037
+ <LabelValue label="Fecha" value="12 mar 2025" />
1038
+ <LabelValue label="Categoría" value="Mercado" />
1039
+ <LabelValue label="Estado" value={<Badge label="Pendiente" variant="secondary" />} />
1040
+ ```
1041
+
1042
+ ---
1043
+
1044
+ ### MonthPicker
1045
+
1046
+ **Import:** `import { MonthPicker } from '@retray-dev/ui-kit'`
1047
+ **When to use:** Compact month/year selector with previous/next navigation. Common in finance apps for filtering by period.
1048
+
1049
+ | Prop | Type | Default | Notes |
1050
+ |------|------|---------|-------|
1051
+ | value | `MonthPickerValue` | required | `{ month: number, year: number }` — `month` is 1–12 |
1052
+ | onChange | `(value: MonthPickerValue) => void` | required | Called on each navigation step |
1053
+ | style | `ViewStyle` | — | — |
1054
+
1055
+ **`MonthPickerValue`:** `{ month: number, year: number }` — month is 1-indexed (January = 1).
1056
+
1057
+ **Navigation:** Arrows wrap correctly at year boundaries (December → January increments the year; January → December decrements it). The component is fully controlled — no internal state.
1058
+
1059
+ **Example:**
1060
+ ```tsx
1061
+ const [period, setPeriod] = useState({ month: new Date().getMonth() + 1, year: new Date().getFullYear() })
1062
+
1063
+ <MonthPicker value={period} onChange={setPeriod} />
1064
+ // Displays: "April 2026"
1065
+ ```
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  A personal React Native / Expo UI component library with a built-in design system, dark mode support, haptic feedback, and smooth animations.
4
4
 
5
- - 26 components across 5 categories
6
- - Light/dark theme with 18 color tokens and full customization
5
+ - 32 components across 6 categories
6
+ - Light/dark theme with 20 color tokens and full customization
7
7
  - Apple HIG–compliant touch targets and haptic feedback
8
8
  - Animated interactions: spring press, sliding tabs, accordion easing, animated progress
9
9
  - Built with TypeScript — full type declarations included
@@ -93,18 +93,19 @@ import { useTheme } from '@retray-dev/ui-kit'
93
93
  const { colors, colorScheme } = useTheme()
94
94
  ```
95
95
 
96
- **Available tokens:** `background`, `foreground`, `card`, `cardForeground`, `primary`, `primaryForeground`, `secondary`, `secondaryForeground`, `muted`, `mutedForeground`, `accent`, `accentForeground`, `destructive`, `destructiveForeground`, `border`, `input`, `ring`
96
+ **Available tokens:** `background`, `foreground`, `card`, `cardForeground`, `primary`, `primaryForeground`, `secondary`, `secondaryForeground`, `muted`, `mutedForeground`, `accent`, `accentForeground`, `destructive`, `destructiveForeground`, `border`, `input`, `ring`, `success`, `successForeground`
97
97
 
98
98
  ## Components
99
99
 
100
100
  | Category | Components |
101
101
  | ----------- | ----------------------------------------------------------------------------------------------- |
102
- | Display | `Text`, `Badge`, `Avatar`, `Separator`, `Spinner`, `Skeleton`, `Progress`, `CurrencyDisplay` |
102
+ | Display | `Text`, `Badge`, `Avatar`, `Separator`, `Spinner`, `Skeleton`, `Progress`, `CurrencyDisplay` |
103
103
  | Surfaces | `Card`, `Alert`, `EmptyState` |
104
104
  | Form | `Button`, `Input`, `CurrencyInput`, `CurrencyInputLarge`, `Textarea`, `Checkbox`, `Switch`, `Toggle`, `RadioGroup`, `Select`, `Slider` |
105
105
  | Composition | `Tabs`, `Accordion` |
106
- | Overlays | `Sheet` |
106
+ | Overlays | `Sheet`, `ConfirmDialog` |
107
107
  | Feedback | `Toast` / `ToastProvider` / `useToast` |
108
+ | Data | `ListItem`, `Chip` / `ChipGroup`, `LabelValue`, `MonthPicker` |
108
109
 
109
110
  ### Quick examples
110
111