@retray-dev/ui-kit 0.1.0 → 1.0.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 (56) hide show
  1. package/COMPONENTS.md +654 -0
  2. package/LICENSE +21 -0
  3. package/README.md +151 -0
  4. package/dist/index.d.mts +309 -3
  5. package/dist/index.d.ts +309 -3
  6. package/dist/index.js +1477 -57
  7. package/dist/index.mjs +1424 -57
  8. package/package.json +27 -5
  9. package/src/components/Accordion/Accordion.tsx +161 -0
  10. package/src/components/Accordion/index.ts +2 -0
  11. package/src/components/Alert/Alert.tsx +57 -0
  12. package/src/components/Alert/index.ts +2 -0
  13. package/src/components/Avatar/Avatar.tsx +67 -0
  14. package/src/components/Avatar/index.ts +2 -0
  15. package/src/components/Badge/Badge.tsx +48 -0
  16. package/src/components/Badge/index.ts +2 -0
  17. package/src/components/Button/Button.tsx +78 -45
  18. package/src/components/Card/Card.tsx +109 -0
  19. package/src/components/Card/index.ts +9 -0
  20. package/src/components/Checkbox/Checkbox.tsx +70 -0
  21. package/src/components/Checkbox/index.ts +2 -0
  22. package/src/components/EmptyState/EmptyState.tsx +69 -0
  23. package/src/components/EmptyState/index.ts +2 -0
  24. package/src/components/Input/Input.tsx +26 -41
  25. package/src/components/Progress/Progress.tsx +53 -0
  26. package/src/components/Progress/index.ts +2 -0
  27. package/src/components/RadioGroup/RadioGroup.tsx +105 -0
  28. package/src/components/RadioGroup/index.ts +2 -0
  29. package/src/components/Select/Select.tsx +185 -0
  30. package/src/components/Select/index.ts +2 -0
  31. package/src/components/Separator/Separator.tsx +33 -0
  32. package/src/components/Separator/index.ts +2 -0
  33. package/src/components/Sheet/Sheet.tsx +108 -0
  34. package/src/components/Sheet/index.ts +2 -0
  35. package/src/components/Skeleton/Skeleton.tsx +40 -0
  36. package/src/components/Skeleton/index.ts +2 -0
  37. package/src/components/Slider/Slider.tsx +142 -0
  38. package/src/components/Slider/index.ts +2 -0
  39. package/src/components/Spinner/Spinner.tsx +27 -0
  40. package/src/components/Spinner/index.ts +2 -0
  41. package/src/components/Switch/Switch.tsx +82 -0
  42. package/src/components/Switch/index.ts +2 -0
  43. package/src/components/Tabs/Tabs.tsx +145 -0
  44. package/src/components/Tabs/index.ts +2 -0
  45. package/src/components/Text/Text.tsx +10 -4
  46. package/src/components/Textarea/Textarea.tsx +70 -0
  47. package/src/components/Textarea/index.ts +2 -0
  48. package/src/components/Toast/Toast.tsx +164 -0
  49. package/src/components/Toast/index.ts +2 -0
  50. package/src/components/Toggle/Toggle.tsx +80 -0
  51. package/src/components/Toggle/index.ts +2 -0
  52. package/src/index.ts +26 -0
  53. package/src/theme/ThemeProvider.tsx +47 -0
  54. package/src/theme/colors.ts +41 -0
  55. package/src/theme/index.ts +4 -0
  56. package/src/theme/types.ts +31 -0
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # @retray-dev/ui-kit
2
+
3
+ A personal React Native / Expo UI component library with a built-in design system, dark mode support, haptic feedback, and smooth animations.
4
+
5
+ - 23 components across 5 categories
6
+ - Light/dark theme with 18 color tokens and full customization
7
+ - Apple HIG–compliant touch targets and haptic feedback
8
+ - Animated interactions: spring press, sliding tabs, accordion easing, animated progress
9
+ - Built with TypeScript — full type declarations included
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # npm
15
+ npm install @retray-dev/ui-kit
16
+
17
+ # pnpm
18
+ pnpm add @retray-dev/ui-kit
19
+ ```
20
+
21
+ ### Peer dependencies
22
+
23
+ Install these in your app if not already present:
24
+
25
+ ```bash
26
+ pnpm add expo-haptics react-native-safe-area-context @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-worklets
27
+ ```
28
+
29
+ For Expo projects, run `npx expo install` instead to get SDK-compatible versions.
30
+
31
+ Add the Worklets Babel plugin to `babel.config.js` (required by `@gorhom/bottom-sheet`):
32
+
33
+ ```js
34
+ module.exports = function (api) {
35
+ api.cache(true)
36
+ return {
37
+ presets: ['babel-preset-expo'],
38
+ plugins: ['react-native-worklets/plugin'],
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Setup
44
+
45
+ Wrap your app root with all required providers. Order matters.
46
+
47
+ ```tsx
48
+ import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context'
49
+ import { GestureHandlerRootView } from 'react-native-gesture-handler'
50
+ import { ThemeProvider, BottomSheetModalProvider, ToastProvider } from '@retray-dev/ui-kit'
51
+
52
+ export default function App() {
53
+ return (
54
+ <SafeAreaProvider initialMetrics={initialWindowMetrics}>
55
+ <GestureHandlerRootView style={{ flex: 1 }}>
56
+ <ThemeProvider colorScheme="system">
57
+ <BottomSheetModalProvider>
58
+ <ToastProvider>
59
+ {/* your app */}
60
+ </ToastProvider>
61
+ </BottomSheetModalProvider>
62
+ </ThemeProvider>
63
+ </GestureHandlerRootView>
64
+ </SafeAreaProvider>
65
+ )
66
+ }
67
+ ```
68
+
69
+ | Provider | Required by |
70
+ |----------|-------------|
71
+ | `SafeAreaProvider` | `ToastProvider` (uses `useSafeAreaInsets`) |
72
+ | `GestureHandlerRootView` | `Sheet` (uses `@gorhom/bottom-sheet`) |
73
+ | `ThemeProvider` | All components |
74
+ | `BottomSheetModalProvider` | `Sheet` |
75
+ | `ToastProvider` | `useToast` hook |
76
+
77
+ ## Theme
78
+
79
+ Customize any color token per scheme:
80
+
81
+ ```tsx
82
+ const myTheme = {
83
+ light: { primary: '#6366f1', primaryForeground: '#ffffff' },
84
+ dark: { primary: '#818cf8', primaryForeground: '#ffffff' },
85
+ }
86
+
87
+ <ThemeProvider theme={myTheme} colorScheme="system">
88
+ ```
89
+
90
+ Access theme colors anywhere inside the tree:
91
+
92
+ ```tsx
93
+ import { useTheme } from '@retray-dev/ui-kit'
94
+
95
+ const { colors, colorScheme } = useTheme()
96
+ ```
97
+
98
+ **Available tokens:** `background`, `foreground`, `card`, `cardForeground`, `primary`, `primaryForeground`, `secondary`, `secondaryForeground`, `muted`, `mutedForeground`, `accent`, `accentForeground`, `destructive`, `destructiveForeground`, `border`, `input`, `ring`
99
+
100
+ ## Components
101
+
102
+ | Category | Components |
103
+ |----------|------------|
104
+ | Display | `Text`, `Badge`, `Avatar`, `Separator`, `Spinner`, `Skeleton`, `Progress` |
105
+ | Surfaces | `Card`, `Alert`, `EmptyState` |
106
+ | Form | `Button`, `Input`, `Textarea`, `Checkbox`, `Switch`, `Toggle`, `RadioGroup`, `Select`, `Slider` |
107
+ | Composition | `Tabs`, `Accordion` |
108
+ | Overlays | `Sheet` |
109
+ | Feedback | `Toast` / `ToastProvider` / `useToast` |
110
+
111
+ ### Quick examples
112
+
113
+ ```tsx
114
+ import {
115
+ Button, Input, Badge, Card, CardHeader, CardTitle, CardContent,
116
+ Toast, useToast, Sheet, Select, Tabs, TabsContent,
117
+ } from '@retray-dev/ui-kit'
118
+
119
+ // Button
120
+ <Button variant="default" size="md" onPress={() => {}}>
121
+ Save
122
+ </Button>
123
+
124
+ // Toast
125
+ const { toast } = useToast()
126
+ toast({ title: 'Saved', variant: 'success' })
127
+
128
+ // Sheet (bottom sheet)
129
+ <Sheet open={open} onClose={() => setOpen(false)} title="Options" snapPoints={['40%']}>
130
+ <Text>Sheet content</Text>
131
+ </Sheet>
132
+
133
+ // Select
134
+ <Select
135
+ value={value}
136
+ onValueChange={setValue}
137
+ options={[{ label: 'Option A', value: 'a' }, { label: 'Option B', value: 'b' }]}
138
+ placeholder="Pick one"
139
+ />
140
+ ```
141
+
142
+ Full props reference and more examples are available in [COMPONENTS.md](./COMPONENTS.md), which is also shipped inside the npm package for use with AI tools:
143
+
144
+ ```markdown
145
+ ## UI Components
146
+ @./node_modules/@retray-dev/ui-kit/COMPONENTS.md
147
+ ```
148
+
149
+ ## License
150
+
151
+ MIT © Julian Camilo Cruz Sanchez
package/dist/index.d.mts CHANGED
@@ -1,16 +1,75 @@
1
1
  import React from 'react';
2
- import { TouchableOpacityProps, TextProps as TextProps$1, TextInputProps } from 'react-native';
2
+ import { TouchableOpacityProps, TextProps as TextProps$1, TextInputProps, ViewStyle, TextStyle, ActivityIndicatorProps } from 'react-native';
3
+ export { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
4
+
5
+ type ThemeColors = {
6
+ background: string;
7
+ foreground: string;
8
+ card: string;
9
+ cardForeground: string;
10
+ primary: string;
11
+ primaryForeground: string;
12
+ secondary: string;
13
+ secondaryForeground: string;
14
+ muted: string;
15
+ mutedForeground: string;
16
+ accent: string;
17
+ accentForeground: string;
18
+ destructive: string;
19
+ destructiveForeground: string;
20
+ border: string;
21
+ input: string;
22
+ ring: string;
23
+ };
24
+ type Theme = {
25
+ light?: Partial<ThemeColors>;
26
+ dark?: Partial<ThemeColors>;
27
+ };
28
+ type ColorScheme = 'light' | 'dark' | 'system';
29
+ type ThemeContextValue = {
30
+ colors: ThemeColors;
31
+ colorScheme: 'light' | 'dark';
32
+ };
33
+
34
+ interface ThemeProviderProps {
35
+ children: React.ReactNode;
36
+ /**
37
+ * Override individual color tokens per scheme. Only provide the tokens you want
38
+ * to change — the rest fall back to the defaults.
39
+ * @example
40
+ * { light: { primary: '#6366f1', primaryForeground: '#fff' },
41
+ * dark: { primary: '#818cf8', primaryForeground: '#fff' } }
42
+ */
43
+ theme?: Theme;
44
+ /**
45
+ * - `'system'` (default): auto-detects device setting and updates when it changes.
46
+ * - `'light'` / `'dark'`: forces a specific scheme regardless of device setting.
47
+ */
48
+ colorScheme?: ColorScheme;
49
+ }
50
+ declare function ThemeProvider({ children, theme, colorScheme }: ThemeProviderProps): React.JSX.Element;
51
+ declare function useTheme(): ThemeContextValue;
52
+
53
+ declare const defaultLight: ThemeColors;
54
+ declare const defaultDark: ThemeColors;
3
55
 
4
56
  type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost';
5
57
  type ButtonSize = 'sm' | 'md' | 'lg';
6
58
  interface ButtonProps extends TouchableOpacityProps {
7
59
  label: string;
60
+ /**
61
+ * - `primary`: filled with `primary` token — main CTA
62
+ * - `secondary`: filled with `secondary` token — less prominent
63
+ * - `outline`: transparent with border — alternative actions
64
+ * - `ghost`: fully transparent — in-context or low-emphasis actions
65
+ */
8
66
  variant?: ButtonVariant;
9
67
  size?: ButtonSize;
68
+ /** Replaces the label with a spinner and forces `disabled`. */
10
69
  loading?: boolean;
11
70
  fullWidth?: boolean;
12
71
  }
13
- declare function Button({ label, variant, size, loading, fullWidth, disabled, style, ...props }: ButtonProps): React.JSX.Element;
72
+ declare function Button({ label, variant, size, loading, fullWidth, disabled, style, onPress, ...props }: ButtonProps): React.JSX.Element;
14
73
 
15
74
  type TextVariant = 'h1' | 'h2' | 'h3' | 'body' | 'caption' | 'label';
16
75
  interface TextProps extends TextProps$1 {
@@ -26,4 +85,251 @@ interface InputProps extends TextInputProps {
26
85
  }
27
86
  declare function Input({ label, error, hint, style, onFocus, onBlur, ...props }: InputProps): React.JSX.Element;
28
87
 
29
- export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, Text, type TextProps, type TextVariant };
88
+ type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline';
89
+ interface BadgeProps {
90
+ label: string;
91
+ variant?: BadgeVariant;
92
+ style?: ViewStyle;
93
+ }
94
+ declare function Badge({ label, variant, style }: BadgeProps): React.JSX.Element;
95
+
96
+ interface CardProps {
97
+ children: React.ReactNode;
98
+ style?: ViewStyle;
99
+ }
100
+ interface CardHeaderProps {
101
+ children: React.ReactNode;
102
+ style?: ViewStyle;
103
+ }
104
+ interface CardTitleProps {
105
+ children: React.ReactNode;
106
+ style?: TextStyle;
107
+ }
108
+ interface CardDescriptionProps {
109
+ children: React.ReactNode;
110
+ style?: TextStyle;
111
+ }
112
+ interface CardContentProps {
113
+ children: React.ReactNode;
114
+ style?: ViewStyle;
115
+ }
116
+ interface CardFooterProps {
117
+ children: React.ReactNode;
118
+ style?: ViewStyle;
119
+ }
120
+ declare function Card({ children, style }: CardProps): React.JSX.Element;
121
+ declare function CardHeader({ children, style }: CardHeaderProps): React.JSX.Element;
122
+ declare function CardTitle({ children, style }: CardTitleProps): React.JSX.Element;
123
+ declare function CardDescription({ children, style }: CardDescriptionProps): React.JSX.Element;
124
+ declare function CardContent({ children, style }: CardContentProps): React.JSX.Element;
125
+ declare function CardFooter({ children, style }: CardFooterProps): React.JSX.Element;
126
+
127
+ interface SeparatorProps {
128
+ orientation?: 'horizontal' | 'vertical';
129
+ style?: ViewStyle;
130
+ }
131
+ declare function Separator({ orientation, style }: SeparatorProps): React.JSX.Element;
132
+
133
+ type SpinnerSize = 'sm' | 'md' | 'lg';
134
+ interface SpinnerProps extends Omit<ActivityIndicatorProps, 'size'> {
135
+ size?: SpinnerSize;
136
+ color?: string;
137
+ }
138
+ declare function Spinner({ size, color, ...props }: SpinnerProps): React.JSX.Element;
139
+
140
+ interface SkeletonProps {
141
+ width?: number | string;
142
+ height?: number;
143
+ borderRadius?: number;
144
+ style?: ViewStyle;
145
+ }
146
+ declare function Skeleton({ width, height, borderRadius, style }: SkeletonProps): React.JSX.Element;
147
+
148
+ type AvatarSize = 'sm' | 'md' | 'lg' | 'xl';
149
+ interface AvatarProps {
150
+ src?: string;
151
+ fallback?: string;
152
+ size?: AvatarSize;
153
+ style?: ViewStyle;
154
+ }
155
+ declare function Avatar({ src, fallback, size, style }: AvatarProps): React.JSX.Element;
156
+
157
+ type AlertVariant = 'default' | 'destructive';
158
+ interface AlertProps {
159
+ title?: string;
160
+ description?: string;
161
+ variant?: AlertVariant;
162
+ icon?: React.ReactNode;
163
+ style?: ViewStyle;
164
+ }
165
+ declare function Alert({ title, description, variant, icon, style }: AlertProps): React.JSX.Element;
166
+
167
+ interface ProgressProps {
168
+ value?: number;
169
+ max?: number;
170
+ style?: ViewStyle;
171
+ }
172
+ declare function Progress({ value, max, style }: ProgressProps): React.JSX.Element;
173
+
174
+ interface EmptyStateProps {
175
+ icon?: React.ReactNode;
176
+ title: string;
177
+ description?: string;
178
+ action?: React.ReactNode;
179
+ style?: ViewStyle;
180
+ }
181
+ declare function EmptyState({ icon, title, description, action, style }: EmptyStateProps): React.JSX.Element;
182
+
183
+ interface TextareaProps extends TextInputProps {
184
+ label?: string;
185
+ error?: string;
186
+ hint?: string;
187
+ rows?: number;
188
+ }
189
+ declare function Textarea({ label, error, hint, rows, style, onFocus, onBlur, ...props }: TextareaProps): React.JSX.Element;
190
+
191
+ interface CheckboxProps {
192
+ checked?: boolean;
193
+ onCheckedChange?: (checked: boolean) => void;
194
+ label?: string;
195
+ disabled?: boolean;
196
+ style?: ViewStyle;
197
+ }
198
+ declare function Checkbox({ checked, onCheckedChange, label, disabled, style }: CheckboxProps): React.JSX.Element;
199
+
200
+ interface SwitchProps {
201
+ checked?: boolean;
202
+ onCheckedChange?: (checked: boolean) => void;
203
+ disabled?: boolean;
204
+ style?: ViewStyle;
205
+ }
206
+ declare function Switch({ checked, onCheckedChange, disabled, style }: SwitchProps): React.JSX.Element;
207
+
208
+ type ToggleVariant = 'default' | 'outline';
209
+ type ToggleSize = 'sm' | 'md' | 'lg';
210
+ interface ToggleProps extends TouchableOpacityProps {
211
+ pressed?: boolean;
212
+ onPressedChange?: (pressed: boolean) => void;
213
+ variant?: ToggleVariant;
214
+ size?: ToggleSize;
215
+ label?: string;
216
+ icon?: React.ReactNode;
217
+ }
218
+ declare function Toggle({ pressed, onPressedChange, variant, size, label, icon, disabled, style, ...props }: ToggleProps): React.JSX.Element;
219
+
220
+ interface RadioOption {
221
+ label: string;
222
+ value: string;
223
+ disabled?: boolean;
224
+ }
225
+ interface RadioGroupProps {
226
+ options: RadioOption[];
227
+ value?: string;
228
+ onValueChange?: (value: string) => void;
229
+ orientation?: 'vertical' | 'horizontal';
230
+ style?: ViewStyle;
231
+ }
232
+ declare function RadioGroup({ options, value, onValueChange, orientation, style, }: RadioGroupProps): React.JSX.Element;
233
+
234
+ interface TabItem {
235
+ label: string;
236
+ value: string;
237
+ }
238
+ interface TabsProps {
239
+ tabs: TabItem[];
240
+ value?: string;
241
+ onValueChange?: (value: string) => void;
242
+ children?: React.ReactNode;
243
+ style?: ViewStyle;
244
+ }
245
+ interface TabsContentProps {
246
+ value: string;
247
+ activeValue: string;
248
+ children: React.ReactNode;
249
+ style?: ViewStyle;
250
+ }
251
+ declare function Tabs({ tabs, value, onValueChange, children, style }: TabsProps): React.JSX.Element;
252
+ declare function TabsContent({ value, activeValue, children, style }: TabsContentProps): React.JSX.Element | null;
253
+
254
+ interface AccordionItem {
255
+ value: string;
256
+ trigger: string;
257
+ content: React.ReactNode;
258
+ }
259
+ interface AccordionProps {
260
+ items: AccordionItem[];
261
+ /**
262
+ * - `'single'` (default): only one item can be open at a time. Opening another closes the current one.
263
+ * - `'multiple'`: any number of items can be open simultaneously.
264
+ */
265
+ type?: 'single' | 'multiple';
266
+ /** Item value(s) that should be open on first render. */
267
+ defaultValue?: string | string[];
268
+ style?: ViewStyle;
269
+ }
270
+ declare function Accordion({ items, type, defaultValue, style }: AccordionProps): React.JSX.Element;
271
+
272
+ interface SliderProps {
273
+ value?: number;
274
+ minimumValue?: number;
275
+ maximumValue?: number;
276
+ step?: number;
277
+ onValueChange?: (value: number) => void;
278
+ onSlidingComplete?: (value: number) => void;
279
+ disabled?: boolean;
280
+ style?: ViewStyle;
281
+ }
282
+ declare function Slider({ value, minimumValue, maximumValue, step, onValueChange, onSlidingComplete, disabled, style, }: SliderProps): React.JSX.Element;
283
+
284
+ interface SheetProps {
285
+ open: boolean;
286
+ onClose: () => void;
287
+ title?: string;
288
+ description?: string;
289
+ children?: React.ReactNode;
290
+ snapPoints?: (string | number)[];
291
+ style?: ViewStyle;
292
+ }
293
+ declare function Sheet({ open, onClose, title, description, children, snapPoints, style, }: SheetProps): React.JSX.Element;
294
+
295
+ interface SelectOption {
296
+ label: string;
297
+ value: string;
298
+ disabled?: boolean;
299
+ }
300
+ interface SelectProps {
301
+ options: SelectOption[];
302
+ value?: string;
303
+ onValueChange?: (value: string) => void;
304
+ placeholder?: string;
305
+ label?: string;
306
+ error?: string;
307
+ disabled?: boolean;
308
+ style?: ViewStyle;
309
+ }
310
+ declare function Select({ options, value, onValueChange, placeholder, label, error, disabled, style, }: SelectProps): React.JSX.Element;
311
+
312
+ type ToastVariant = 'default' | 'destructive' | 'success';
313
+ interface ToastItem {
314
+ id: string;
315
+ title?: string;
316
+ description?: string;
317
+ variant?: ToastVariant;
318
+ duration?: number;
319
+ }
320
+ interface ToastContextValue {
321
+ toast: (item: Omit<ToastItem, 'id'>) => void;
322
+ dismiss: (id: string) => void;
323
+ }
324
+ declare function useToast(): ToastContextValue;
325
+ /**
326
+ * Must wrap the app root alongside ThemeProvider.
327
+ * Renders toasts in an absolute overlay at the top of the screen.
328
+ * Use `useToast()` anywhere inside to trigger toasts.
329
+ */
330
+ interface ToastProviderProps {
331
+ children: React.ReactNode;
332
+ }
333
+ declare function ToastProvider({ children }: ToastProviderProps): React.JSX.Element;
334
+
335
+ export { Accordion, type AccordionItem, type AccordionProps, Alert, type AlertProps, type AlertVariant, Avatar, type AvatarProps, type AvatarSize, Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardContent, type CardContentProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, Checkbox, type CheckboxProps, type ColorScheme, EmptyState, type EmptyStateProps, Input, type InputProps, Progress, type ProgressProps, RadioGroup, type RadioGroupProps, type RadioOption, Select, type SelectOption, type SelectProps, Separator, type SeparatorProps, Sheet, type SheetProps, Skeleton, type SkeletonProps, Slider, type SliderProps, Spinner, type SpinnerProps, type SpinnerSize, Switch, type SwitchProps, type TabItem, Tabs, TabsContent, type TabsContentProps, type TabsProps, Text, type TextProps, type TextVariant, Textarea, type TextareaProps, type Theme, type ThemeColors, ThemeProvider, type ThemeProviderProps, type ToastItem, ToastProvider, type ToastProviderProps, type ToastVariant, Toggle, type ToggleProps, type ToggleSize, type ToggleVariant, defaultDark, defaultLight, useTheme, useToast };