@masumdev/rn-ui 0.1.5 → 0.1.7

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 (90) hide show
  1. package/README.md +47 -1744
  2. package/lib/commonjs/components/AlertDialog.js.map +1 -1
  3. package/lib/commonjs/components/AspectRatio.js.map +1 -1
  4. package/lib/commonjs/components/Avatar.js.map +1 -1
  5. package/lib/commonjs/components/Badge.js +7 -2
  6. package/lib/commonjs/components/Badge.js.map +1 -1
  7. package/lib/commonjs/components/Button.js.map +1 -1
  8. package/lib/commonjs/components/ButtonGroup.js +2 -4
  9. package/lib/commonjs/components/ButtonGroup.js.map +1 -1
  10. package/lib/commonjs/components/Calendar.js.map +1 -1
  11. package/lib/commonjs/components/FloatingActionButton.js.map +1 -1
  12. package/lib/commonjs/components/IconButton.js.map +1 -1
  13. package/lib/commonjs/components/Progress.js +3 -1
  14. package/lib/commonjs/components/Progress.js.map +1 -1
  15. package/lib/commonjs/components/Rating.js +376 -0
  16. package/lib/commonjs/components/Rating.js.map +1 -0
  17. package/lib/commonjs/components/index.js +14 -0
  18. package/lib/commonjs/components/index.js.map +1 -1
  19. package/lib/commonjs/components/types.js +37 -0
  20. package/lib/commonjs/components/types.js.map +1 -1
  21. package/lib/commonjs/theme/tokens.js +8 -0
  22. package/lib/commonjs/theme/tokens.js.map +1 -1
  23. package/lib/module/components/AlertDialog.js.map +1 -1
  24. package/lib/module/components/AspectRatio.js.map +1 -1
  25. package/lib/module/components/Avatar.js.map +1 -1
  26. package/lib/module/components/Badge.js +7 -2
  27. package/lib/module/components/Badge.js.map +1 -1
  28. package/lib/module/components/Button.js.map +1 -1
  29. package/lib/module/components/ButtonGroup.js +3 -5
  30. package/lib/module/components/ButtonGroup.js.map +1 -1
  31. package/lib/module/components/Calendar.js.map +1 -1
  32. package/lib/module/components/FloatingActionButton.js.map +1 -1
  33. package/lib/module/components/IconButton.js.map +1 -1
  34. package/lib/module/components/Progress.js +3 -1
  35. package/lib/module/components/Progress.js.map +1 -1
  36. package/lib/module/components/Rating.js +370 -0
  37. package/lib/module/components/Rating.js.map +1 -0
  38. package/lib/module/components/index.js +2 -0
  39. package/lib/module/components/index.js.map +1 -1
  40. package/lib/module/components/types.js +37 -0
  41. package/lib/module/components/types.js.map +1 -1
  42. package/lib/module/theme/tokens.js +8 -0
  43. package/lib/module/theme/tokens.js.map +1 -1
  44. package/lib/typescript/commonjs/components/AlertDialog.d.ts +2 -3
  45. package/lib/typescript/commonjs/components/AlertDialog.d.ts.map +1 -1
  46. package/lib/typescript/commonjs/components/AspectRatio.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/components/Badge.d.ts +3 -6
  48. package/lib/typescript/commonjs/components/Badge.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/components/Button.d.ts +5 -11
  50. package/lib/typescript/commonjs/components/Button.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/components/ButtonGroup.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/components/FloatingActionButton.d.ts +2 -5
  53. package/lib/typescript/commonjs/components/FloatingActionButton.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/components/IconButton.d.ts +3 -6
  55. package/lib/typescript/commonjs/components/IconButton.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/components/Progress.d.ts +3 -2
  57. package/lib/typescript/commonjs/components/Progress.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/components/Rating.d.ts +62 -0
  59. package/lib/typescript/commonjs/components/Rating.d.ts.map +1 -0
  60. package/lib/typescript/commonjs/components/index.d.ts +4 -1
  61. package/lib/typescript/commonjs/components/index.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/components/types.d.ts +75 -0
  63. package/lib/typescript/commonjs/components/types.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/theme/tokens.d.ts.map +1 -1
  65. package/lib/typescript/commonjs/theme/types.d.ts +3 -0
  66. package/lib/typescript/commonjs/theme/types.d.ts.map +1 -1
  67. package/lib/typescript/module/components/AlertDialog.d.ts +2 -3
  68. package/lib/typescript/module/components/AlertDialog.d.ts.map +1 -1
  69. package/lib/typescript/module/components/AspectRatio.d.ts.map +1 -1
  70. package/lib/typescript/module/components/Badge.d.ts +3 -6
  71. package/lib/typescript/module/components/Badge.d.ts.map +1 -1
  72. package/lib/typescript/module/components/Button.d.ts +5 -11
  73. package/lib/typescript/module/components/Button.d.ts.map +1 -1
  74. package/lib/typescript/module/components/ButtonGroup.d.ts.map +1 -1
  75. package/lib/typescript/module/components/FloatingActionButton.d.ts +2 -5
  76. package/lib/typescript/module/components/FloatingActionButton.d.ts.map +1 -1
  77. package/lib/typescript/module/components/IconButton.d.ts +3 -6
  78. package/lib/typescript/module/components/IconButton.d.ts.map +1 -1
  79. package/lib/typescript/module/components/Progress.d.ts +3 -2
  80. package/lib/typescript/module/components/Progress.d.ts.map +1 -1
  81. package/lib/typescript/module/components/Rating.d.ts +62 -0
  82. package/lib/typescript/module/components/Rating.d.ts.map +1 -0
  83. package/lib/typescript/module/components/index.d.ts +4 -1
  84. package/lib/typescript/module/components/index.d.ts.map +1 -1
  85. package/lib/typescript/module/components/types.d.ts +75 -0
  86. package/lib/typescript/module/components/types.d.ts.map +1 -1
  87. package/lib/typescript/module/theme/tokens.d.ts.map +1 -1
  88. package/lib/typescript/module/theme/types.d.ts +3 -0
  89. package/lib/typescript/module/theme/types.d.ts.map +1 -1
  90. package/package.json +11 -1
package/README.md CHANGED
@@ -1,95 +1,56 @@
1
1
  # @masumdev/rn-ui
2
2
 
3
- Reusable React Native UI kit with typed theme tokens, flat light/dark mode, pluggable persistence, pluggable fonts, and composable core components.
3
+ > A modern, flat-designed React Native & Expo UI kit with 55+ typed components, dynamic light/dark theme engine, zero-shadow defaults, and pluggable architecture.
4
4
 
5
- `@masumdev/rn-ui` is designed for Expo and React Native apps that want a consistent flat UI system without tying the library to app-specific choices such as navigation, storage, icon packs, haptics, or analytics.
5
+ [![npm version](https://img.shields.io/npm/v/@masumdev/rn-ui.svg)](https://www.npmjs.com/package/@masumdev/rn-ui)
6
+ [![license](https://img.shields.io/npm/l/@masumdev/rn-ui.svg)](./LICENSE)
6
7
 
7
- ## What You Get
8
+ ---
8
9
 
9
- - Flat, border-based components with no shadow/elevation by default.
10
- - Light, dark, and system color-scheme support.
11
- - Typed theme tokens for colors, fonts, typography, spacing, radius, shadows, and component sizing.
12
- - Pluggable theme persistence through a tiny storage adapter.
13
- - Pluggable fonts through theme tokens.
14
- - Pluggable icons through render functions or React nodes.
15
- - Reanimated-powered component interactions.
16
- - Mobile-first primitives for forms, feedback, overlays, data display, and local navigation UI.
10
+ ## 📚 Full Documentation
17
11
 
18
- ## Requirements
12
+ Comprehensive guides, component previews, prop tables, and interactive examples are available in our official documentation:
19
13
 
20
- Minimum runtime expectations:
14
+ 👉 **[Explore Full Documentation & Component Catalog](https://react-native-library-docs.netlify.app/rn-ui)**
21
15
 
22
- - React Native app or Expo app.
23
- - React and React Native installed by the app.
24
- - `react-native-reanimated` and `react-native-worklets`.
25
- - `react-native-gesture-handler` and `GestureHandlerRootView` at the app root for gesture-driven components such as `Slider` and Gorhom-based sheets.
16
+ - 📖 **[Installation Guide](https://react-native-library-docs.netlify.app/rn-ui/installation)**
17
+ - 🎨 **[Theming & Dark Mode](https://react-native-library-docs.netlify.app/rn-ui/theming)**
18
+ - 🧩 **[55+ Component Catalog](https://react-native-library-docs.netlify.app/rn-ui/components)**
19
+ - 🛠️ **[Building Custom Components](https://react-native-library-docs.netlify.app/rn-ui/custom-components)**
20
+ - 📜 **[Architectural Rules](./RULES.md)**
21
+ - 🚀 **[Changelog](https://react-native-library-docs.netlify.app/rn-ui/changelog)**
26
22
 
27
- This package currently ships a single root export that includes every component. Because `Calendar` and `BottomSheet` are exported from the root package, install their peer dependencies too when consuming the package from npm:
23
+ ---
28
24
 
29
- - `react-native-calendars`
30
- - `@gorhom/bottom-sheet`
25
+ ## ✨ Features
31
26
 
32
- Future versions may split optional integrations into subpath exports so these can become truly optional.
27
+ - **Flat Aesthetic**: Border-based, clean UI primitives with zero elevation/shadow by default.
28
+ - **Dynamic Theme Engine**: Light, dark, and system preference support via `ThemeProvider`.
29
+ - **55+ Typed Components**: Forms, feedback, overlays, navigation, data display, and chat UI primitives.
30
+ - **Pluggable Architecture**: Zero lock-in for fonts, icons, navigation, storage, or haptics.
31
+ - **Reanimated Powered**: Smooth 60fps micro-animations powered by `react-native-reanimated`.
32
+ - **Strict Type Safety**: 100% TypeScript with zero `any` types and shared base UI prop interfaces.
33
33
 
34
- ## Install
34
+ ---
35
35
 
36
- ### Expo
36
+ ## 📦 Quick Install
37
37
 
38
+ ### Expo
38
39
  ```sh
39
40
  npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler react-native-calendars
40
41
  bun add @masumdev/rn-ui @gorhom/bottom-sheet
41
42
  ```
42
43
 
43
- If you use npm instead of Bun:
44
-
45
- ```sh
46
- npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler react-native-calendars
47
- npm install @masumdev/rn-ui @gorhom/bottom-sheet
48
- ```
49
-
50
44
  ### React Native CLI
51
-
52
- Install the package and peer dependencies:
53
-
54
45
  ```sh
55
46
  bun add @masumdev/rn-ui react-native-reanimated react-native-worklets react-native-gesture-handler react-native-calendars @gorhom/bottom-sheet
56
47
  ```
57
48
 
58
- For iOS, run pods after installing native dependencies:
59
-
60
- ```sh
61
- cd ios
62
- pod install
63
- cd ..
64
- ```
65
-
66
- ## Setup
67
-
68
- ### 1. Add GestureHandlerRootView
69
-
70
- Wrap the app root with `GestureHandlerRootView`. This is required for gesture-driven components and `@gorhom/bottom-sheet`.
49
+ ---
71
50
 
72
- Expo Router example:
73
-
74
- ```tsx
75
- import { Stack } from "expo-router";
76
- import { GestureHandlerRootView } from "react-native-gesture-handler";
77
- import { ThemeProvider, ToastProvider } from "@masumdev/rn-ui";
78
-
79
- export default function RootLayout() {
80
- return (
81
- <GestureHandlerRootView style={{ flex: 1 }}>
82
- <ThemeProvider defaultColorScheme="system">
83
- <ToastProvider placement="bottom">
84
- <Stack screenOptions={{ headerShown: false }} />
85
- </ToastProvider>
86
- </ThemeProvider>
87
- </GestureHandlerRootView>
88
- );
89
- }
90
- ```
51
+ ## Quick Setup
91
52
 
92
- Plain React Native example:
53
+ Wrap your application root with `GestureHandlerRootView` and `ThemeProvider`:
93
54
 
94
55
  ```tsx
95
56
  import { GestureHandlerRootView } from "react-native-gesture-handler";
@@ -99,7 +60,7 @@ export default function App() {
99
60
  return (
100
61
  <GestureHandlerRootView style={{ flex: 1 }}>
101
62
  <ThemeProvider defaultColorScheme="system">
102
- <ToastProvider>
63
+ <ToastProvider placement="bottom">
103
64
  <RootNavigator />
104
65
  </ToastProvider>
105
66
  </ThemeProvider>
@@ -108,1697 +69,39 @@ export default function App() {
108
69
  }
109
70
  ```
110
71
 
111
- ### 2. Configure Reanimated
112
-
113
- Expo SDKs usually create the correct Babel setup, but if your app manages Babel manually, keep the Reanimated plugin last.
114
-
115
- ```js
116
- module.exports = function (api) {
117
- api.cache(true);
118
-
119
- return {
120
- presets: ["babel-preset-expo"],
121
- plugins: ["react-native-reanimated/plugin"],
122
- };
123
- };
124
- ```
125
-
126
- ### 3. Wrap Once With ThemeProvider
127
-
128
- `defaultColorScheme` accepts:
129
-
130
- - `light`
131
- - `dark`
132
- - `system`
133
-
134
- `system` follows the device color scheme through React Native `useColorScheme()`.
135
-
136
- `ThemeProvider` should live once near the app root. Components read tokens through context, so nested providers are only needed if a subtree intentionally uses a different theme.
137
-
138
- ### 4. Add ToastProvider When Using Toast
139
-
140
- `useToast()` requires `ToastProvider` above the screen/component that calls it.
141
-
142
- ```tsx
143
- import { ToastProvider } from "@masumdev/rn-ui";
144
-
145
- <ToastProvider placement="bottom">
146
- <AppScreens />
147
- </ToastProvider>;
148
- ```
72
+ ---
149
73
 
150
- ## Usage
74
+ ## 🚀 Basic Usage
151
75
 
152
76
  ```tsx
153
- import { Badge, Box, Button, Card, Text, useTheme } from "@masumdev/rn-ui";
77
+ import React from "react";
78
+ import { Box, Card, Text, Badge, Button, useTheme } from "@masumdev/rn-ui";
154
79
 
155
- export function Example() {
156
- const { setColorScheme, toggleColorScheme } = useTheme();
80
+ export function ExampleScreen() {
81
+ const { toggleColorScheme } = useTheme();
157
82
 
158
83
  return (
159
- <Box flex={1} bg="background" p="lg" gap="md">
160
- <Card>
161
- <Badge tone="success">Active</Badge>
162
- <Text variant="h3">Reusable UI</Text>
163
- <Text color="textMuted">
164
- Theme tokens keep spacing, color, typography, and radius consistent.
84
+ <Box flex={1} bg="background" p="lg" gap="md" justify="center">
85
+ <Card elevated>
86
+ <Box row justify="space-between" align="center">
87
+ <Text variant="h3">@masumdev/rn-ui</Text>
88
+ <Badge tone="success">Active</Badge>
89
+ </Box>
90
+ <Text color="textMuted" style={{ marginTop: 8 }}>
91
+ Flat, token-driven React Native components built for speed and type-safety.
165
92
  </Text>
166
93
  </Card>
167
94
 
168
- <Button fullWidth onPress={toggleColorScheme}>
169
- Toggle Theme
170
- </Button>
171
-
172
- <Button variant="outline" onPress={() => setColorScheme("system")}>
173
- Follow System
95
+ <Button tone="primary" variant="filled" fullWidth onPress={toggleColorScheme}>
96
+ Toggle Theme Mode
174
97
  </Button>
175
98
  </Box>
176
99
  );
177
100
  }
178
101
  ```
179
102
 
180
- ## Custom Theme
181
-
182
- Override only the tokens you need. The library deep-merges your values with the default light and dark themes.
183
-
184
- When changing `primary`, also set `primarySoft`, `primaryStrong`, and `onPrimary` so filled buttons, soft badges, sliders, switches, focus states, and selected controls stay readable in both modes.
185
-
186
- ```tsx
187
- import { ThemeProvider } from "@masumdev/rn-ui";
188
-
189
- const themes = {
190
- light: {
191
- colors: {
192
- background: "#F6FBFC",
193
- surface: "#FFFFFF",
194
- text: "#06202A",
195
- textMuted: "#476371",
196
- primary: "#06B6D4",
197
- primarySoft: "#CFFAFE",
198
- primaryStrong: "#0891B2",
199
- onPrimary: "#06202A",
200
- accent: "#F43F5E",
201
- accentSoft: "#FFE4E6",
202
- border: "#B8D4DD",
203
- borderMuted: "#D8E8EE",
204
- },
205
- fonts: {
206
- regular: "OutfitRegular",
207
- medium: "OutfitMedium",
208
- semibold: "OutfitSemiBold",
209
- bold: "OutfitBold",
210
- },
211
- typography: {
212
- body: {
213
- fontSize: 16,
214
- },
215
- label: {
216
- letterSpacing: 0.2,
217
- },
218
- },
219
- radii: {
220
- lg: 14,
221
- xl: 18,
222
- },
223
- },
224
- dark: {
225
- colors: {
226
- background: "#06141B",
227
- surface: "#0B202A",
228
- text: "#F2FBFD",
229
- textMuted: "#B7CDD5",
230
- primary: "#67E8F9",
231
- primarySoft: "#164E63",
232
- primaryStrong: "#A5F3FC",
233
- onPrimary: "#06202A",
234
- accent: "#FB7185",
235
- accentSoft: "#4C1220",
236
- border: "#2A5260",
237
- borderMuted: "#173441",
238
- },
239
- },
240
- };
241
-
242
- export function App() {
243
- return (
244
- <ThemeProvider defaultColorScheme="system" themes={themes}>
245
- <RootNavigator />
246
- </ThemeProvider>
247
- );
248
- }
249
- ```
250
-
251
- Common tokens:
252
-
253
- - `colors.background`: screen background.
254
- - `colors.surface`: cards, menus, sheets, and panels.
255
- - `colors.text`, `textMuted`, `textSubtle`: text hierarchy.
256
- - `colors.primary`, `primarySoft`, `primaryStrong`, `onPrimary`: main action color system.
257
- - `colors.border`, `borderMuted`, `divider`: flat border system.
258
- - `spacing`: named spacing scale used by layout primitives.
259
- - `radii`: corner radius scale.
260
- - `typography`: text variants used by `Text`.
261
- - `components`: component-specific sizes such as `button`, `iconButton`, `switch`, `slider`, and `floatingActionButton`.
262
-
263
- ## Fonts
264
-
265
- Fonts are pluggable. `rn-ui` does not load font files by itself, so it works with Expo Font, local TTF files, React Native CLI font linking, or any other font-loading setup.
266
-
267
- Load the font in your app, then pass the registered font names through the `fonts` token.
268
-
269
- ```tsx
270
- import { useFonts } from "expo-font";
271
- import { ThemeProvider } from "@masumdev/rn-ui";
272
-
273
- const themes = {
274
- light: {
275
- fonts: {
276
- regular: "OutfitRegular",
277
- medium: "OutfitMedium",
278
- semibold: "OutfitSemiBold",
279
- bold: "OutfitBold",
280
- mono: "SpaceMono",
281
- },
282
- },
283
- dark: {
284
- fonts: {
285
- regular: "OutfitRegular",
286
- medium: "OutfitMedium",
287
- semibold: "OutfitSemiBold",
288
- bold: "OutfitBold",
289
- mono: "SpaceMono",
290
- },
291
- },
292
- };
293
-
294
- export function App() {
295
- const [loaded] = useFonts({
296
- OutfitRegular: require("./assets/fonts/Outfit-Regular.ttf"),
297
- OutfitMedium: require("./assets/fonts/Outfit-Medium.ttf"),
298
- OutfitSemiBold: require("./assets/fonts/Outfit-SemiBold.ttf"),
299
- OutfitBold: require("./assets/fonts/Outfit-Bold.ttf"),
300
- });
301
-
302
- if (!loaded) return null;
303
-
304
- return (
305
- <ThemeProvider themes={themes}>
306
- <RootNavigator />
307
- </ThemeProvider>
308
- );
309
- }
310
- ```
311
-
312
- Default mapping:
313
-
314
- - `display`, `h1`, `h2` use `fonts.bold`
315
- - `h3`, `title`, `subtitle` use `fonts.semibold`
316
- - `label`, `labelSmall` use `fonts.semibold` or `fonts.medium`
317
- - `body`, `bodySmall`, `caption` use `fonts.regular`
318
-
319
- You can still override one typography variant directly:
320
-
321
- ```tsx
322
- const themes = {
323
- light: {
324
- typography: {
325
- h1: {
326
- fontFamily: "CustomDisplayBold",
327
- fontSize: 34,
328
- lineHeight: 42,
329
- },
330
- },
331
- },
332
- };
333
- ```
334
-
335
- ## Persisting Theme Choice
336
-
337
- The core package does not depend on AsyncStorage, SQLite, Expo SecureStore, MMKV, or Zustand. Pass a small adapter from your app.
338
-
339
- `ThemeProvider` waits for storage hydration by default, so the app can avoid rendering light mode before the saved dark mode is loaded.
340
-
341
- ### Expo SecureStore
342
-
343
- ```tsx
344
- import * as SecureStore from "expo-secure-store";
345
- import { ThemeProvider } from "@masumdev/rn-ui";
346
-
347
- const storage = {
348
- getItem: (key: string) => SecureStore.getItemAsync(key),
349
- setItem: (key: string, value: string) => SecureStore.setItemAsync(key, value),
350
- };
351
-
352
- export function App() {
353
- return (
354
- <ThemeProvider storage={storage} defaultColorScheme="system">
355
- <RootNavigator />
356
- </ThemeProvider>
357
- );
358
- }
359
- ```
360
-
361
- ### AsyncStorage
362
-
363
- ```tsx
364
- import AsyncStorage from "@react-native-async-storage/async-storage";
365
- import { ThemeProvider } from "@masumdev/rn-ui";
366
-
367
- const storage = {
368
- getItem: (key: string) => AsyncStorage.getItem(key),
369
- setItem: (key: string, value: string) => AsyncStorage.setItem(key, value),
370
- };
371
-
372
- export function App() {
373
- return (
374
- <ThemeProvider storage={storage} defaultColorScheme="system">
375
- <RootNavigator />
376
- </ThemeProvider>
377
- );
378
- }
379
- ```
380
-
381
- Expo Go support depends on whether the chosen storage native module is available in the runtime. In the native playground, SecureStore is used because it works cleanly with the Expo workflow.
382
-
383
- ## Logging
384
-
385
- The library does not force logging. Apps can decide how noisy persistence logs should be.
386
-
387
- Recommended app pattern:
388
-
389
- ```tsx
390
- const ENABLE_THEME_DEBUG_LOGS = false;
391
-
392
- const debugTheme = (...args: unknown[]) => {
393
- if (__DEV__ && ENABLE_THEME_DEBUG_LOGS) {
394
- console.debug("[rn-ui]", ...args);
395
- }
396
- };
397
-
398
- const errorTheme = (...args: unknown[]) => {
399
- console.error("[rn-ui]", ...args);
400
- };
401
- ```
402
-
403
- Use debug logs for successful hydrate/save messages and error logs for failed storage operations.
404
-
405
- ## Components
406
-
407
- Current core components:
408
-
409
- - `Box`
410
- - `Text`
411
- - `BottomSheet`
412
- - `Accordion`
413
- - `Alert`
414
- - `AlertDialog`
415
- - `Button`
416
- - `IconButton`
417
- - `Badge`
418
- - `Card`
419
- - `Divider`
420
- - `AspectRatio`
421
- - `Attachment`
422
- - `Avatar`
423
- - `Bubble`
424
- - `ButtonGroup`
425
- - `Calendar`
426
- - `Carousel`
427
- - `Checkbox`
428
- - `Collapsible`
429
- - `Combobox`
430
- - `ContextMenu`
431
- - `DropdownMenu`
432
- - `Empty`
433
- - `HoverCard`
434
- - `Input`
435
- - `InputGroup`
436
- - `InputOTP`
437
- - `Item`
438
- - `KeyboardAvoiding`
439
- - `Label`
440
- - `FormField`
441
- - `Switch`
442
- - `RadioGroup`
443
- - `Slider`
444
- - `Progress`
445
- - `Skeleton`
446
- - `Tabs`
447
- - `Stepper`
448
- - `Sheet`
449
- - `Toast`
450
- - `Textarea`
451
- - `Select`
452
- - `Command`
453
- - `Popover`
454
- - `Pagination`
455
- - `Breadcrumb`
456
- - `Table`
457
- - `DataList`
458
- - `Timeline`
459
- - `MetricCard`
460
- - `FloatingActionButton`
461
-
462
- Icons are intentionally not tied to Ionicons or Expo. Pass any React node or render function.
463
-
464
- ```tsx
465
- import { Button } from "@masumdev/rn-ui";
466
- import { Ionicons } from "@expo/vector-icons";
467
-
468
- <Button
469
- leftIcon={({ color, size }) => (
470
- <Ionicons name="add" color={color} size={size} />
471
- )}
472
- >
473
- Create
474
- </Button>;
475
- ```
476
-
477
- ### Accordion
478
-
479
- Use `Accordion` for expandable flat bordered sections. It supports controlled and uncontrolled state.
480
-
481
- ```tsx
482
- import { Accordion, Text } from "@masumdev/rn-ui";
483
-
484
- <Accordion
485
- defaultOpenIds={["theme"]}
486
- items={[
487
- {
488
- id: "theme",
489
- title: "Theme tokens",
490
- subtitle: "Colors, fonts, spacing, and radius",
491
- content: "Accordion follows the same flat token-driven style.",
492
- },
493
- {
494
- id: "icons",
495
- title: "Generic icons",
496
- content: <Text color="textMuted">Icons can be render functions.</Text>,
497
- },
498
- ]}
499
- />;
500
- ```
501
-
502
- Controlled:
503
-
504
- ```tsx
505
- const [openIds, setOpenIds] = React.useState(["theme"]);
506
-
507
- <Accordion
508
- openIds={openIds}
509
- onOpenChange={setOpenIds}
510
- allowMultiple
511
- items={items}
512
- />;
513
- ```
514
-
515
- Animation:
516
-
517
- - Default animation uses Reanimated.
518
- - Uses the package Reanimated peer dependency.
519
- - Content animates height and opacity.
520
- - Indicator animates rotation.
521
- - Pass `animated={false}` to disable animation.
522
- - Pass `animationDuration` to tune timing.
523
-
524
- ```tsx
525
- <Accordion animationDuration={220} defaultOpenIds={["theme"]} items={items} />
526
- ```
527
-
528
- Custom animation can be plugged in through `animationComponents`:
529
-
530
- ```tsx
531
- import type {
532
- AccordionAnimatedContentProps,
533
- AccordionAnimatedIndicatorProps,
534
- } from "@masumdev/rn-ui";
535
-
536
- function CustomAccordionContent(props: AccordionAnimatedContentProps) {
537
- return <YourAnimatedContent {...props} />;
538
- }
539
-
540
- function CustomAccordionIndicator(props: AccordionAnimatedIndicatorProps) {
541
- return <YourAnimatedIndicator {...props} />;
542
- }
543
-
544
- <Accordion
545
- items={items}
546
- animationComponents={{
547
- Content: CustomAccordionContent,
548
- Indicator: CustomAccordionIndicator,
549
- }}
550
- />;
551
- ```
552
-
553
- ### Button
554
-
555
- Use `Button` for text and icon actions. `variant` controls visual treatment, while `tone` controls semantic color.
556
-
557
- ```tsx
558
- <Button variant="filled" tone="primary">
559
- Continue
560
- </Button>
561
-
562
- <Button variant="outline" tone="secondary">
563
- Cancel
564
- </Button>
565
-
566
- <Button tone="danger">Delete</Button>
567
- ```
568
-
569
- `variant="danger"` is still accepted for older usage, but new code should prefer `tone="danger"` so variants stay visual-only.
570
-
571
- ### IconButton
572
-
573
- Use `IconButton` for icon-only actions. Use `tone` for semantic token colors, or `color` for a token name/custom color override.
574
-
575
- ```tsx
576
- <IconButton
577
- icon={({ color, size }) => <Settings color={color} size={size} />}
578
- variant="outline"
579
- tone="secondary"
580
- />
581
-
582
- <IconButton
583
- icon={({ color, size }) => <Trash color={color} size={size} />}
584
- tone="danger"
585
- />
586
- ```
587
-
588
- ### BottomSheet
589
-
590
- Use `BottomSheet` for a theme-aware wrapper around `@gorhom/bottom-sheet`. The app must install Gorhom and its runtime peers.
591
-
592
- ```sh
593
- bun add @gorhom/bottom-sheet react-native-gesture-handler
594
- ```
595
-
596
- Wrap the app root with `GestureHandlerRootView` at app level:
597
-
598
- ```tsx
599
- import { GestureHandlerRootView } from "react-native-gesture-handler";
600
-
601
- <GestureHandlerRootView style={{ flex: 1 }}>
602
- <ThemeProvider>
603
- <App />
604
- </ThemeProvider>
605
- </GestureHandlerRootView>;
606
- ```
607
-
608
- If the app uses Reanimated 4, add the Worklets Babel plugin in the app config:
609
-
610
- ```js
611
- module.exports = function (api) {
612
- api.cache(true);
613
-
614
- return {
615
- presets: ["babel-preset-expo"],
616
- plugins: ["react-native-reanimated/plugin"],
617
- };
618
- };
619
- ```
620
-
621
- Use the themed wrapper:
622
-
623
- ```tsx
624
- import {
625
- BottomSheet,
626
- BottomSheetView,
627
- Button,
628
- Text,
629
- type BottomSheetMethods,
630
- } from '@masumdev/rn-ui';
631
-
632
- const bottomSheetRef = React.useRef<BottomSheetMethods>(null);
633
- const snapPoints = React.useMemo(() => ['35%', '70%'], []);
634
-
635
- <Button onPress={() => bottomSheetRef.current?.snapToIndex(0)}>
636
- Open Sheet
637
- </Button>
638
-
639
- <BottomSheet
640
- ref={bottomSheetRef}
641
- index={-1}
642
- snapPoints={snapPoints}
643
- enablePanDownToClose
644
- >
645
- <BottomSheetView>
646
- <Text variant="title">Theme-aware sheet</Text>
647
- </BottomSheetView>
648
- </BottomSheet>
649
- ```
650
-
651
- The wrapper maps theme tokens to Gorhom props:
652
-
653
- - `backgroundStyle` uses `colors.surface`, `colors.border`, and `radii.xxl`
654
- - `handleIndicatorStyle` uses `colors.border`
655
- - `style` keeps shadow/elevation at zero
656
- - `backdropComponent` defaults to a themed `BottomSheetBackdrop`
657
-
658
- Useful wrapper props:
659
-
660
- - `withBackdrop`
661
- - `backdropOpacity`
662
- - `backdropAppearsOnIndex`
663
- - `backdropDisappearsOnIndex`
664
- - `backdropPressBehavior`
665
- - `backdropStyle`
666
-
667
- Gorhom primitives are re-exported for convenience: `BottomSheetView`, `BottomSheetScrollView`, `BottomSheetFlatList`, `BottomSheetSectionList`, `BottomSheetTextInput`, `BottomSheetModal`, `BottomSheetModalProvider`, `useBottomSheet`, and `useBottomSheetModal`.
668
-
669
- ### Alert
670
-
671
- Use `Alert` for inline feedback. It supports semantic tones, flat variants, generic icons, optional action, and optional close control.
672
-
673
- ```tsx
674
- import { Alert } from "@masumdev/rn-ui";
675
-
676
- <Alert tone="info" title="Information">
677
- This message uses theme tokens and adapts to light or dark mode.
678
- </Alert>;
679
- ```
680
-
681
- With icon and action:
682
-
683
- ```tsx
684
- <Alert
685
- tone="success"
686
- variant="outline"
687
- icon={({ color, size }) => <Icon name="check" color={color} size={size} />}
688
- action={{
689
- label: "View details",
690
- onPress: openDetails,
691
- }}
692
- >
693
- Your changes were saved.
694
- </Alert>
695
- ```
696
-
697
- Dismissible alert:
698
-
699
- ```tsx
700
- <Alert
701
- tone="warning"
702
- title="Unsaved changes"
703
- dismissible
704
- closeIcon={({ color, size }) => <Icon name="x" color={color} size={size} />}
705
- >
706
- This alert removes itself when the close button is pressed.
707
- </Alert>
708
- ```
709
-
710
- `icon`, `action.icon`, and `closeIcon` are all pluggable through `RenderIcon`.
711
-
712
- Dismiss animations use Reanimated by default. Use `animated={false}` to disable or `animationDuration` to tune timing.
713
-
714
- ```tsx
715
- <Alert dismissible animationDuration={220}>
716
- Animated dismissible alert.
717
- </Alert>
718
- ```
719
-
720
- Action icons can be fully overridden, including custom open/close animation owned by the app:
721
-
722
- ```tsx
723
- <Alert
724
- action={{
725
- label: expanded ? "Hide details" : "View details",
726
- icon: ({ color, size }) => (
727
- <AnimatedChevron expanded={expanded} color={color} size={size} />
728
- ),
729
- onPress: () => setExpanded((value) => !value),
730
- }}
731
- >
732
- Alert content.
733
- </Alert>
734
- ```
735
-
736
- ### AlertDialog
737
-
738
- Use `AlertDialog` for modal confirmation and blocking feedback. It uses React Native `Modal` and Reanimated by default.
739
-
740
- ```tsx
741
- const [visible, setVisible] = React.useState(false);
742
-
743
- <Button onPress={() => setVisible(true)}>Delete</Button>
744
-
745
- <AlertDialog
746
- visible={visible}
747
- tone="danger"
748
- title="Delete item?"
749
- description="This action cannot be undone."
750
- confirmText="Delete"
751
- cancelText="Cancel"
752
- onConfirm={deleteItem}
753
- onCancel={() => setVisible(false)}
754
- onClose={() => setVisible(false)}
755
- />
756
- ```
757
-
758
- With pluggable icons:
759
-
760
- ```tsx
761
- <AlertDialog
762
- visible={visible}
763
- icon={({ color, size }) => <Trash color={color} size={size} />}
764
- closeIcon={({ color, size }) => <X color={color} size={size} />}
765
- onClose={() => setVisible(false)}
766
- />
767
- ```
768
-
769
- Useful props:
770
-
771
- - `dismissOnBackdropPress`
772
- - `confirmLoading`
773
- - `confirmDisabled`
774
- - `cancelDisabled`
775
- - `animated`
776
- - `animationDuration`
777
- - `modalProps`
778
-
779
- Android notes:
780
-
781
- - `AlertDialog` enables `statusBarTranslucent`, `navigationBarTranslucent`, and `hardwareAccelerated` by default so the backdrop can cover modern Android system UI areas more consistently.
782
- - If an app uses custom edge-to-edge or navigation bar handling, override native modal behavior through `modalProps`.
783
- - Android navigation bar behavior is controlled by system UI, not by the modal backdrop view. If the app needs to hide or style the navigation bar while a dialog is open, handle it at app level with the system UI solution already used by that app. `rn-ui` does not depend on Expo navigation-bar APIs.
784
-
785
- ### AspectRatio
786
-
787
- Use `AspectRatio` to display layout/media with a specific proportion. The child element automatically stretches to fill the container.
788
-
789
- ```tsx
790
- import { AspectRatio } from "@masumdev/rn-ui";
791
- import { Image } from "react-native";
792
-
793
- <AspectRatio ratio={16 / 9} radius="md">
794
- <Image
795
- source={{
796
- uri: "https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe",
797
- }}
798
- style={{ resizeMode: "cover" }}
799
- />
800
- </AspectRatio>;
801
- ```
802
-
803
- ### Attachment
804
-
805
- Use `Attachment` to represent file/image uploads or documents. Supports grid-like `card` previews and full-width list `row` views with status indicators.
806
-
807
- ```tsx
808
- import { Attachment } from '@masumdev/rn-ui';
809
-
810
- // Card layout (Image preview)
811
- <Attachment
812
- layout="card"
813
- name="workspace.png"
814
- description="PNG • 820 KB"
815
- thumbnail="https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe"
816
- onRemove={removeFile}
817
- />
818
-
819
- // Row layout (Document preview)
820
- <Attachment
821
- layout="row"
822
- name="sales-dashboard.pdf"
823
- description="Uploading • 64%"
824
- descriptionTone="info"
825
- loading
826
- onRemove={removeFile}
827
- />
828
- ```
829
-
830
- `descriptionTone` accepts `default`, `info`, `success`, `warning`, and `danger`. Use it instead of deriving visual state from description copy. `thumbnail`, `fileIcon`, and `closeIcon` are pluggable through `RenderIcon`.
831
-
832
- ### Avatar
833
-
834
- Use `Avatar` to display user profile images. Supports sizes (`sm`, `default`, `lg`), custom fallback placeholders, activity badges, and overlapping avatar groups.
835
-
836
- ```tsx
837
- import {
838
- Avatar,
839
- AvatarImage,
840
- AvatarFallback,
841
- AvatarBadge,
842
- AvatarGroup,
843
- AvatarGroupCount,
844
- } from '@masumdev/rn-ui';
845
-
846
- // Individual Avatar with Badge
847
- <Avatar size="lg">
848
- <AvatarImage source={{ uri: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb' }} />
849
- <AvatarFallback>JD</AvatarFallback>
850
- <AvatarBadge bg={colors.success} />
851
- </Avatar>
852
-
853
- // Avatar Group
854
- <AvatarGroup size="default">
855
- <Avatar>
856
- <AvatarImage source={{ uri: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb' }} />
857
- <AvatarFallback>JD</AvatarFallback>
858
- </Avatar>
859
- <Avatar>
860
- <AvatarImage source={{ uri: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d' }} />
861
- <AvatarFallback>AM</AvatarFallback>
862
- </Avatar>
863
- <AvatarGroupCount count={5} />
864
- </AvatarGroup>
865
- ```
866
-
867
- ### Bubble
868
-
869
- Use `BubbleGroup`, `Bubble`, `BubbleContent`, and `BubbleReactions` to display conversation bubbles (chat messages) with support for variants, alignments, and overlay reaction tags.
870
-
871
- ```tsx
872
- import {
873
- BubbleGroup,
874
- Bubble,
875
- BubbleContent,
876
- BubbleReactions,
877
- Text,
878
- } from "@masumdev/rn-ui";
879
-
880
- <BubbleGroup>
881
- {/* Incoming message */}
882
- <Bubble align="start" variant="secondary">
883
- <BubbleContent>Hello! How can I help you today?</BubbleContent>
884
- </Bubble>
885
-
886
- {/* Outgoing message with reactions */}
887
- <Bubble align="end" variant="default">
888
- <BubbleContent>I'd like to customize the colors of my theme.</BubbleContent>
889
- <BubbleReactions side="bottom" align="end">
890
- <Text style={{ fontSize: 11 }}>👍 1</Text>
891
- </BubbleReactions>
892
- </Bubble>
893
- </BubbleGroup>;
894
- ```
895
-
896
- ### ButtonGroup
897
-
898
- Use `ButtonGroup` to group buttons, static text containers, and separators horizontally or vertically with unified borders and border radii.
899
-
900
- ```tsx
901
- import {
902
- ButtonGroup,
903
- ButtonGroupText,
904
- ButtonGroupSeparator,
905
- Button,
906
- } from "@masumdev/rn-ui";
907
-
908
- <ButtonGroup orientation="horizontal">
909
- <ButtonGroupText>Prefix</ButtonGroupText>
910
- <Button variant="outline">Action A</Button>
911
- <ButtonGroupSeparator />
912
- <Button variant="outline">Action B</Button>
913
- </ButtonGroup>;
914
- ```
915
-
916
- ### Calendar
917
-
918
- Use `Calendar` to render date pickers and handle single date or range select.
919
-
920
- ```tsx
921
- import { Calendar } from "@masumdev/rn-ui";
922
-
923
- <Calendar
924
- markedDates={{
925
- "2026-07-12": { selected: true, startingDay: true },
926
- "2026-07-13": { selected: true, color: "muted" },
927
- "2026-07-14": { selected: true, endingDay: true },
928
- }}
929
- />;
930
- ```
931
-
932
- ### Carousel
933
-
934
- Use `Carousel` for horizontally scrollable card decks. Pagination is on by default and next/previous icons are pluggable.
935
-
936
- ```tsx
937
- import {
938
- Carousel,
939
- CarouselContent,
940
- CarouselItem,
941
- CarouselPrevious,
942
- CarouselNext,
943
- } from "@masumdev/rn-ui";
944
-
945
- <Carousel itemWidth={280}>
946
- <CarouselContent>
947
- <CarouselItem>
948
- <Card>
949
- <Text>Slide one</Text>
950
- </Card>
951
- </CarouselItem>
952
- <CarouselItem>
953
- <Card>
954
- <Text>Slide two</Text>
955
- </Card>
956
- </CarouselItem>
957
- </CarouselContent>
958
- <CarouselPrevious
959
- icon={({ color, size }) => <ChevronLeft color={color} size={size} />}
960
- />
961
- <CarouselNext
962
- icon={({ color, size }) => <ChevronRight color={color} size={size} />}
963
- />
964
- </Carousel>;
965
- ```
966
-
967
- ### Checkbox
968
-
969
- Use `Checkbox` for controlled boolean state. The check icon is pluggable.
970
-
971
- ```tsx
972
- <Checkbox
973
- checked={checked}
974
- onCheckedChange={setChecked}
975
- icon={({ color, size }) => <Check color={color} size={size} />}
976
- />
977
- ```
978
-
979
- ### Collapsible
980
-
981
- Use `Collapsible` for composable expandable content.
982
-
983
- ```tsx
984
- <Collapsible defaultOpen>
985
- <CollapsibleTrigger>
986
- <Text variant="label">Toggle details</Text>
987
- </CollapsibleTrigger>
988
- <CollapsibleContent>
989
- <Text color="textMuted">Hidden content.</Text>
990
- </CollapsibleContent>
991
- </Collapsible>
992
- ```
993
-
994
- ### Combobox
995
-
996
- Use `Combobox` for searchable selection. It uses React Native `Modal` by default, stays flat by default, and exposes `modalProps`, `overlayStyle`, `chevronIcon`, and `checkIcon` for app-level customization.
997
-
998
- ```tsx
999
- <Combobox value={value} onValueChange={setValue}>
1000
- <ComboboxInput
1001
- placeholder="Select framework"
1002
- chevronIcon={({ color, size }) => (
1003
- <ChevronsUpDown color={color} size={size} />
1004
- )}
1005
- />
1006
- <ComboboxContent>
1007
- <ComboboxList>
1008
- <ComboboxItem value="expo" label="Expo">
1009
- Expo
1010
- </ComboboxItem>
1011
- <ComboboxItem value="react-native" label="React Native">
1012
- React Native
1013
- </ComboboxItem>
1014
- <ComboboxEmpty>No results.</ComboboxEmpty>
1015
- </ComboboxList>
1016
- </ComboboxContent>
1017
- </Combobox>
1018
- ```
1019
-
1020
- ### ContextMenu
1021
-
1022
- Use `ContextMenu` for long-press menus. It uses React Native `Modal` by default and keeps system UI behavior app-overridable through `modalProps`.
1023
-
1024
- ```tsx
1025
- <ContextMenu>
1026
- <ContextMenuTrigger>
1027
- <Button variant="outline">Long press</Button>
1028
- </ContextMenuTrigger>
1029
- <ContextMenuContent>
1030
- <ContextMenuLabel>Actions</ContextMenuLabel>
1031
- <ContextMenuItem onPress={editItem}>Edit</ContextMenuItem>
1032
- <ContextMenuCheckboxItem checked={pinned} onCheckedChange={setPinned}>
1033
- Pinned
1034
- </ContextMenuCheckboxItem>
1035
- <ContextMenuSeparator />
1036
- <ContextMenuItem variant="destructive" onPress={deleteItem}>
1037
- Delete
1038
- </ContextMenuItem>
1039
- </ContextMenuContent>
1040
- </ContextMenu>
1041
- ```
1042
-
1043
- ### DropdownMenu
1044
-
1045
- Use `DropdownMenu` for tap-triggered action menus. It uses React Native `Modal`, Reanimated entry animation, flat bordered styling, alignment control, checkbox items, shortcuts, and app-overridable modal/backdrop props.
1046
-
1047
- ```tsx
1048
- <DropdownMenu>
1049
- <DropdownMenuTrigger style={triggerStyle}>
1050
- <Text variant="label">Open menu</Text>
1051
- </DropdownMenuTrigger>
1052
- <DropdownMenuContent align="start">
1053
- <DropdownMenuLabel>Actions</DropdownMenuLabel>
1054
- <DropdownMenuItem onPress={refreshList}>
1055
- Refresh
1056
- <DropdownMenuShortcut>R</DropdownMenuShortcut>
1057
- </DropdownMenuItem>
1058
- <DropdownMenuCheckboxItem checked={compact} onCheckedChange={setCompact}>
1059
- Compact mode
1060
- </DropdownMenuCheckboxItem>
1061
- <DropdownMenuSeparator />
1062
- <DropdownMenuItem variant="destructive" onPress={deleteItem}>
1063
- Delete
1064
- </DropdownMenuItem>
1065
- </DropdownMenuContent>
1066
- </DropdownMenu>
1067
- ```
1068
-
1069
- Useful props:
1070
-
1071
- - `open`, `defaultOpen`, and `onOpenChange`
1072
- - `align="start" | "end"`
1073
- - `width`, `maxHeight`, and `sideOffset`
1074
- - `modalProps` and `overlayStyle`
1075
- - `checkIcon` on `DropdownMenuCheckboxItem`
1076
-
1077
- Avoid nesting another `Pressable` or `Button` directly inside `DropdownMenuTrigger`; style the trigger itself or render non-pressable visual children inside it.
1078
-
1079
- ### Empty
1080
-
1081
- Use `Empty` for empty states such as no projects, no data, or no search results. It is composable and mirrors the web pattern with React Native primitives.
1082
-
1083
- ```tsx
1084
- <Empty>
1085
- <EmptyHeader>
1086
- <EmptyMedia variant="icon">
1087
- <FileText color={colors.text} size={16} />
1088
- </EmptyMedia>
1089
- <EmptyTitle>Expo React Native</EmptyTitle>
1090
- <EmptyDescription>
1091
- Expo React Native by Ma'sum. Crafted for consistent mobile UI in 2026.
1092
- </EmptyDescription>
1093
- </EmptyHeader>
1094
-
1095
- <EmptyContent>
1096
- <Box row center gap="sm">
1097
- <Button size="sm">Explore 2026</Button>
1098
- <Button size="sm" variant="outline" tone="secondary">
1099
- by Ma'sum
1100
- </Button>
1101
- </Box>
1102
- <Button size="sm" variant="ghost" tone="secondary">
1103
- Expo React Native
1104
- </Button>
1105
- </EmptyContent>
1106
- </Empty>
1107
- ```
1108
-
1109
- Parts:
1110
-
1111
- - `Empty`
1112
- - `EmptyHeader`
1113
- - `EmptyMedia`
1114
- - `EmptyTitle`
1115
- - `EmptyDescription`
1116
- - `EmptyContent`
1117
-
1118
- ### HoverCard
1119
-
1120
- Use `HoverCard` for richer contextual previews. On mobile, the default trigger is `longPress`.
1121
-
1122
- ```tsx
1123
- <HoverCard openDelay={10} closeDelay={100}>
1124
- <HoverCardTrigger style={triggerStyle}>
1125
- <Text variant="label" color="primary">
1126
- Expo React Native
1127
- </Text>
1128
- </HoverCardTrigger>
1129
- <HoverCardContent>
1130
- <Box gap="xs">
1131
- <Text variant="label">Expo React Native</Text>
1132
- <Text variant="bodySmall" color="textMuted">
1133
- Expo React Native by Ma'sum.
1134
- </Text>
1135
- <Text variant="caption" color="textSubtle">
1136
- Highlight 2026
1137
- </Text>
1138
- </Box>
1139
- </HoverCardContent>
1140
- </HoverCard>
1141
- ```
1142
-
1143
- Useful props:
1144
-
1145
- - `open`, `defaultOpen`, and `onOpenChange`
1146
- - `openDelay` and `closeDelay`
1147
- - `triggerMode="longPress" | "press" | "manual"`
1148
- - `align="start" | "center" | "end"`
1149
- - `width`, `maxHeight`, `sideOffset`, `modalProps`, and `overlayStyle`
1150
-
1151
- ### Input
1152
-
1153
- Use `Input` for token-based text fields. It wraps React Native `TextInput`, supports light/dark mode, and keeps the default style flat with a clear border.
1154
-
1155
- ```tsx
1156
- const [value, setValue] = React.useState("Expo React Native by Ma'sum");
1157
-
1158
- <Input
1159
- value={value}
1160
- onChangeText={setValue}
1161
- placeholder="Expo React Native by Ma'sum"
1162
- />
1163
-
1164
- <Input
1165
- type="email"
1166
- placeholder="expo-react-native@masum.dev"
1167
- />
1168
-
1169
- <Input
1170
- invalid
1171
- value="Expo React Native by Ma'sum, 2026"
1172
- onChangeText={() => undefined}
1173
- />
1174
- ```
1175
-
1176
- Useful props:
1177
-
1178
- - `type="text" | "email" | "number" | "password" | "tel" | "url"`
1179
- - `size="sm" | "md" | "lg"`
1180
- - `invalid`, `disabled`, and `fullWidth`
1181
- - All standard React Native `TextInputProps`
1182
-
1183
- ### InputGroup
1184
-
1185
- Use `InputGroup` when an input needs inline addons, result counts, small actions, or a multiline grouped field.
1186
-
1187
- ```tsx
1188
- <InputGroup>
1189
- <InputGroupAddon>
1190
- <Search color={colors.textMuted} size={16} />
1191
- </InputGroupAddon>
1192
- <InputGroupInput placeholder="Search..." />
1193
- <InputGroupAddon align="inline-end">
1194
- <InputGroupText>12 results</InputGroupText>
1195
- </InputGroupAddon>
1196
- </InputGroup>
1197
-
1198
- <InputGroup>
1199
- <InputGroupInput placeholder="Enter password" secureTextEntry />
1200
- <InputGroupAddon align="inline-end">
1201
- <EyeOff color={colors.textMuted} size={16} />
1202
- </InputGroupAddon>
1203
- </InputGroup>
1204
-
1205
- <InputGroup orientation="block">
1206
- <InputGroupAddon align="block-start">
1207
- <InputGroupText>Expo React Native by Ma'sum</InputGroupText>
1208
- </InputGroupAddon>
1209
- <InputGroupTextarea placeholder="Highlight 2026" />
1210
- <InputGroupAddon align="block-end">
1211
- <InputGroupButton size="xs">Send</InputGroupButton>
1212
- </InputGroupAddon>
1213
- </InputGroup>
1214
-
1215
- <InputGroup orientation="block">
1216
- <InputGroupInput placeholder="Enter amount" />
1217
- <InputGroupAddon align="block-end">
1218
- <InputGroupText>USD</InputGroupText>
1219
- </InputGroupAddon>
1220
- </InputGroup>
1221
- ```
1222
-
1223
- Parts:
1224
-
1225
- - `InputGroup`
1226
- - `InputGroupAddon`
1227
- - `InputGroupButton`
1228
- - `InputGroupText`
1229
- - `InputGroupInput`
1230
- - `InputGroupTextarea`
1231
-
1232
- Useful props:
1233
-
1234
- - `orientation="inline" | "block"`
1235
- - `InputGroupAddon align="inline-start" | "inline-end" | "block-start" | "block-end"`
1236
- - `InputGroupButton size="xs" | "sm" | "icon-xs" | "icon-sm"`
1237
- - `invalid` and `disabled` can be set on the group or input control
1238
-
1239
- ### InputOTP
1240
-
1241
- Use `InputOTP` for one-time passcode fields. The root owns the hidden native `TextInput`; slots render the visual code boxes.
1242
-
1243
- ```tsx
1244
- const [otp, setOtp] = React.useState("");
1245
-
1246
- <InputOTP value={otp} onChangeText={setOtp} maxLength={6}>
1247
- <InputOTPGroup>
1248
- <InputOTPSlot index={0} />
1249
- <InputOTPSlot index={1} />
1250
- <InputOTPSlot index={2} />
1251
- <InputOTPSeparator />
1252
- <InputOTPSlot index={3} />
1253
- <InputOTPSlot index={4} />
1254
- <InputOTPSlot index={5} />
1255
- </InputOTPGroup>
1256
- </InputOTP>
1257
-
1258
- <InputOTP maxLength={4} invalid>
1259
- <InputOTPGroup>
1260
- <InputOTPSlot index={0} />
1261
- <InputOTPSlot index={1} />
1262
- <InputOTPSlot index={2} />
1263
- <InputOTPSlot index={3} />
1264
- </InputOTPGroup>
1265
- </InputOTP>
1266
- ```
1267
-
1268
- Parts:
1269
-
1270
- - `InputOTP`
1271
- - `InputOTPGroup`
1272
- - `InputOTPSlot`
1273
- - `InputOTPSeparator`
1274
-
1275
- Useful props:
1276
-
1277
- - `value`, `defaultValue`, and `onChangeText`
1278
- - `maxLength`, `disabled`, `invalid`, and `autoFocus`
1279
- - `textInputProps` for native `TextInput` overrides
1280
-
1281
- ### Item
1282
-
1283
- Use `Item` primitives for reusable list rows and grouped content.
1284
-
1285
- ```tsx
1286
- <ItemGroup>
1287
- <Item variant="outline">
1288
- <ItemMedia variant="icon">
1289
- <Inbox color={colors.primary} size={20} />
1290
- </ItemMedia>
1291
- <ItemContent>
1292
- <ItemTitle>Expo React Native</ItemTitle>
1293
- <ItemDescription>
1294
- Reusable item row by Ma'sum for consistent 2026 mobile lists.
1295
- </ItemDescription>
1296
- </ItemContent>
1297
- <ItemActions>
1298
- <Badge tone="success" variant="soft">
1299
- Active
1300
- </Badge>
1301
- </ItemActions>
1302
- </Item>
1303
-
1304
- <ItemSeparator />
1305
-
1306
- <Item variant="muted" size="sm">
1307
- <ItemHeader>
1308
- <ItemTitle>Theme tokens</ItemTitle>
1309
- <Badge tone="info" variant="outline">
1310
- 2026
1311
- </Badge>
1312
- </ItemHeader>
1313
- <ItemContent>
1314
- <ItemDescription>
1315
- Header and footer areas stay full width.
1316
- </ItemDescription>
1317
- </ItemContent>
1318
- <ItemFooter>
1319
- <Text variant="caption" color="textMuted">
1320
- by Ma'sum
1321
- </Text>
1322
- <Button size="xs" variant="ghost" tone="secondary">
1323
- View
1324
- </Button>
1325
- </ItemFooter>
1326
- </Item>
1327
- </ItemGroup>
1328
- ```
1329
-
1330
- Parts:
1331
-
1332
- - `ItemGroup`
1333
- - `Item`
1334
- - `ItemMedia`
1335
- - `ItemContent`
1336
- - `ItemTitle`
1337
- - `ItemDescription`
1338
- - `ItemActions`
1339
- - `ItemHeader`
1340
- - `ItemFooter`
1341
- - `ItemSeparator`
1342
-
1343
- Useful props:
1344
-
1345
- - `Item variant="default" | "outline" | "muted"`
1346
- - `Item size="default" | "sm" | "xs"`
1347
- - `ItemMedia variant="default" | "icon" | "image"`
1348
-
1349
- ### Toast
1350
-
1351
- Wrap the app once with `ToastProvider`, then use `useToast()` from any screen.
1352
-
1353
- ```tsx
1354
- <ThemeProvider>
1355
- <ToastProvider placement="top">
1356
- <App />
1357
- </ToastProvider>
1358
- </ThemeProvider>
1359
- ```
1360
-
1361
- ```tsx
1362
- const toast = useToast();
1363
-
1364
- toast.show({
1365
- title: "Expo React Native",
1366
- description: "Toast by Ma'sum for 2026 mobile UI.",
1367
- tone: "success",
1368
- icon: ({ color, size }) => <Check color={color} size={size} />,
1369
- action: {
1370
- label: "Undo",
1371
- onPress: handleUndo,
1372
- },
1373
- });
1374
- ```
1375
-
1376
- Parts and APIs:
1377
-
1378
- - `ToastProvider`
1379
- - `useToast`
1380
- - `ToastViewport`
1381
- - `Toast`
1382
- - `ToastContent`
1383
- - `ToastTitle`
1384
- - `ToastDescription`
1385
- - `ToastAction`
1386
- - `ToastClose`
1387
-
1388
- Useful props:
1389
-
1390
- - `ToastProvider placement="top" | "bottom"`
1391
- - `offset` to control distance from the top/bottom edge; Android top placement accounts for `StatusBar.currentHeight`, and Android bottom placement leaves extra room for navigation controls by default
1392
- - `duration`, `maxToasts`, `swipeToDismiss`, `viewportStyle`, and `renderToast`
1393
- - `toast.show({ title, description, tone, icon, closeIcon, action, duration })`
1394
- - `toast.dismiss(id?)` and `toast.update(id, options)`
1395
-
1396
- ### Form And Controls
1397
-
1398
- Use these primitives for common form, preference, loading, and local navigation UI.
1399
-
1400
- ```tsx
1401
- <FormField required>
1402
- <FormLabel>Expo React Native</FormLabel>
1403
- <FormControl>
1404
- <Input placeholder="Expo React Native by Ma'sum" />
1405
- </FormControl>
1406
- <FormDescription>Consistent field copy.</FormDescription>
1407
- <FormMessage>Shown when the field is invalid.</FormMessage>
1408
- </FormField>
1409
-
1410
- <Label required requiredIndicator=" (required)">
1411
- Expo React Native
1412
- </Label>
1413
-
1414
- <Switch value={enabled} onValueChange={setEnabled} />
1415
- <Switch value={enabled} onValueChange={setEnabled} size="lg" tone="success" />
1416
-
1417
- <RadioGroup value={value} onValueChange={setValue}>
1418
- <RadioGroupItem value="expo" label="Expo React Native" />
1419
- </RadioGroup>
1420
-
1421
- <Slider
1422
- value={64}
1423
- tone="accent"
1424
- onValueChange={setValue}
1425
- onSlidingComplete={saveValue}
1426
- />
1427
- <Progress value={64} />
1428
- <Skeleton style={{ height: 16, width: "72%" }} />
1429
-
1430
- <Tabs value={tab} onValueChange={setTab}>
1431
- <TabsList>
1432
- <TabsTrigger value="preview">Preview</TabsTrigger>
1433
- <TabsTrigger value="tokens">Tokens</TabsTrigger>
1434
- </TabsList>
1435
- <TabsContent value="preview">
1436
- <Text>Expo React Native by Ma'sum</Text>
1437
- </TabsContent>
1438
- </Tabs>
1439
-
1440
- <Stepper value={2} onValueChange={setValue} min={0} max={9} />
1441
- ```
1442
-
1443
- Parts and APIs:
1444
-
1445
- - `Label` with `required`, `requiredIndicator`, and `requiredIndicatorStyle`
1446
- - `FormField`, `FormLabel`, `FormControl`, `FormDescription`, `FormMessage`, and `useFormField`
1447
- - `Switch` with `size`, `tone`, `activeIcon`, `inactiveIcon`, `thumbContent`, `activeThumbContent`, `inactiveThumbContent`, `renderThumb`, `trackStyle`, and `thumbStyle`
1448
- - `RadioGroup` and `RadioGroupItem`
1449
- - `Slider` with `tone`, `step`, tap-to-seek, hold feedback, smooth drag gestures, `trackStyle`, `activeTrackStyle`, and `thumbStyle`
1450
- - `Progress`
1451
- - `Skeleton`
1452
- - `Tabs`, `TabsList`, `TabsTrigger`, and `TabsContent`
1453
- - `Stepper`
1454
-
1455
- `Switch` is a custom Reanimated control, not the platform `Switch`. It keeps a
1456
- simple controlled API while rendering a flat bordered track, animated thumb,
1457
- theme-aware tone, and optional thumb icons.
1458
-
1459
- Use `thumbContent` for a simple ReactNode inside the thumb, or
1460
- `activeThumbContent` / `inactiveThumbContent` when the content should change
1461
- between states. Each content prop also accepts a render function with
1462
- `{ checked, disabled, invalid, color, size }`.
1463
-
1464
- `Slider` uses React Native Gesture Handler and Reanimated for tap-to-seek,
1465
- press/hold feedback, smooth horizontal dragging, and spring snapping on release.
1466
- Apps must keep `GestureHandlerRootView` at the native root, which is also
1467
- required by BottomSheet.
1468
-
1469
- ### Sheet
1470
-
1471
- Use `Sheet` as a higher-level wrapper around the package BottomSheet integration.
1472
-
1473
- ```tsx
1474
- <Sheet ref={sheetRef} snapPoints={["35%", "70%"]}>
1475
- <SheetContent>
1476
- <SheetHeader>
1477
- <SheetTitle>Expo React Native Sheet</SheetTitle>
1478
- <SheetDescription>by Ma'sum, 2026.</SheetDescription>
1479
- </SheetHeader>
1480
- <SheetFooter>
1481
- <Button onPress={() => sheetRef.current?.close()}>Close</Button>
1482
- </SheetFooter>
1483
- </SheetContent>
1484
- </Sheet>
1485
- ```
1486
-
1487
- `Sheet` defaults to `index={-1}`, `animateOnMount={false}`, and
1488
- `enablePanDownToClose` so it stays closed on initial screen render and only
1489
- opens when the app calls methods such as `snapToIndex(0)`.
1490
-
1491
- Parts:
1492
-
1493
- - `Sheet`
1494
- - `SheetContent`
1495
- - `SheetHeader`
1496
- - `SheetTitle`
1497
- - `SheetDescription`
1498
- - `SheetFooter`
1499
-
1500
- ### Data And Overlays
1501
-
1502
- Use these primitives for multiline fields, mobile selection, command sheets, anchored content, and compact data display.
1503
-
1504
- ```tsx
1505
- <Textarea placeholder="Write Expo React Native notes by Ma'sum..." />
1506
-
1507
- <Select
1508
- value={value}
1509
- onValueChange={setValue}
1510
- options={[{ value: "expo", label: "Expo React Native" }]}
1511
- />
1512
-
1513
- <Command
1514
- visible={visible}
1515
- onClose={close}
1516
- items={[{ value: "theme", label: "Theme tokens" }]}
1517
- onSelect={handleSelect}
1518
- />
1519
-
1520
- <Popover>
1521
- <PopoverTrigger>
1522
- <Text>Open Popover</Text>
1523
- </PopoverTrigger>
1524
- <PopoverContent>
1525
- <Text>Expo React Native by Ma'sum</Text>
1526
- </PopoverContent>
1527
- </Popover>
1528
-
1529
- <Pagination page={1} pageCount={5} onPageChange={setPage} />
1530
-
1531
- <Breadcrumb>
1532
- <BreadcrumbLink>Expo</BreadcrumbLink>
1533
- <BreadcrumbSeparator />
1534
- <BreadcrumbPage>Ma'sum</BreadcrumbPage>
1535
- </Breadcrumb>
1536
-
1537
- <Table>
1538
- <TableRow>
1539
- <TableHead>Name</TableHead>
1540
- <TableHead>Status</TableHead>
1541
- </TableRow>
1542
- <TableRow>
1543
- <TableCell>Expo React Native</TableCell>
1544
- <TableCell>Active</TableCell>
1545
- </TableRow>
1546
- </Table>
1547
-
1548
- <DataList>
1549
- <DataListItem>
1550
- <DataListLabel>Framework</DataListLabel>
1551
- <DataListValue>Expo React Native</DataListValue>
1552
- </DataListItem>
1553
- </DataList>
1554
-
1555
- <Timeline>
1556
- <TimelineItem active>
1557
- <TimelineTitle>Theme tokens</TimelineTitle>
1558
- <TimelineDescription>Flat border system by Ma'sum.</TimelineDescription>
1559
- </TimelineItem>
1560
- </Timeline>
1561
-
1562
- <MetricCard label="Expo React Native" value="2026" />
1563
-
1564
- <FloatingActionButton
1565
- icon={({ color, size }) => <Plus color={color} size={size} />}
1566
- label="Create"
1567
- tone="primary"
1568
- />
1569
- ```
1570
-
1571
- Parts and APIs:
1572
-
1573
- - `Textarea`
1574
- - `Select`
1575
- - `Command`
1576
- - `Popover`, `PopoverTrigger`, and `PopoverContent`
1577
- - `Pagination`
1578
- - `Breadcrumb`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, and `BreadcrumbSeparator`
1579
- - `Table`, `TableRow`, `TableHead`, and `TableCell`
1580
- - `DataList`, `DataListItem`, `DataListLabel`, and `DataListValue`
1581
- - `Timeline`, `TimelineItem`, `TimelineTitle`, and `TimelineDescription`
1582
- - `MetricCard`
1583
- - `FloatingActionButton`
1584
-
1585
- `TableHead` defaults to a transparent flat header with a subtle divider, so it
1586
- inherits the surrounding card/surface color instead of rendering a mismatched
1587
- filled header background.
1588
-
1589
- ### KeyboardAvoiding
1590
-
1591
- Use `KeyboardAvoiding` for form screens that need keyboard-safe layout. It wraps React Native `KeyboardAvoidingView` and can optionally include a themed `ScrollView`.
1592
-
1593
- ```tsx
1594
- <KeyboardAvoiding scroll p="lg" gap="md">
1595
- <Text variant="title">Expo React Native</Text>
1596
- <Input placeholder="Expo React Native by Ma'sum" />
1597
- <Button>Highlight 2026</Button>
1598
- </KeyboardAvoiding>
1599
-
1600
- <KeyboardAvoiding enabled={false}>
1601
- <Input placeholder="Managed by the app keyboard layer" />
1602
- </KeyboardAvoiding>
1603
- ```
1604
-
1605
- For Android Expo apps, set the app window to resize so the keyboard can move content predictably:
1606
-
1607
- ```json
1608
- {
1609
- "expo": {
1610
- "android": {
1611
- "softwareKeyboardLayoutMode": "resize"
1612
- }
1613
- }
1614
- }
1615
- ```
1616
-
1617
- Useful props:
1618
-
1619
- - `scroll` to render a keyboard-friendly `ScrollView`
1620
- - `bg`, `p`, `px`, `py`, and `gap` for token-based layout
1621
- - `fullHeight` to control whether the wrapper uses `flex: 1`
1622
- - `enabled={false}` to disable keyboard avoiding when the app uses another keyboard library
1623
- - `keyboardVerticalOffset`, `behavior`, and `enabled` from React Native `KeyboardAvoidingView`
1624
- - `scrollViewProps` for `keyboardShouldPersistTaps`, `contentInsetAdjustmentBehavior`, and other `ScrollView` options
1625
-
1626
- ## Common Setup Issues
1627
-
1628
- ### Gesture components do not respond
1629
-
1630
- Make sure `GestureHandlerRootView` wraps the native app root.
1631
-
1632
- ```tsx
1633
- import { GestureHandlerRootView } from "react-native-gesture-handler";
1634
-
1635
- <GestureHandlerRootView style={{ flex: 1 }}>
1636
- <App />
1637
- </GestureHandlerRootView>;
1638
- ```
1639
-
1640
- This affects `Slider`, Gorhom `BottomSheet`, and any future gesture-driven component.
1641
-
1642
- ### Reanimated animations do not run
1643
-
1644
- Verify the app has installed:
1645
-
1646
- ```sh
1647
- bun add react-native-reanimated react-native-worklets
1648
- ```
1649
-
1650
- For manual Babel config, keep the Reanimated plugin last:
1651
-
1652
- ```js
1653
- plugins: ["react-native-reanimated/plugin"];
1654
- ```
1655
-
1656
- Restart Metro after changing Babel/Reanimated setup.
1657
-
1658
- ### Toast does not show
1659
-
1660
- `useToast()` needs `ToastProvider` above the component that calls it.
1661
-
1662
- ```tsx
1663
- <ThemeProvider>
1664
- <ToastProvider>
1665
- <App />
1666
- </ToastProvider>
1667
- </ThemeProvider>
1668
- ```
1669
-
1670
- ### Dark mode resets after reload
1671
-
1672
- Pass a `storage` adapter to `ThemeProvider` and control `colorScheme` in the app if you need app-owned persistence.
1673
-
1674
- ```tsx
1675
- <ThemeProvider
1676
- storage={storage}
1677
- storageKey="rn-ui-color-scheme"
1678
- defaultColorScheme="system"
1679
- >
1680
- <App />
1681
- </ThemeProvider>
1682
- ```
1683
-
1684
- If the app uses Expo Go, choose storage supported by Expo Go, such as `expo-secure-store`.
1685
-
1686
- ### Missing peer dependency errors
1687
-
1688
- Because the package currently exports all components from one root entry, install the peer dependencies listed in the install section even if your first screen only uses a few components. Missing peers usually show up as Metro import errors for packages such as:
1689
-
1690
- - `react-native-reanimated`
1691
- - `react-native-worklets`
1692
- - `react-native-gesture-handler`
1693
- - `react-native-calendars`
1694
- - `@gorhom/bottom-sheet`
1695
-
1696
- ### Expo Go vs development builds
1697
-
1698
- `rn-ui` avoids app-specific native system UI modules. Components should work in Expo Go as long as their peer dependencies are available in the Expo runtime. If an app chooses extra native modules outside this package, such as custom system bar libraries, those modules may require a development build.
1699
-
1700
- ## Publishing Notes
1701
-
1702
- The npm package publishes compiled files from `dist`, `README.md`, and `LICENSE`.
1703
-
1704
- Before publishing:
1705
-
1706
- ```sh
1707
- bun run --filter @masumdev/rn-ui build
1708
- cd packages/rn-ui
1709
- npm pack --dry-run
1710
- npm publish --access public
1711
- ```
1712
-
1713
- The published package exposes:
1714
-
1715
- - CommonJS: `dist/index.js`
1716
- - ESM: `dist/index.mjs`
1717
- - Types: `dist/index.d.ts`
1718
-
1719
- ## Folder Structure
1720
-
1721
- ```txt
1722
- src/
1723
- components/
1724
- Accordion.tsx
1725
- Alert.tsx
1726
- AlertDialog.tsx
1727
- AspectRatio.tsx
1728
- Attachment.tsx
1729
- Avatar.tsx
1730
- BottomSheet.tsx
1731
- Bubble.tsx
1732
- ButtonGroup.tsx
1733
- Calendar.tsx
1734
- Carousel.tsx
1735
- Checkbox.tsx
1736
- Collapsible.tsx
1737
- Combobox.tsx
1738
- ContextMenu.tsx
1739
- Command.tsx
1740
- DataList.tsx
1741
- DropdownMenu.tsx
1742
- Empty.tsx
1743
- FloatingActionButton.tsx
1744
- HoverCard.tsx
1745
- Input.tsx
1746
- InputGroup.tsx
1747
- InputOTP.tsx
1748
- Item.tsx
1749
- KeyboardAvoiding.tsx
1750
- Label.tsx
1751
- MetricCard.tsx
1752
- Pagination.tsx
1753
- Popover.tsx
1754
- FormField.tsx
1755
- Progress.tsx
1756
- RadioGroup.tsx
1757
- Sheet.tsx
1758
- Skeleton.tsx
1759
- Slider.tsx
1760
- Stepper.tsx
1761
- Switch.tsx
1762
- Tabs.tsx
1763
- Table.tsx
1764
- Textarea.tsx
1765
- Timeline.tsx
1766
- Toast.tsx
1767
- Badge.tsx
1768
- Box.tsx
1769
- Button.tsx
1770
- Card.tsx
1771
- Divider.tsx
1772
- IconButton.tsx
1773
- Text.tsx
1774
- index.ts
1775
- theme/
1776
- ThemeProvider.tsx
1777
- createTheme.ts
1778
- index.ts
1779
- tokens.ts
1780
- types.ts
1781
- useTheme.ts
1782
- useThemeStyles.ts
1783
- utils/
1784
- color.ts
1785
- index.ts
1786
- index.ts
1787
- ```
1788
-
1789
- ## Design Notes
1790
-
1791
- - The default visual style is flat: no shadow/elevation by default, stronger borders, semantic surfaces, and consistent rounded corners.
1792
- - Default primary color uses a modern indigo palette: `#4F46E5` in light mode and `#818CF8` in dark mode.
1793
- - Use semantic colors such as `background`, `surface`, `text`, `primary`, `danger`, and `border` instead of hardcoded hex values.
1794
- - Use `spacing`, `radii`, `fonts`, `typography`, and `components` tokens from `useTheme()` or `useThemeStyles()`.
1795
- - Use `components.borderWidth` for default, strong, focus, ring, and hairline border sizing.
1796
- - Use `components.switch` for switch width, height, thumb size, and icon size.
1797
- - Use `components.slider` for slider height, track height, thumb sizing, and hit slop.
1798
- - Keep app-specific storage, fonts, icons, and haptics outside the UI core.
1799
- - Add new components through `components/` and export them from `components/index.ts`.
1800
- - When changing package APIs, tokens, default visuals, persistence behavior, or app integration examples, update this README in the same change.
103
+ ---
1801
104
 
1802
- ## Development Rules
105
+ ## 📄 License
1803
106
 
1804
- See [`RULES.md`](./RULES.md) for file structure rules, code style rules, component conventions, usage patterns, logging rules, and verification checklist.
107
+ MIT © [Ma'sum](https://github.com/masumrpg)