@urbint/cl 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules +313 -0
- package/.rnstorybook/index.ts +11 -0
- package/.rnstorybook/main.ts +8 -0
- package/.rnstorybook/preview.tsx +14 -0
- package/.rnstorybook/storybook.requires.ts +49 -0
- package/.storybook/main.ts +16 -0
- package/.storybook/preview.ts +32 -0
- package/.storybook/vitest.setup.ts +7 -0
- package/App.tsx +422 -0
- package/README.md +229 -0
- package/app.json +33 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/splash-icon.png +0 -0
- package/babel.config.js +16 -0
- package/docs/components/CodeBlock.tsx +80 -0
- package/docs/components/PropTable.tsx +93 -0
- package/docs/components/Sidebar.tsx +199 -0
- package/docs/components/index.ts +8 -0
- package/docs/data/colorTokens.ts +70 -0
- package/docs/data/componentData.tsx +1685 -0
- package/docs/data/index.ts +7 -0
- package/docs/index.ts +19 -0
- package/docs/navigation.ts +94 -0
- package/docs/pages/ColorsPage.tsx +226 -0
- package/docs/pages/ComponentPage.tsx +235 -0
- package/docs/pages/InstallationPage.tsx +232 -0
- package/docs/pages/IntroductionPage.tsx +163 -0
- package/docs/pages/ThemingPage.tsx +251 -0
- package/docs/pages/index.ts +10 -0
- package/docs/theme.ts +64 -0
- package/docs/types.ts +54 -0
- package/index.ts +8 -0
- package/llms.txt +1893 -0
- package/mcp-config.example.json +10 -0
- package/mcp-server/README.md +192 -0
- package/mcp-server/package-lock.json +1707 -0
- package/mcp-server/package.json +38 -0
- package/mcp-server/src/index.ts +1136 -0
- package/mcp-server/src/registry/components.ts +1446 -0
- package/mcp-server/src/registry/index.ts +3 -0
- package/mcp-server/src/registry/tokens.ts +256 -0
- package/mcp-server/tsconfig.json +19 -0
- package/package.json +92 -0
- package/src/components/Accordion/Accordion.stories.tsx +226 -0
- package/src/components/Accordion/Accordion.tsx +255 -0
- package/src/components/Accordion/index.ts +12 -0
- package/src/components/ActionSheet/ActionSheet.stories.tsx +393 -0
- package/src/components/ActionSheet/ActionSheet.tsx +258 -0
- package/src/components/ActionSheet/index.ts +2 -0
- package/src/components/Alert/Alert.stories.tsx +165 -0
- package/src/components/Alert/Alert.tsx +164 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/AlertDialog/AlertDialog.stories.tsx +330 -0
- package/src/components/AlertDialog/AlertDialog.tsx +234 -0
- package/src/components/AlertDialog/index.ts +2 -0
- package/src/components/Avatar/Avatar.stories.tsx +154 -0
- package/src/components/Avatar/Avatar.tsx +219 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Badge/Badge.stories.tsx +146 -0
- package/src/components/Badge/Badge.tsx +125 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Box/Box.stories.tsx +192 -0
- package/src/components/Box/Box.tsx +184 -0
- package/src/components/Box/index.ts +2 -0
- package/src/components/Button/Button.stories.tsx +157 -0
- package/src/components/Button/Button.tsx +180 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Card/Card.stories.tsx +145 -0
- package/src/components/Card/Card.tsx +169 -0
- package/src/components/Card/index.ts +11 -0
- package/src/components/Center/Center.stories.tsx +215 -0
- package/src/components/Center/Center.tsx +29 -0
- package/src/components/Center/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +94 -0
- package/src/components/Checkbox/Checkbox.tsx +242 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +623 -0
- package/src/components/DatePicker/DatePicker.tsx +1228 -0
- package/src/components/DatePicker/index.ts +8 -0
- package/src/components/Divider/Divider.stories.tsx +224 -0
- package/src/components/Divider/Divider.tsx +73 -0
- package/src/components/Divider/index.ts +2 -0
- package/src/components/Drawer/Drawer.stories.tsx +414 -0
- package/src/components/Drawer/Drawer.tsx +342 -0
- package/src/components/Drawer/index.ts +11 -0
- package/src/components/Fab/Fab.stories.tsx +360 -0
- package/src/components/Fab/Fab.tsx +185 -0
- package/src/components/Fab/index.ts +2 -0
- package/src/components/FormControl/FormControl.stories.tsx +276 -0
- package/src/components/FormControl/FormControl.tsx +185 -0
- package/src/components/FormControl/index.ts +12 -0
- package/src/components/Grid/Grid.stories.tsx +244 -0
- package/src/components/Grid/Grid.tsx +93 -0
- package/src/components/Grid/index.ts +2 -0
- package/src/components/HStack/HStack.stories.tsx +230 -0
- package/src/components/HStack/HStack.tsx +80 -0
- package/src/components/HStack/index.ts +2 -0
- package/src/components/Heading/Heading.stories.tsx +111 -0
- package/src/components/Heading/Heading.tsx +85 -0
- package/src/components/Heading/index.ts +2 -0
- package/src/components/Icon/Icon.stories.tsx +320 -0
- package/src/components/Icon/Icon.tsx +117 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Image/Image.stories.tsx +357 -0
- package/src/components/Image/Image.tsx +168 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/Input/Input.stories.tsx +164 -0
- package/src/components/Input/Input.tsx +274 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Link/Link.stories.tsx +187 -0
- package/src/components/Link/Link.tsx +104 -0
- package/src/components/Link/index.ts +2 -0
- package/src/components/Menu/Menu.stories.tsx +363 -0
- package/src/components/Menu/Menu.tsx +238 -0
- package/src/components/Menu/index.ts +2 -0
- package/src/components/Modal/Modal.stories.tsx +156 -0
- package/src/components/Modal/Modal.tsx +280 -0
- package/src/components/Modal/index.ts +11 -0
- package/src/components/Popover/Popover.stories.tsx +330 -0
- package/src/components/Popover/Popover.tsx +315 -0
- package/src/components/Popover/index.ts +11 -0
- package/src/components/Portal/Portal.stories.tsx +376 -0
- package/src/components/Portal/Portal.tsx +100 -0
- package/src/components/Portal/index.ts +2 -0
- package/src/components/Pressable/Pressable.stories.tsx +338 -0
- package/src/components/Pressable/Pressable.tsx +71 -0
- package/src/components/Pressable/index.ts +2 -0
- package/src/components/Progress/Progress.stories.tsx +131 -0
- package/src/components/Progress/Progress.tsx +219 -0
- package/src/components/Progress/index.ts +2 -0
- package/src/components/Radio/Radio.stories.tsx +101 -0
- package/src/components/Radio/Radio.tsx +234 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/Select/Select.stories.tsx +908 -0
- package/src/components/Select/Select.tsx +659 -0
- package/src/components/Select/index.ts +8 -0
- package/src/components/Skeleton/Skeleton.stories.tsx +154 -0
- package/src/components/Skeleton/Skeleton.tsx +192 -0
- package/src/components/Skeleton/index.ts +8 -0
- package/src/components/Slider/Slider.stories.tsx +363 -0
- package/src/components/Slider/Slider.tsx +209 -0
- package/src/components/Slider/index.ts +2 -0
- package/src/components/Spinner/Spinner.stories.tsx +108 -0
- package/src/components/Spinner/Spinner.tsx +121 -0
- package/src/components/Spinner/index.ts +2 -0
- package/src/components/Switch/Switch.stories.tsx +116 -0
- package/src/components/Switch/Switch.tsx +172 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Table/Table.stories.tsx +417 -0
- package/src/components/Table/Table.tsx +233 -0
- package/src/components/Table/index.ts +2 -0
- package/src/components/Text/Text.stories.tsx +93 -0
- package/src/components/Text/Text.tsx +119 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Textarea/Textarea.stories.tsx +280 -0
- package/src/components/Textarea/Textarea.tsx +212 -0
- package/src/components/Textarea/index.ts +2 -0
- package/src/components/Toast/Toast.stories.tsx +446 -0
- package/src/components/Toast/Toast.tsx +221 -0
- package/src/components/Toast/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +354 -0
- package/src/components/Tooltip/Tooltip.tsx +261 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/VStack/VStack.stories.tsx +183 -0
- package/src/components/VStack/VStack.tsx +76 -0
- package/src/components/VStack/index.ts +2 -0
- package/src/components/index.ts +62 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useControllableState.ts +41 -0
- package/src/hooks/useDisclosure.ts +51 -0
- package/src/index.ts +22 -0
- package/src/stories/Button.stories.tsx +53 -0
- package/src/stories/Button.tsx +101 -0
- package/src/stories/Configure.mdx +364 -0
- package/src/stories/Header.stories.tsx +33 -0
- package/src/stories/Header.tsx +75 -0
- package/src/stories/Page.stories.tsx +25 -0
- package/src/stories/Page.tsx +154 -0
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +1 -0
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +1 -0
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +1 -0
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +1 -0
- package/src/stories/assets/youtube.svg +1 -0
- package/src/styles/index.ts +7 -0
- package/src/styles/tokens.ts +318 -0
- package/src/styles/unistyles.ts +254 -0
- package/src/utils/createContext.tsx +25 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/mergeRefs.ts +21 -0
- package/tsconfig.json +26 -0
- package/urbint-cl-1.0.0.tgz +0 -0
- package/vitest.config.ts +37 -0
- package/vitest.shims.d.ts +1 -0
package/llms.txt
ADDED
|
@@ -0,0 +1,1893 @@
|
|
|
1
|
+
# Urbint Component Library (@urbint/cl) - LLM Documentation
|
|
2
|
+
|
|
3
|
+
> This documentation is designed for LLM consumption to assist developers using the Urbint Component Library.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Urbint Component Library (`@urbint/cl`) is an enterprise-ready React Native component library built with Unistyles 3.0. It provides 40+ production-ready components for B2B SAAS applications across iOS, Android, and Web platforms.
|
|
8
|
+
|
|
9
|
+
**Key Features:**
|
|
10
|
+
- Cross-platform: iOS, Android, Web
|
|
11
|
+
- Full TypeScript support
|
|
12
|
+
- Light and Dark themes
|
|
13
|
+
- Accessible (WCAG 2.1 compliant)
|
|
14
|
+
- Built with Unistyles 3.0
|
|
15
|
+
|
|
16
|
+
**Tech Stack:**
|
|
17
|
+
- React Native 0.81+
|
|
18
|
+
- Unistyles 3.0+
|
|
19
|
+
- TypeScript 5.0+
|
|
20
|
+
- Expo SDK 54+
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Install the library and peer dependencies
|
|
28
|
+
npm install @urbint/cl react-native-unistyles
|
|
29
|
+
|
|
30
|
+
# Or with yarn
|
|
31
|
+
yarn add @urbint/cl react-native-unistyles
|
|
32
|
+
|
|
33
|
+
# Or link locally during development
|
|
34
|
+
npm link ../path-to-urbint-cl
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Babel Configuration
|
|
38
|
+
|
|
39
|
+
Add the Unistyles Babel plugin to `babel.config.js`:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
module.exports = function (api) {
|
|
43
|
+
api.cache(true);
|
|
44
|
+
return {
|
|
45
|
+
presets: ['babel-preset-expo'],
|
|
46
|
+
plugins: [
|
|
47
|
+
['react-native-unistyles/plugin', { root: 'src' }],
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Setup
|
|
54
|
+
|
|
55
|
+
Import styles in your app entry point before any components:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// App.tsx
|
|
59
|
+
import '@urbint/cl/styles';
|
|
60
|
+
import { Box, Text, Button } from '@urbint/cl';
|
|
61
|
+
|
|
62
|
+
export default function App() {
|
|
63
|
+
return (
|
|
64
|
+
<Box p="lg">
|
|
65
|
+
<Text>Hello World</Text>
|
|
66
|
+
<Button variant="primary">Click Me</Button>
|
|
67
|
+
</Box>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Design Tokens
|
|
75
|
+
|
|
76
|
+
### Colors
|
|
77
|
+
|
|
78
|
+
#### Brand Colors
|
|
79
|
+
- `brand.navy`: #0D2B3E - Primary dark brand color
|
|
80
|
+
- `brand.blue`: #00A0CC - Primary action color
|
|
81
|
+
|
|
82
|
+
#### Text Colors
|
|
83
|
+
- `text.primary`: #1F2937 - Primary text
|
|
84
|
+
- `text.secondary`: #6B7280 - Secondary text
|
|
85
|
+
- `text.disabled`: #9CA3AF - Disabled text
|
|
86
|
+
- `text.inverse`: #FFFFFF - Text on dark backgrounds
|
|
87
|
+
|
|
88
|
+
#### Background Colors
|
|
89
|
+
- `background.primary`: #FFFFFF - Main background
|
|
90
|
+
- `background.secondary`: #F9FAFB - Subtle background
|
|
91
|
+
- `background.tertiary`: #F3F4F6 - Elevated surfaces
|
|
92
|
+
- `background.inverse`: #111827 - Dark background
|
|
93
|
+
|
|
94
|
+
#### Border Colors
|
|
95
|
+
- `border.disabled`: #E5E7EB - Subtle borders
|
|
96
|
+
- `border.default`: #D1D5DB - Standard borders
|
|
97
|
+
- `border.hover`: #9CA3AF - Hover state
|
|
98
|
+
- `border.active`: #00A0CC - Focus/active state
|
|
99
|
+
|
|
100
|
+
#### Feedback Colors
|
|
101
|
+
- `feedback.info`: #3B82F6
|
|
102
|
+
- `feedback.success`: #22C55E
|
|
103
|
+
- `feedback.warning`: #F59E0B
|
|
104
|
+
- `feedback.error`: #EF4444
|
|
105
|
+
|
|
106
|
+
#### Badge Colors
|
|
107
|
+
- `badge.gray`: #6B7280
|
|
108
|
+
- `badge.red`: #DC2626
|
|
109
|
+
- `badge.orange`: #EA580C
|
|
110
|
+
- `badge.yellow`: #CA8A04
|
|
111
|
+
- `badge.green`: #16A34A
|
|
112
|
+
- `badge.blue`: #2563EB
|
|
113
|
+
- `badge.purple`: #7C3AED
|
|
114
|
+
|
|
115
|
+
### Spacing Tokens
|
|
116
|
+
|
|
117
|
+
Spacing props accept **token names** (recommended) or raw numbers for backward compatibility.
|
|
118
|
+
|
|
119
|
+
| Token | Value | Description |
|
|
120
|
+
|-------|-------|-------------|
|
|
121
|
+
| `'none'` | 0px | No spacing |
|
|
122
|
+
| `'xs'` | 4px | Extra small |
|
|
123
|
+
| `'sm'` | 8px | Small |
|
|
124
|
+
| `'md'` | 12px | Medium |
|
|
125
|
+
| `'lg'` | 16px | Large |
|
|
126
|
+
| `'xl'` | 24px | Extra large |
|
|
127
|
+
| `'2xl'` | 32px | 2x extra large |
|
|
128
|
+
| `'3xl'` | 48px | 3x extra large |
|
|
129
|
+
| `'4xl'` | 64px | 4x extra large |
|
|
130
|
+
| `'5xl'` | 72px | 5x extra large |
|
|
131
|
+
|
|
132
|
+
**Legacy multiplier tokens (also supported):**
|
|
133
|
+
- `'0.5x'`: 2px, `'base'`: 4px, `'2x'`: 8px, `'3x'`: 12px, `'4x'`: 16px, `'6x'`: 24px, `'8x'`: 32px, `'12x'`: 48px, `'18x'`: 72px
|
|
134
|
+
|
|
135
|
+
### Typography Scale
|
|
136
|
+
- `h1`: 32px, bold (700)
|
|
137
|
+
- `h2`: 24px, semibold (600)
|
|
138
|
+
- `h3`: 20px, semibold (600)
|
|
139
|
+
- `h4`: 18px, semibold (600)
|
|
140
|
+
- `body`: 16px, regular (400)
|
|
141
|
+
- `label`: 14px, regular (400)
|
|
142
|
+
- `caption`: 13px, regular (400)
|
|
143
|
+
- `small`: 12px, regular (400)
|
|
144
|
+
|
|
145
|
+
### Border Radius
|
|
146
|
+
- `none`: 0
|
|
147
|
+
- `sm`: 2px
|
|
148
|
+
- `md`: 4px
|
|
149
|
+
- `lg`: 8px
|
|
150
|
+
- `xl`: 12px
|
|
151
|
+
- `2xl`: 16px
|
|
152
|
+
- `3xl`: 24px
|
|
153
|
+
- `full`: 9999px
|
|
154
|
+
|
|
155
|
+
### Elevation (Shadows)
|
|
156
|
+
- `5`: Subtle shadow
|
|
157
|
+
- `10`: Light shadow
|
|
158
|
+
- `20`: Medium shadow
|
|
159
|
+
- `30`: Strong shadow
|
|
160
|
+
- `40`: Heavy shadow
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Components Reference
|
|
165
|
+
|
|
166
|
+
### Layout Components
|
|
167
|
+
|
|
168
|
+
#### Box
|
|
169
|
+
The most fundamental layout component. A polymorphic container with style props.
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
import { Box } from '@urbint/cl';
|
|
173
|
+
|
|
174
|
+
// Using spacing tokens (recommended)
|
|
175
|
+
<Box p="lg" bg="brand.blue" rounded="md" shadow="10">
|
|
176
|
+
<Text color="white">Content</Text>
|
|
177
|
+
</Box>
|
|
178
|
+
|
|
179
|
+
// You can also use raw numbers for backward compatibility
|
|
180
|
+
<Box p={16} m="sm" gap="md">
|
|
181
|
+
<Text>Mixed usage</Text>
|
|
182
|
+
</Box>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Props:**
|
|
186
|
+
| Prop | Type | Default | Description |
|
|
187
|
+
|------|------|---------|-------------|
|
|
188
|
+
| p | SpacingToken \| number | - | Padding all sides ('xs', 'sm', 'md', 'lg', 'xl', '2xl', etc.) |
|
|
189
|
+
| px | SpacingToken \| number | - | Horizontal padding |
|
|
190
|
+
| py | SpacingToken \| number | - | Vertical padding |
|
|
191
|
+
| pt, pb, pl, pr | SpacingToken \| number | - | Individual padding |
|
|
192
|
+
| m | SpacingToken \| number | - | Margin all sides |
|
|
193
|
+
| mx, my | SpacingToken \| number | - | Horizontal/vertical margin |
|
|
194
|
+
| mt, mb, ml, mr | SpacingToken \| number | - | Individual margin |
|
|
195
|
+
| gap | SpacingToken \| number | - | Gap between children |
|
|
196
|
+
| bg | string | - | Background color |
|
|
197
|
+
| rounded | 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| '3xl' \| 'full' | - | Border radius |
|
|
198
|
+
| w | number \| string | - | Width |
|
|
199
|
+
| h | number \| string | - | Height |
|
|
200
|
+
| minW, maxW | number \| string | - | Min/max width |
|
|
201
|
+
| minH, maxH | number \| string | - | Min/max height |
|
|
202
|
+
| flex | number | - | Flex value |
|
|
203
|
+
| flexDirection | 'row' \| 'column' | - | Flex direction |
|
|
204
|
+
| alignItems | FlexAlignType | - | Align items |
|
|
205
|
+
| justifyContent | FlexJustify | - | Justify content |
|
|
206
|
+
| shadow | '5' \| '10' \| '20' \| '30' \| '40' | - | Shadow elevation |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
#### HStack
|
|
211
|
+
Horizontal stack layout with consistent spacing.
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
import { HStack } from '@urbint/cl';
|
|
215
|
+
|
|
216
|
+
// Using spacing tokens (recommended)
|
|
217
|
+
<HStack space="sm" alignItems="center">
|
|
218
|
+
<Avatar name="John" />
|
|
219
|
+
<Text>John Doe</Text>
|
|
220
|
+
</HStack>
|
|
221
|
+
|
|
222
|
+
// Using larger spacing
|
|
223
|
+
<HStack space="xl">
|
|
224
|
+
<Button>Cancel</Button>
|
|
225
|
+
<Button variant="primary">Submit</Button>
|
|
226
|
+
</HStack>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Props:**
|
|
230
|
+
| Prop | Type | Default | Description |
|
|
231
|
+
|------|------|---------|-------------|
|
|
232
|
+
| space | SpacingToken \| number | 'none' | Gap between children ('xs', 'sm', 'md', 'lg', 'xl', etc.) |
|
|
233
|
+
| px | SpacingToken \| number | - | Horizontal padding ('xs', 'sm', 'md', 'lg', 'xl', etc.) |
|
|
234
|
+
| py | SpacingToken \| number | - | Vertical padding ('xs', 'sm', 'md', 'lg', 'xl', etc.) |
|
|
235
|
+
| alignItems | FlexAlignType | 'center' | Cross-axis alignment |
|
|
236
|
+
| justifyContent | FlexJustify | 'flex-start' | Main-axis alignment |
|
|
237
|
+
| wrap | boolean | false | Allow wrapping |
|
|
238
|
+
| reversed | boolean | false | Reverse order |
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
#### VStack
|
|
243
|
+
Vertical stack layout with consistent spacing.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
import { VStack } from '@urbint/cl';
|
|
247
|
+
|
|
248
|
+
// Using spacing tokens (recommended)
|
|
249
|
+
<VStack space="lg">
|
|
250
|
+
<Heading as="h2">Title</Heading>
|
|
251
|
+
<Text>Description</Text>
|
|
252
|
+
<Button>Action</Button>
|
|
253
|
+
</VStack>
|
|
254
|
+
|
|
255
|
+
// Form layout with medium spacing
|
|
256
|
+
<VStack space="md">
|
|
257
|
+
<Input label="Email" />
|
|
258
|
+
<Input label="Password" isPassword />
|
|
259
|
+
<Button>Sign In</Button>
|
|
260
|
+
</VStack>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Props:**
|
|
264
|
+
| Prop | Type | Default | Description |
|
|
265
|
+
|------|------|---------|-------------|
|
|
266
|
+
| space | SpacingToken \| number | 'none' | Gap between children ('xs', 'sm', 'md', 'lg', 'xl', etc.) |
|
|
267
|
+
| px | SpacingToken \| number | - | Horizontal padding ('xs', 'sm', 'md', 'lg', 'xl', etc.) |
|
|
268
|
+
| py | SpacingToken \| number | - | Vertical padding ('xs', 'sm', 'md', 'lg', 'xl', etc.) |
|
|
269
|
+
| alignItems | FlexAlignType | 'stretch' | Cross-axis alignment |
|
|
270
|
+
| justifyContent | FlexJustify | 'flex-start' | Main-axis alignment |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
#### Center
|
|
275
|
+
Centers children horizontally and vertically.
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
import { Center } from '@urbint/cl';
|
|
279
|
+
|
|
280
|
+
<Center h={200}>
|
|
281
|
+
<Spinner />
|
|
282
|
+
</Center>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
#### Grid
|
|
288
|
+
Grid layout for arranging items in rows and columns.
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
import { Grid, GridItem } from '@urbint/cl';
|
|
292
|
+
|
|
293
|
+
// Using spacing tokens (recommended)
|
|
294
|
+
<Grid columns={3} gap="lg">
|
|
295
|
+
<GridItem><Card>1</Card></GridItem>
|
|
296
|
+
<GridItem><Card>2</Card></GridItem>
|
|
297
|
+
<GridItem><Card>3</Card></GridItem>
|
|
298
|
+
</Grid>
|
|
299
|
+
|
|
300
|
+
// Different row and column gaps
|
|
301
|
+
<Grid columns={2} rowGap="xl" columnGap="md">
|
|
302
|
+
<GridItem><Card>A</Card></GridItem>
|
|
303
|
+
<GridItem><Card>B</Card></GridItem>
|
|
304
|
+
</Grid>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Props:**
|
|
308
|
+
| Prop | Type | Default | Description |
|
|
309
|
+
|------|------|---------|-------------|
|
|
310
|
+
| columns | number | 1 | Number of columns |
|
|
311
|
+
| gap | SpacingToken \| number | 'none' | Gap between items ('xs', 'sm', 'md', 'lg', etc.) |
|
|
312
|
+
| rowGap | SpacingToken \| number | - | Gap between rows |
|
|
313
|
+
| columnGap | SpacingToken \| number | - | Gap between columns |
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
#### Divider
|
|
318
|
+
Visual separator between content.
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { Divider } from '@urbint/cl';
|
|
322
|
+
|
|
323
|
+
<VStack>
|
|
324
|
+
<Text>Above</Text>
|
|
325
|
+
<Divider />
|
|
326
|
+
<Text>Below</Text>
|
|
327
|
+
</VStack>
|
|
328
|
+
|
|
329
|
+
<HStack>
|
|
330
|
+
<Text>Left</Text>
|
|
331
|
+
<Divider orientation="vertical" />
|
|
332
|
+
<Text>Right</Text>
|
|
333
|
+
</HStack>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Props:**
|
|
337
|
+
| Prop | Type | Default | Description |
|
|
338
|
+
|------|------|---------|-------------|
|
|
339
|
+
| orientation | 'horizontal' \| 'vertical' | 'horizontal' | Direction |
|
|
340
|
+
| thickness | number | 1 | Line thickness |
|
|
341
|
+
| color | string | border.disabled | Divider color |
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### Typography Components
|
|
346
|
+
|
|
347
|
+
#### Text
|
|
348
|
+
Primary text component with variants.
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { Text } from '@urbint/cl';
|
|
352
|
+
|
|
353
|
+
<Text variant="body">Regular body text</Text>
|
|
354
|
+
<Text variant="caption" color="text.secondary">Secondary caption</Text>
|
|
355
|
+
<Text weight="bold" align="center">Bold centered</Text>
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Props:**
|
|
359
|
+
| Prop | Type | Default | Description |
|
|
360
|
+
|------|------|---------|-------------|
|
|
361
|
+
| variant | 'body' \| 'caption' \| 'label' \| 'small' | 'body' | Text style |
|
|
362
|
+
| weight | 'regular' \| 'medium' \| 'semiBold' \| 'bold' | 'regular' | Font weight |
|
|
363
|
+
| color | string | text.primary | Text color |
|
|
364
|
+
| align | 'left' \| 'center' \| 'right' | 'left' | Alignment |
|
|
365
|
+
| numberOfLines | number | - | Max lines |
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
#### Heading
|
|
370
|
+
Semantic heading component.
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
import { Heading } from '@urbint/cl';
|
|
374
|
+
|
|
375
|
+
<Heading as="h1">Page Title</Heading>
|
|
376
|
+
<Heading as="h2">Section Title</Heading>
|
|
377
|
+
<Heading as="h3" color="brand.blue">Colored Heading</Heading>
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Props:**
|
|
381
|
+
| Prop | Type | Default | Description |
|
|
382
|
+
|------|------|---------|-------------|
|
|
383
|
+
| as | 'h1' \| 'h2' \| 'h3' \| 'h4' | 'h2' | Heading level |
|
|
384
|
+
| color | string | text.primary | Text color |
|
|
385
|
+
| align | 'left' \| 'center' \| 'right' | 'left' | Alignment |
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
#### Link
|
|
390
|
+
Interactive text link.
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
import { Link } from '@urbint/cl';
|
|
394
|
+
|
|
395
|
+
<Link href="/about">About Us</Link>
|
|
396
|
+
<Link href="https://example.com" isExternal>External Link</Link>
|
|
397
|
+
<Link onPress={() => navigate('/home')}>Go Home</Link>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Props:**
|
|
401
|
+
| Prop | Type | Default | Description |
|
|
402
|
+
|------|------|---------|-------------|
|
|
403
|
+
| href | string | - | URL to navigate |
|
|
404
|
+
| onPress | () => void | - | Press handler |
|
|
405
|
+
| isExternal | boolean | false | Open in new tab |
|
|
406
|
+
| color | string | brand.blue | Link color |
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
### Form Components
|
|
411
|
+
|
|
412
|
+
#### Button
|
|
413
|
+
Primary action component.
|
|
414
|
+
|
|
415
|
+
```tsx
|
|
416
|
+
import { Button } from '@urbint/cl';
|
|
417
|
+
|
|
418
|
+
<Button variant="primary" onPress={handleSubmit}>Submit</Button>
|
|
419
|
+
<Button variant="secondary">Cancel</Button>
|
|
420
|
+
<Button variant="ghost">Learn More</Button>
|
|
421
|
+
<Button variant="danger" onPress={handleDelete}>Delete</Button>
|
|
422
|
+
<Button variant="outline">Outline</Button>
|
|
423
|
+
<Button isLoading>Saving...</Button>
|
|
424
|
+
<Button isDisabled>Disabled</Button>
|
|
425
|
+
<Button size="sm">Small</Button>
|
|
426
|
+
<Button size="lg">Large</Button>
|
|
427
|
+
<Button leftIcon={<Icon name="plus" />}>Add Item</Button>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Props:**
|
|
431
|
+
| Prop | Type | Default | Description |
|
|
432
|
+
|------|------|---------|-------------|
|
|
433
|
+
| variant | 'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'outline' | 'primary' | Style variant |
|
|
434
|
+
| size | 'sm' \| 'md' \| 'lg' | 'md' | Button size |
|
|
435
|
+
| isLoading | boolean | false | Show loading spinner |
|
|
436
|
+
| isDisabled | boolean | false | Disable button |
|
|
437
|
+
| leftIcon | ReactNode | - | Icon before text |
|
|
438
|
+
| rightIcon | ReactNode | - | Icon after text |
|
|
439
|
+
| onPress | () => void | - | Press handler |
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
#### Input
|
|
444
|
+
Text input field.
|
|
445
|
+
|
|
446
|
+
```tsx
|
|
447
|
+
import { Input } from '@urbint/cl';
|
|
448
|
+
|
|
449
|
+
<Input
|
|
450
|
+
label="Email"
|
|
451
|
+
placeholder="Enter your email"
|
|
452
|
+
value={email}
|
|
453
|
+
onChange={setEmail}
|
|
454
|
+
/>
|
|
455
|
+
|
|
456
|
+
<Input
|
|
457
|
+
label="Password"
|
|
458
|
+
isPassword
|
|
459
|
+
placeholder="Enter password"
|
|
460
|
+
/>
|
|
461
|
+
|
|
462
|
+
<Input
|
|
463
|
+
label="Username"
|
|
464
|
+
isInvalid
|
|
465
|
+
errorMessage="Username is already taken"
|
|
466
|
+
/>
|
|
467
|
+
|
|
468
|
+
<Input
|
|
469
|
+
label="Disabled"
|
|
470
|
+
isDisabled
|
|
471
|
+
value="Cannot edit"
|
|
472
|
+
/>
|
|
473
|
+
|
|
474
|
+
<Input
|
|
475
|
+
leftElement={<Icon name="search" />}
|
|
476
|
+
placeholder="Search..."
|
|
477
|
+
/>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Props:**
|
|
481
|
+
| Prop | Type | Default | Description |
|
|
482
|
+
|------|------|---------|-------------|
|
|
483
|
+
| label | string | - | Input label |
|
|
484
|
+
| placeholder | string | - | Placeholder text |
|
|
485
|
+
| value | string | - | Controlled value |
|
|
486
|
+
| onChange | (value: string) => void | - | Change handler |
|
|
487
|
+
| isInvalid | boolean | false | Error state |
|
|
488
|
+
| errorMessage | string | - | Error message |
|
|
489
|
+
| isDisabled | boolean | false | Disable input |
|
|
490
|
+
| isPassword | boolean | false | Password type |
|
|
491
|
+
| leftElement | ReactNode | - | Left icon/element |
|
|
492
|
+
| rightElement | ReactNode | - | Right icon/element |
|
|
493
|
+
| showFocusBorder | boolean | false | Show border highlight on focus |
|
|
494
|
+
| borderColor | string | - | Custom border color |
|
|
495
|
+
| focusBorderColor | string | - | Custom focus border color |
|
|
496
|
+
| backgroundColor | string | - | Custom background color |
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
#### Textarea
|
|
501
|
+
Multi-line text input.
|
|
502
|
+
|
|
503
|
+
```tsx
|
|
504
|
+
import { Textarea } from '@urbint/cl';
|
|
505
|
+
|
|
506
|
+
<Textarea
|
|
507
|
+
label="Description"
|
|
508
|
+
placeholder="Enter description..."
|
|
509
|
+
rows={4}
|
|
510
|
+
value={description}
|
|
511
|
+
onChange={setDescription}
|
|
512
|
+
/>
|
|
513
|
+
|
|
514
|
+
<Textarea
|
|
515
|
+
label="Notes"
|
|
516
|
+
maxLength={500}
|
|
517
|
+
showCount
|
|
518
|
+
/>
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Props:**
|
|
522
|
+
| Prop | Type | Default | Description |
|
|
523
|
+
|------|------|---------|-------------|
|
|
524
|
+
| label | string | - | Textarea label |
|
|
525
|
+
| placeholder | string | - | Placeholder |
|
|
526
|
+
| rows | number | 4 | Visible rows |
|
|
527
|
+
| maxLength | number | - | Max characters |
|
|
528
|
+
| showCount | boolean | false | Show character count |
|
|
529
|
+
| value | string | - | Controlled value |
|
|
530
|
+
| onChange | (value: string) => void | - | Change handler |
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
#### Checkbox
|
|
535
|
+
Boolean selection control.
|
|
536
|
+
|
|
537
|
+
```tsx
|
|
538
|
+
import { Checkbox } from '@urbint/cl';
|
|
539
|
+
|
|
540
|
+
<Checkbox
|
|
541
|
+
label="I accept the terms"
|
|
542
|
+
isChecked={accepted}
|
|
543
|
+
onChange={setAccepted}
|
|
544
|
+
/>
|
|
545
|
+
|
|
546
|
+
<Checkbox label="Remember me" defaultChecked />
|
|
547
|
+
<Checkbox label="Disabled" isDisabled />
|
|
548
|
+
<Checkbox label="Indeterminate" isIndeterminate />
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Props:**
|
|
552
|
+
| Prop | Type | Default | Description |
|
|
553
|
+
|------|------|---------|-------------|
|
|
554
|
+
| label | string | - | Checkbox label |
|
|
555
|
+
| isChecked | boolean | - | Controlled state |
|
|
556
|
+
| defaultChecked | boolean | false | Initial state |
|
|
557
|
+
| onChange | (checked: boolean) => void | - | Change handler |
|
|
558
|
+
| isDisabled | boolean | false | Disable checkbox |
|
|
559
|
+
| isIndeterminate | boolean | false | Partial selection |
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
#### Radio & RadioGroup
|
|
564
|
+
Single selection from options.
|
|
565
|
+
|
|
566
|
+
```tsx
|
|
567
|
+
import { Radio, RadioGroup } from '@urbint/cl';
|
|
568
|
+
|
|
569
|
+
<RadioGroup
|
|
570
|
+
label="Select size"
|
|
571
|
+
value={size}
|
|
572
|
+
onChange={setSize}
|
|
573
|
+
>
|
|
574
|
+
<Radio value="sm" label="Small" />
|
|
575
|
+
<Radio value="md" label="Medium" />
|
|
576
|
+
<Radio value="lg" label="Large" />
|
|
577
|
+
</RadioGroup>
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**RadioGroup Props:**
|
|
581
|
+
| Prop | Type | Default | Description |
|
|
582
|
+
|------|------|---------|-------------|
|
|
583
|
+
| label | string | - | Group label |
|
|
584
|
+
| value | string | - | Selected value |
|
|
585
|
+
| onChange | (value: string) => void | - | Change handler |
|
|
586
|
+
|
|
587
|
+
**Radio Props:**
|
|
588
|
+
| Prop | Type | Default | Description |
|
|
589
|
+
|------|------|---------|-------------|
|
|
590
|
+
| value | string | required | Radio value |
|
|
591
|
+
| label | string | - | Radio label |
|
|
592
|
+
| isDisabled | boolean | false | Disable radio |
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
#### Switch
|
|
597
|
+
Toggle switch for binary states.
|
|
598
|
+
|
|
599
|
+
```tsx
|
|
600
|
+
import { Switch } from '@urbint/cl';
|
|
601
|
+
|
|
602
|
+
<Switch
|
|
603
|
+
label="Enable notifications"
|
|
604
|
+
isChecked={enabled}
|
|
605
|
+
onChange={setEnabled}
|
|
606
|
+
/>
|
|
607
|
+
|
|
608
|
+
<Switch label="Dark mode" colorScheme="primary" />
|
|
609
|
+
<Switch label="Auto-save" colorScheme="success" defaultChecked />
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
**Props:**
|
|
613
|
+
| Prop | Type | Default | Description |
|
|
614
|
+
|------|------|---------|-------------|
|
|
615
|
+
| label | string | - | Switch label |
|
|
616
|
+
| isChecked | boolean | - | Controlled state |
|
|
617
|
+
| defaultChecked | boolean | false | Initial state |
|
|
618
|
+
| onChange | (checked: boolean) => void | - | Change handler |
|
|
619
|
+
| colorScheme | 'primary' \| 'success' \| 'danger' | 'primary' | Active color |
|
|
620
|
+
| isDisabled | boolean | false | Disable switch |
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
#### Select
|
|
625
|
+
Dropdown selection with popover-style dropdown. Supports single select, multi-select, and searchable modes with hover states.
|
|
626
|
+
|
|
627
|
+
```tsx
|
|
628
|
+
import { Select } from '@urbint/cl';
|
|
629
|
+
|
|
630
|
+
// Basic usage
|
|
631
|
+
<Select
|
|
632
|
+
label="Country"
|
|
633
|
+
placeholder="Select country"
|
|
634
|
+
options={[
|
|
635
|
+
{ value: 'us', label: 'United States' },
|
|
636
|
+
{ value: 'uk', label: 'United Kingdom' },
|
|
637
|
+
{ value: 'ca', label: 'Canada' },
|
|
638
|
+
]}
|
|
639
|
+
value={country}
|
|
640
|
+
onChange={setCountry}
|
|
641
|
+
/>
|
|
642
|
+
|
|
643
|
+
// Multi-select
|
|
644
|
+
<Select
|
|
645
|
+
label="Technologies"
|
|
646
|
+
placeholder="Select technologies..."
|
|
647
|
+
isMultiple
|
|
648
|
+
options={[
|
|
649
|
+
{ value: 'react', label: 'React' },
|
|
650
|
+
{ value: 'vue', label: 'Vue' },
|
|
651
|
+
{ value: 'angular', label: 'Angular' },
|
|
652
|
+
]}
|
|
653
|
+
value={selectedTechs}
|
|
654
|
+
onChange={setSelectedTechs}
|
|
655
|
+
/>
|
|
656
|
+
|
|
657
|
+
// Searchable select
|
|
658
|
+
<Select
|
|
659
|
+
label="Country"
|
|
660
|
+
placeholder="Search countries..."
|
|
661
|
+
isSearchable
|
|
662
|
+
searchPlaceholder="Type to search..."
|
|
663
|
+
options={countryOptions}
|
|
664
|
+
/>
|
|
665
|
+
|
|
666
|
+
// Searchable multi-select
|
|
667
|
+
<Select
|
|
668
|
+
label="Tags"
|
|
669
|
+
placeholder="Search and select tags..."
|
|
670
|
+
isSearchable
|
|
671
|
+
isMultiple
|
|
672
|
+
noResultsText="No tags found"
|
|
673
|
+
options={tagOptions}
|
|
674
|
+
/>
|
|
675
|
+
|
|
676
|
+
// With custom filter function
|
|
677
|
+
<Select
|
|
678
|
+
label="Technologies"
|
|
679
|
+
isSearchable
|
|
680
|
+
isMultiple
|
|
681
|
+
options={techOptions}
|
|
682
|
+
filterOption={(option, query) =>
|
|
683
|
+
option.label.toLowerCase().includes(query.toLowerCase()) ||
|
|
684
|
+
option.category?.toLowerCase().includes(query.toLowerCase())
|
|
685
|
+
}
|
|
686
|
+
/>
|
|
687
|
+
|
|
688
|
+
// With custom option rendering
|
|
689
|
+
<Select
|
|
690
|
+
options={[
|
|
691
|
+
{ value: 'us', label: 'United States', flag: '🇺🇸' },
|
|
692
|
+
{ value: 'uk', label: 'United Kingdom', flag: '🇬🇧' },
|
|
693
|
+
]}
|
|
694
|
+
renderOption={({ option, isSelected, isHovered, searchQuery }) => (
|
|
695
|
+
<HStack space="sm" style={{ flex: 1 }}>
|
|
696
|
+
<Text>{option.flag}</Text>
|
|
697
|
+
<Text style={{ color: isSelected ? '#00A0CC' : '#000' }}>
|
|
698
|
+
{option.label}
|
|
699
|
+
</Text>
|
|
700
|
+
</HStack>
|
|
701
|
+
)}
|
|
702
|
+
renderSelectedValue={({ option, selectedOptions, placeholder, isMultiple }) => (
|
|
703
|
+
option ? (
|
|
704
|
+
<HStack space="sm">
|
|
705
|
+
<Text>{option.flag}</Text>
|
|
706
|
+
<Text>{option.label}</Text>
|
|
707
|
+
</HStack>
|
|
708
|
+
) : (
|
|
709
|
+
<Text style={{ color: '#9CA3AF' }}>{placeholder}</Text>
|
|
710
|
+
)
|
|
711
|
+
)}
|
|
712
|
+
/>
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
**Props:**
|
|
716
|
+
| Prop | Type | Default | Description |
|
|
717
|
+
|------|------|---------|-------------|
|
|
718
|
+
| label | string | - | Select label |
|
|
719
|
+
| placeholder | string | 'Select an option' | Placeholder text |
|
|
720
|
+
| options | SelectOption[] | required | Options array |
|
|
721
|
+
| value | string \| string[] | - | Selected value(s) |
|
|
722
|
+
| defaultValue | string \| string[] | - | Default selected value(s) |
|
|
723
|
+
| onChange | (value: string \| string[]) => void | - | Change handler |
|
|
724
|
+
| isDisabled | boolean | false | Disable select |
|
|
725
|
+
| isMultiple | boolean | false | Enable multiple selection |
|
|
726
|
+
| isSearchable | boolean | false | Enable search/filter |
|
|
727
|
+
| searchPlaceholder | string | 'Search...' | Search input placeholder |
|
|
728
|
+
| noResultsText | string | 'No results found' | Text when no options match |
|
|
729
|
+
| filterOption | (option, query) => boolean | - | Custom filter function |
|
|
730
|
+
| size | 'sm' \| 'md' \| 'lg' | 'md' | Select size |
|
|
731
|
+
| variant | 'outline' \| 'filled' | 'outline' | Select variant |
|
|
732
|
+
| renderOption | (props: RenderOptionProps) => ReactNode | - | Custom option renderer |
|
|
733
|
+
| renderSelectedValue | (props: RenderSelectedValueProps) => ReactNode | - | Custom selected value renderer |
|
|
734
|
+
|
|
735
|
+
**SelectOption:**
|
|
736
|
+
```ts
|
|
737
|
+
interface SelectOption {
|
|
738
|
+
label: string;
|
|
739
|
+
value: string;
|
|
740
|
+
disabled?: boolean;
|
|
741
|
+
[key: string]: any; // Custom data for rendering
|
|
742
|
+
}
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
**RenderOptionProps:**
|
|
746
|
+
```ts
|
|
747
|
+
interface RenderOptionProps {
|
|
748
|
+
option: SelectOption;
|
|
749
|
+
isSelected: boolean;
|
|
750
|
+
isDisabled: boolean;
|
|
751
|
+
isHovered?: boolean;
|
|
752
|
+
searchQuery?: string; // Current search query for highlighting
|
|
753
|
+
}
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
**RenderSelectedValueProps:**
|
|
757
|
+
```ts
|
|
758
|
+
interface RenderSelectedValueProps {
|
|
759
|
+
option: SelectOption | undefined; // First selected option
|
|
760
|
+
selectedOptions: SelectOption[]; // All selected options (for multi-select)
|
|
761
|
+
placeholder: string;
|
|
762
|
+
isMultiple: boolean;
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
#### DatePicker
|
|
769
|
+
Date and time picker with multiple modes. Supports date only, time only, or date and time selection (side by side).
|
|
770
|
+
|
|
771
|
+
```tsx
|
|
772
|
+
import { DatePicker } from '@urbint/cl';
|
|
773
|
+
|
|
774
|
+
// Date only
|
|
775
|
+
<DatePicker
|
|
776
|
+
label="Date of Birth"
|
|
777
|
+
mode="date"
|
|
778
|
+
placeholder="Select date"
|
|
779
|
+
value={date}
|
|
780
|
+
onChange={setDate}
|
|
781
|
+
/>
|
|
782
|
+
|
|
783
|
+
// Time only
|
|
784
|
+
<DatePicker
|
|
785
|
+
label="Appointment Time"
|
|
786
|
+
mode="time"
|
|
787
|
+
placeholder="Select time"
|
|
788
|
+
use24HourFormat={false}
|
|
789
|
+
/>
|
|
790
|
+
|
|
791
|
+
// Date and time (side by side layout)
|
|
792
|
+
<DatePicker
|
|
793
|
+
label="Event Start"
|
|
794
|
+
mode="datetime"
|
|
795
|
+
placeholder="Select date & time"
|
|
796
|
+
value={datetime}
|
|
797
|
+
onChange={setDatetime}
|
|
798
|
+
showNowButton={true}
|
|
799
|
+
/>
|
|
800
|
+
|
|
801
|
+
// With min/max constraints
|
|
802
|
+
<DatePicker
|
|
803
|
+
label="Future Date"
|
|
804
|
+
mode="date"
|
|
805
|
+
minDate={new Date()}
|
|
806
|
+
maxDate={new Date(2026, 11, 31)}
|
|
807
|
+
/>
|
|
808
|
+
|
|
809
|
+
// With custom format
|
|
810
|
+
<DatePicker
|
|
811
|
+
label="European Format"
|
|
812
|
+
mode="date"
|
|
813
|
+
formatDate={(date) => {
|
|
814
|
+
const d = date.getDate().toString().padStart(2, '0');
|
|
815
|
+
const m = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
816
|
+
return `${d}/${m}/${date.getFullYear()}`;
|
|
817
|
+
}}
|
|
818
|
+
/>
|
|
819
|
+
|
|
820
|
+
// 24-hour time format
|
|
821
|
+
<DatePicker
|
|
822
|
+
label="Time (24h)"
|
|
823
|
+
mode="time"
|
|
824
|
+
use24HourFormat={true}
|
|
825
|
+
/>
|
|
826
|
+
|
|
827
|
+
// Monday as first day of week
|
|
828
|
+
<DatePicker
|
|
829
|
+
label="Week starts Monday"
|
|
830
|
+
mode="date"
|
|
831
|
+
firstDayOfWeek={1}
|
|
832
|
+
/>
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**Props:**
|
|
836
|
+
| Prop | Type | Default | Description |
|
|
837
|
+
|------|------|---------|-------------|
|
|
838
|
+
| mode | 'date' \| 'time' \| 'datetime' | 'date' | Picker mode |
|
|
839
|
+
| value | Date | - | Controlled value |
|
|
840
|
+
| defaultValue | Date | - | Default value |
|
|
841
|
+
| onChange | (date: Date) => void | - | Change handler |
|
|
842
|
+
| placeholder | string | Auto-generated | Placeholder text |
|
|
843
|
+
| label | string | - | Label text |
|
|
844
|
+
| helperText | string | - | Helper text |
|
|
845
|
+
| errorMessage | string | - | Error message |
|
|
846
|
+
| isInvalid | boolean | false | Error state |
|
|
847
|
+
| isDisabled | boolean | false | Disable picker |
|
|
848
|
+
| isRequired | boolean | false | Required field |
|
|
849
|
+
| minDate | Date | - | Minimum selectable date |
|
|
850
|
+
| maxDate | Date | - | Maximum selectable date |
|
|
851
|
+
| size | 'sm' \| 'md' \| 'lg' | 'md' | Picker size |
|
|
852
|
+
| variant | 'outline' \| 'filled' | 'outline' | Visual variant |
|
|
853
|
+
| formatDate | (date: Date, mode: DatePickerMode) => string | Default formatter | Custom format function |
|
|
854
|
+
| use24HourFormat | boolean | false | Use 24-hour time format |
|
|
855
|
+
| firstDayOfWeek | 0 \| 1 | 0 | First day (0=Sunday, 1=Monday) |
|
|
856
|
+
| showNowButton | boolean | true | Show "Now" button in time/datetime modes |
|
|
857
|
+
|
|
858
|
+
**Mode Details:**
|
|
859
|
+
- `date`: Shows calendar only, closes on date selection
|
|
860
|
+
- `time`: Shows hour/minute/AM-PM columns with "Now" and "OK" buttons
|
|
861
|
+
- `datetime`: Shows calendar and time picker side by side with "Now" and "OK" buttons
|
|
862
|
+
|
|
863
|
+
---
|
|
864
|
+
|
|
865
|
+
#### Slider
|
|
866
|
+
Range value selector.
|
|
867
|
+
|
|
868
|
+
```tsx
|
|
869
|
+
import { Slider } from '@urbint/cl';
|
|
870
|
+
|
|
871
|
+
<Slider
|
|
872
|
+
label="Volume"
|
|
873
|
+
value={volume}
|
|
874
|
+
onChange={setVolume}
|
|
875
|
+
min={0}
|
|
876
|
+
max={100}
|
|
877
|
+
showValue
|
|
878
|
+
/>
|
|
879
|
+
|
|
880
|
+
<Slider
|
|
881
|
+
label="Price range"
|
|
882
|
+
min={0}
|
|
883
|
+
max={1000}
|
|
884
|
+
step={10}
|
|
885
|
+
/>
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
**Props:**
|
|
889
|
+
| Prop | Type | Default | Description |
|
|
890
|
+
|------|------|---------|-------------|
|
|
891
|
+
| label | string | - | Slider label |
|
|
892
|
+
| value | number | - | Current value |
|
|
893
|
+
| onChange | (value: number) => void | - | Change handler |
|
|
894
|
+
| min | number | 0 | Minimum value |
|
|
895
|
+
| max | number | 100 | Maximum value |
|
|
896
|
+
| step | number | 1 | Step increment |
|
|
897
|
+
| showValue | boolean | false | Show current value |
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
#### FormControl
|
|
902
|
+
Wrapper for form elements with label and error handling.
|
|
903
|
+
|
|
904
|
+
```tsx
|
|
905
|
+
import { FormControl, Input } from '@urbint/cl';
|
|
906
|
+
|
|
907
|
+
<FormControl
|
|
908
|
+
label="Email"
|
|
909
|
+
helperText="We'll never share your email"
|
|
910
|
+
isRequired
|
|
911
|
+
>
|
|
912
|
+
<Input placeholder="Enter email" />
|
|
913
|
+
</FormControl>
|
|
914
|
+
|
|
915
|
+
<FormControl
|
|
916
|
+
label="Password"
|
|
917
|
+
isInvalid
|
|
918
|
+
errorMessage="Password must be at least 8 characters"
|
|
919
|
+
>
|
|
920
|
+
<Input isPassword />
|
|
921
|
+
</FormControl>
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
**Props:**
|
|
925
|
+
| Prop | Type | Default | Description |
|
|
926
|
+
|------|------|---------|-------------|
|
|
927
|
+
| label | string | - | Form label |
|
|
928
|
+
| helperText | string | - | Helper text |
|
|
929
|
+
| errorMessage | string | - | Error message |
|
|
930
|
+
| isRequired | boolean | false | Show required indicator |
|
|
931
|
+
| isInvalid | boolean | false | Error state |
|
|
932
|
+
|
|
933
|
+
---
|
|
934
|
+
|
|
935
|
+
### Feedback Components
|
|
936
|
+
|
|
937
|
+
#### Alert
|
|
938
|
+
Status messages.
|
|
939
|
+
|
|
940
|
+
```tsx
|
|
941
|
+
import { Alert } from '@urbint/cl';
|
|
942
|
+
|
|
943
|
+
<Alert status="info" title="Update available" description="A new version is ready." />
|
|
944
|
+
<Alert status="success" title="Saved!" />
|
|
945
|
+
<Alert status="warning" title="Warning" description="Please review before continuing." />
|
|
946
|
+
<Alert status="error" title="Error" description="Something went wrong." isClosable onClose={handleClose} />
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
**Props:**
|
|
950
|
+
| Prop | Type | Default | Description |
|
|
951
|
+
|------|------|---------|-------------|
|
|
952
|
+
| status | 'info' \| 'success' \| 'warning' \| 'error' | 'info' | Alert type |
|
|
953
|
+
| title | string | required | Alert title |
|
|
954
|
+
| description | string | - | Alert description |
|
|
955
|
+
| isClosable | boolean | false | Show close button |
|
|
956
|
+
| onClose | () => void | - | Close handler |
|
|
957
|
+
|
|
958
|
+
---
|
|
959
|
+
|
|
960
|
+
#### Toast
|
|
961
|
+
Non-blocking notifications.
|
|
962
|
+
|
|
963
|
+
```tsx
|
|
964
|
+
import { useToast, ToastProvider } from '@urbint/cl';
|
|
965
|
+
|
|
966
|
+
// Wrap app with ToastProvider
|
|
967
|
+
<ToastProvider>
|
|
968
|
+
<App />
|
|
969
|
+
</ToastProvider>
|
|
970
|
+
|
|
971
|
+
// Use in components
|
|
972
|
+
function MyComponent() {
|
|
973
|
+
const toast = useToast();
|
|
974
|
+
|
|
975
|
+
const handleSave = () => {
|
|
976
|
+
toast.show({
|
|
977
|
+
title: 'Saved successfully',
|
|
978
|
+
status: 'success',
|
|
979
|
+
duration: 3000,
|
|
980
|
+
});
|
|
981
|
+
};
|
|
982
|
+
|
|
983
|
+
const handleError = () => {
|
|
984
|
+
toast.show({
|
|
985
|
+
title: 'Error',
|
|
986
|
+
description: 'Failed to save changes',
|
|
987
|
+
status: 'error',
|
|
988
|
+
});
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
**toast.show() Options:**
|
|
994
|
+
| Option | Type | Default | Description |
|
|
995
|
+
|--------|------|---------|-------------|
|
|
996
|
+
| title | string | required | Toast title |
|
|
997
|
+
| description | string | - | Toast description |
|
|
998
|
+
| status | 'info' \| 'success' \| 'warning' \| 'error' | 'info' | Toast type |
|
|
999
|
+
| duration | number | 5000 | Auto-dismiss (ms) |
|
|
1000
|
+
| position | 'top' \| 'bottom' | 'top' | Screen position |
|
|
1001
|
+
|
|
1002
|
+
---
|
|
1003
|
+
|
|
1004
|
+
#### Progress
|
|
1005
|
+
Progress indicator.
|
|
1006
|
+
|
|
1007
|
+
```tsx
|
|
1008
|
+
import { Progress } from '@urbint/cl';
|
|
1009
|
+
|
|
1010
|
+
// Linear progress
|
|
1011
|
+
<Progress value={75} />
|
|
1012
|
+
<Progress value={50} size="lg" colorScheme="success" />
|
|
1013
|
+
<Progress value={25} showLabel />
|
|
1014
|
+
<Progress isIndeterminate />
|
|
1015
|
+
|
|
1016
|
+
// Circular progress
|
|
1017
|
+
<Progress variant="circular" value={75} />
|
|
1018
|
+
<Progress variant="circular" value={50} size="lg" showLabel />
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
**Props:**
|
|
1022
|
+
| Prop | Type | Default | Description |
|
|
1023
|
+
|------|------|---------|-------------|
|
|
1024
|
+
| value | number | - | Progress 0-100 |
|
|
1025
|
+
| variant | 'linear' \| 'circular' | 'linear' | Progress style |
|
|
1026
|
+
| size | 'sm' \| 'md' \| 'lg' | 'md' | Progress size |
|
|
1027
|
+
| colorScheme | 'primary' \| 'success' \| 'warning' | 'primary' | Color |
|
|
1028
|
+
| showLabel | boolean | false | Show percentage |
|
|
1029
|
+
| isIndeterminate | boolean | false | Indeterminate mode |
|
|
1030
|
+
|
|
1031
|
+
---
|
|
1032
|
+
|
|
1033
|
+
#### Spinner
|
|
1034
|
+
Loading indicator.
|
|
1035
|
+
|
|
1036
|
+
```tsx
|
|
1037
|
+
import { Spinner } from '@urbint/cl';
|
|
1038
|
+
|
|
1039
|
+
<Spinner />
|
|
1040
|
+
<Spinner size="lg" />
|
|
1041
|
+
<Spinner size="sm" color="brand.blue" />
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
**Props:**
|
|
1045
|
+
| Prop | Type | Default | Description |
|
|
1046
|
+
|------|------|---------|-------------|
|
|
1047
|
+
| size | 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Spinner size |
|
|
1048
|
+
| color | string | brand.blue | Spinner color |
|
|
1049
|
+
| label | string | 'Loading' | Accessibility label |
|
|
1050
|
+
|
|
1051
|
+
---
|
|
1052
|
+
|
|
1053
|
+
#### Skeleton
|
|
1054
|
+
Loading placeholder.
|
|
1055
|
+
|
|
1056
|
+
```tsx
|
|
1057
|
+
import { Skeleton, SkeletonText, SkeletonCircle } from '@urbint/cl';
|
|
1058
|
+
|
|
1059
|
+
// Basic skeleton
|
|
1060
|
+
<Skeleton height={20} width="60%" />
|
|
1061
|
+
<Skeleton height={100} />
|
|
1062
|
+
|
|
1063
|
+
// Text skeleton
|
|
1064
|
+
<SkeletonText noOfLines={3} />
|
|
1065
|
+
|
|
1066
|
+
// Circle skeleton (for avatars)
|
|
1067
|
+
<SkeletonCircle size={48} />
|
|
1068
|
+
|
|
1069
|
+
// Combined loading state
|
|
1070
|
+
<HStack space={12}>
|
|
1071
|
+
<SkeletonCircle size={48} />
|
|
1072
|
+
<VStack space={8} flex={1}>
|
|
1073
|
+
<Skeleton height={16} width="70%" />
|
|
1074
|
+
<Skeleton height={14} width="40%" />
|
|
1075
|
+
</VStack>
|
|
1076
|
+
</HStack>
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
**Skeleton Props:**
|
|
1080
|
+
| Prop | Type | Default | Description |
|
|
1081
|
+
|------|------|---------|-------------|
|
|
1082
|
+
| width | number \| string | '100%' | Skeleton width |
|
|
1083
|
+
| height | number | 16 | Skeleton height |
|
|
1084
|
+
| animation | 'pulse' \| 'wave' \| 'none' | 'pulse' | Animation type |
|
|
1085
|
+
|
|
1086
|
+
---
|
|
1087
|
+
|
|
1088
|
+
### Data Display Components
|
|
1089
|
+
|
|
1090
|
+
#### Avatar
|
|
1091
|
+
User profile image.
|
|
1092
|
+
|
|
1093
|
+
```tsx
|
|
1094
|
+
import { Avatar, AvatarGroup } from '@urbint/cl';
|
|
1095
|
+
|
|
1096
|
+
<Avatar name="John Doe" />
|
|
1097
|
+
<Avatar src="https://example.com/avatar.jpg" name="Jane" />
|
|
1098
|
+
<Avatar name="Bob Smith" size="lg" showBadge badgeColor="success" />
|
|
1099
|
+
|
|
1100
|
+
// Avatar group
|
|
1101
|
+
<AvatarGroup max={3}>
|
|
1102
|
+
<Avatar name="John" />
|
|
1103
|
+
<Avatar name="Jane" />
|
|
1104
|
+
<Avatar name="Bob" />
|
|
1105
|
+
<Avatar name="Alice" />
|
|
1106
|
+
</AvatarGroup>
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
**Props:**
|
|
1110
|
+
| Prop | Type | Default | Description |
|
|
1111
|
+
|------|------|---------|-------------|
|
|
1112
|
+
| src | string | - | Image URL |
|
|
1113
|
+
| name | string | - | Name for initials |
|
|
1114
|
+
| size | 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Avatar size |
|
|
1115
|
+
| showBadge | boolean | false | Show status badge |
|
|
1116
|
+
| badgeColor | string | success | Badge color |
|
|
1117
|
+
|
|
1118
|
+
---
|
|
1119
|
+
|
|
1120
|
+
#### Badge
|
|
1121
|
+
Status indicator labels.
|
|
1122
|
+
|
|
1123
|
+
```tsx
|
|
1124
|
+
import { Badge } from '@urbint/cl';
|
|
1125
|
+
|
|
1126
|
+
<Badge variant="gray">Default</Badge>
|
|
1127
|
+
<Badge variant="red">Critical</Badge>
|
|
1128
|
+
<Badge variant="orange">Warning</Badge>
|
|
1129
|
+
<Badge variant="yellow">Pending</Badge>
|
|
1130
|
+
<Badge variant="green">Active</Badge>
|
|
1131
|
+
<Badge variant="blue">Info</Badge>
|
|
1132
|
+
<Badge variant="purple">New</Badge>
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
**Props:**
|
|
1136
|
+
| Prop | Type | Default | Description |
|
|
1137
|
+
|------|------|---------|-------------|
|
|
1138
|
+
| variant | 'gray' \| 'red' \| 'orange' \| 'yellow' \| 'green' \| 'blue' \| 'purple' | 'gray' | Badge color |
|
|
1139
|
+
| size | 'sm' \| 'md' | 'md' | Badge size |
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
#### Card
|
|
1144
|
+
Content container.
|
|
1145
|
+
|
|
1146
|
+
```tsx
|
|
1147
|
+
import { Card, CardHeader, CardBody, CardFooter } from '@urbint/cl';
|
|
1148
|
+
|
|
1149
|
+
<Card variant="elevated">
|
|
1150
|
+
<CardHeader>
|
|
1151
|
+
<Heading as="h3">Card Title</Heading>
|
|
1152
|
+
</CardHeader>
|
|
1153
|
+
<CardBody>
|
|
1154
|
+
<Text>Card content goes here.</Text>
|
|
1155
|
+
</CardBody>
|
|
1156
|
+
<CardFooter>
|
|
1157
|
+
<Button variant="ghost">Cancel</Button>
|
|
1158
|
+
<Button>Submit</Button>
|
|
1159
|
+
</CardFooter>
|
|
1160
|
+
</Card>
|
|
1161
|
+
|
|
1162
|
+
<Card variant="outline" padding="lg">
|
|
1163
|
+
<Text>Simple outline card</Text>
|
|
1164
|
+
</Card>
|
|
1165
|
+
|
|
1166
|
+
// Card with custom elevation
|
|
1167
|
+
<Card shadow="40">
|
|
1168
|
+
<Text>High elevation card</Text>
|
|
1169
|
+
</Card>
|
|
1170
|
+
|
|
1171
|
+
<Card variant="filled" shadow="10">
|
|
1172
|
+
<Text>Filled card with subtle shadow</Text>
|
|
1173
|
+
</Card>
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
**Props:**
|
|
1177
|
+
| Prop | Type | Default | Description |
|
|
1178
|
+
|------|------|---------|-------------|
|
|
1179
|
+
| variant | 'elevated' \| 'outline' \| 'filled' | 'elevated' | Card style |
|
|
1180
|
+
| padding | 'none' \| 'sm' \| 'md' \| 'lg' | 'md' | Internal padding |
|
|
1181
|
+
| shadow | '5' \| '10' \| '20' \| '30' \| '40' | '20' (for elevated) | Shadow elevation level |
|
|
1182
|
+
| isPressable | boolean | false | Make card tappable |
|
|
1183
|
+
| onPress | () => void | - | Press handler (requires isPressable) |
|
|
1184
|
+
|
|
1185
|
+
---
|
|
1186
|
+
|
|
1187
|
+
#### Table
|
|
1188
|
+
Data table.
|
|
1189
|
+
|
|
1190
|
+
```tsx
|
|
1191
|
+
import { Table, TableHead, TableBody, TableRow, TableCell } from '@urbint/cl';
|
|
1192
|
+
|
|
1193
|
+
<Table>
|
|
1194
|
+
<TableHead>
|
|
1195
|
+
<TableRow>
|
|
1196
|
+
<TableCell isHeader>Name</TableCell>
|
|
1197
|
+
<TableCell isHeader>Status</TableCell>
|
|
1198
|
+
<TableCell isHeader>Role</TableCell>
|
|
1199
|
+
</TableRow>
|
|
1200
|
+
</TableHead>
|
|
1201
|
+
<TableBody>
|
|
1202
|
+
<TableRow>
|
|
1203
|
+
<TableCell>John Doe</TableCell>
|
|
1204
|
+
<TableCell><Badge variant="green">Active</Badge></TableCell>
|
|
1205
|
+
<TableCell>Admin</TableCell>
|
|
1206
|
+
</TableRow>
|
|
1207
|
+
</TableBody>
|
|
1208
|
+
</Table>
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
---
|
|
1212
|
+
|
|
1213
|
+
#### Icon
|
|
1214
|
+
SVG icons.
|
|
1215
|
+
|
|
1216
|
+
```tsx
|
|
1217
|
+
import { Icon } from '@urbint/cl';
|
|
1218
|
+
|
|
1219
|
+
<Icon name="check" />
|
|
1220
|
+
<Icon name="close" size="lg" color="error" />
|
|
1221
|
+
<Icon name="search" size="sm" />
|
|
1222
|
+
<Icon name="user" />
|
|
1223
|
+
<Icon name="settings" />
|
|
1224
|
+
<Icon name="bell" />
|
|
1225
|
+
<Icon name="heart" color="red" />
|
|
1226
|
+
<Icon name="star" color="yellow" />
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
**Available Icons:** check, close, search, user, settings, bell, heart, star, plus, minus, edit, delete, chevron-down, chevron-up, chevron-left, chevron-right, arrow-left, arrow-right, info, warning, error, success
|
|
1230
|
+
|
|
1231
|
+
**Props:**
|
|
1232
|
+
| Prop | Type | Default | Description |
|
|
1233
|
+
|------|------|---------|-------------|
|
|
1234
|
+
| name | IconName | required | Icon name |
|
|
1235
|
+
| size | 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Icon size |
|
|
1236
|
+
| color | string | text.primary | Icon color |
|
|
1237
|
+
|
|
1238
|
+
---
|
|
1239
|
+
|
|
1240
|
+
### Overlay Components
|
|
1241
|
+
|
|
1242
|
+
#### Modal
|
|
1243
|
+
Dialog overlay.
|
|
1244
|
+
|
|
1245
|
+
```tsx
|
|
1246
|
+
import { Modal, ModalHeader, ModalBody, ModalFooter, useDisclosure } from '@urbint/cl';
|
|
1247
|
+
|
|
1248
|
+
function MyComponent() {
|
|
1249
|
+
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
1250
|
+
|
|
1251
|
+
return (
|
|
1252
|
+
<>
|
|
1253
|
+
<Button onPress={onOpen}>Open Modal</Button>
|
|
1254
|
+
|
|
1255
|
+
<Modal isOpen={isOpen} onClose={onClose} size="md">
|
|
1256
|
+
<ModalHeader>Modal Title</ModalHeader>
|
|
1257
|
+
<ModalBody>
|
|
1258
|
+
<Text>Modal content goes here.</Text>
|
|
1259
|
+
</ModalBody>
|
|
1260
|
+
<ModalFooter>
|
|
1261
|
+
<Button variant="ghost" onPress={onClose}>Cancel</Button>
|
|
1262
|
+
<Button onPress={handleConfirm}>Confirm</Button>
|
|
1263
|
+
</ModalFooter>
|
|
1264
|
+
</Modal>
|
|
1265
|
+
</>
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
**Props:**
|
|
1271
|
+
| Prop | Type | Default | Description |
|
|
1272
|
+
|------|------|---------|-------------|
|
|
1273
|
+
| isOpen | boolean | required | Open state |
|
|
1274
|
+
| onClose | () => void | required | Close handler |
|
|
1275
|
+
| size | 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full' | 'md' | Modal size |
|
|
1276
|
+
| closeOnOverlayClick | boolean | true | Close on backdrop |
|
|
1277
|
+
|
|
1278
|
+
---
|
|
1279
|
+
|
|
1280
|
+
#### Drawer
|
|
1281
|
+
Slide-out panel.
|
|
1282
|
+
|
|
1283
|
+
```tsx
|
|
1284
|
+
import { Drawer, DrawerHeader, DrawerBody, useDisclosure } from '@urbint/cl';
|
|
1285
|
+
|
|
1286
|
+
function MyComponent() {
|
|
1287
|
+
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
1288
|
+
|
|
1289
|
+
return (
|
|
1290
|
+
<>
|
|
1291
|
+
<Button onPress={onOpen}>Open Menu</Button>
|
|
1292
|
+
|
|
1293
|
+
<Drawer isOpen={isOpen} onClose={onClose} title="Menu" placement="right">
|
|
1294
|
+
<DrawerBody>
|
|
1295
|
+
<VStack space={16}>
|
|
1296
|
+
<Link>Profile</Link>
|
|
1297
|
+
<Link>Settings</Link>
|
|
1298
|
+
<Link>Logout</Link>
|
|
1299
|
+
</VStack>
|
|
1300
|
+
</DrawerBody>
|
|
1301
|
+
</Drawer>
|
|
1302
|
+
</>
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
**Props:**
|
|
1308
|
+
| Prop | Type | Default | Description |
|
|
1309
|
+
|------|------|---------|-------------|
|
|
1310
|
+
| isOpen | boolean | required | Open state |
|
|
1311
|
+
| onClose | () => void | required | Close handler |
|
|
1312
|
+
| title | string | - | Drawer title displayed in header |
|
|
1313
|
+
| placement | 'left' \| 'right' \| 'top' \| 'bottom' | 'right' | Position |
|
|
1314
|
+
| size | 'sm' \| 'md' \| 'lg' \| 'full' | 'md' | Drawer size |
|
|
1315
|
+
|
|
1316
|
+
---
|
|
1317
|
+
|
|
1318
|
+
#### AlertDialog
|
|
1319
|
+
Confirmation dialog.
|
|
1320
|
+
|
|
1321
|
+
```tsx
|
|
1322
|
+
import { AlertDialog, useDisclosure } from '@urbint/cl';
|
|
1323
|
+
|
|
1324
|
+
function DeleteButton() {
|
|
1325
|
+
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
1326
|
+
|
|
1327
|
+
return (
|
|
1328
|
+
<>
|
|
1329
|
+
<Button variant="danger" onPress={onOpen}>Delete</Button>
|
|
1330
|
+
|
|
1331
|
+
<AlertDialog
|
|
1332
|
+
isOpen={isOpen}
|
|
1333
|
+
onClose={onClose}
|
|
1334
|
+
onConfirm={handleDelete}
|
|
1335
|
+
title="Delete Item?"
|
|
1336
|
+
description="This action cannot be undone."
|
|
1337
|
+
confirmLabel="Delete"
|
|
1338
|
+
confirmVariant="danger"
|
|
1339
|
+
/>
|
|
1340
|
+
</>
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
**Props:**
|
|
1346
|
+
| Prop | Type | Default | Description |
|
|
1347
|
+
|------|------|---------|-------------|
|
|
1348
|
+
| isOpen | boolean | required | Open state |
|
|
1349
|
+
| onClose | () => void | required | Close handler |
|
|
1350
|
+
| onConfirm | () => void | required | Confirm handler |
|
|
1351
|
+
| title | string | required | Dialog title |
|
|
1352
|
+
| description | string | - | Dialog description |
|
|
1353
|
+
| confirmLabel | string | 'Confirm' | Confirm button text |
|
|
1354
|
+
| confirmVariant | ButtonVariant | 'primary' | Confirm button style |
|
|
1355
|
+
|
|
1356
|
+
---
|
|
1357
|
+
|
|
1358
|
+
#### Popover
|
|
1359
|
+
Floating content.
|
|
1360
|
+
|
|
1361
|
+
```tsx
|
|
1362
|
+
import { Popover, PopoverTrigger, PopoverContent } from '@urbint/cl';
|
|
1363
|
+
|
|
1364
|
+
<Popover placement="bottom">
|
|
1365
|
+
<PopoverTrigger>
|
|
1366
|
+
<Button>Open Popover</Button>
|
|
1367
|
+
</PopoverTrigger>
|
|
1368
|
+
<PopoverContent>
|
|
1369
|
+
<Text>Popover content here</Text>
|
|
1370
|
+
</PopoverContent>
|
|
1371
|
+
</Popover>
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
**Props:**
|
|
1375
|
+
| Prop | Type | Default | Description |
|
|
1376
|
+
|------|------|---------|-------------|
|
|
1377
|
+
| placement | 'top' \| 'bottom' \| 'left' \| 'right' | 'bottom' | Position |
|
|
1378
|
+
| isOpen | boolean | - | Controlled state |
|
|
1379
|
+
| onClose | () => void | - | Close handler |
|
|
1380
|
+
|
|
1381
|
+
---
|
|
1382
|
+
|
|
1383
|
+
#### Tooltip
|
|
1384
|
+
Hover hints.
|
|
1385
|
+
|
|
1386
|
+
```tsx
|
|
1387
|
+
import { Tooltip } from '@urbint/cl';
|
|
1388
|
+
|
|
1389
|
+
<Tooltip label="This is a helpful tip">
|
|
1390
|
+
<Button>Hover me</Button>
|
|
1391
|
+
</Tooltip>
|
|
1392
|
+
|
|
1393
|
+
<Tooltip label="Delete item" placement="left">
|
|
1394
|
+
<Icon name="delete" />
|
|
1395
|
+
</Tooltip>
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
**Props:**
|
|
1399
|
+
| Prop | Type | Default | Description |
|
|
1400
|
+
|------|------|---------|-------------|
|
|
1401
|
+
| label | string | required | Tooltip text |
|
|
1402
|
+
| placement | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | Position |
|
|
1403
|
+
| hasArrow | boolean | true | Show arrow |
|
|
1404
|
+
|
|
1405
|
+
---
|
|
1406
|
+
|
|
1407
|
+
#### Menu
|
|
1408
|
+
Dropdown menu.
|
|
1409
|
+
|
|
1410
|
+
```tsx
|
|
1411
|
+
import { Menu, MenuTrigger, MenuContent, MenuItem } from '@urbint/cl';
|
|
1412
|
+
|
|
1413
|
+
<Menu>
|
|
1414
|
+
<MenuTrigger>
|
|
1415
|
+
<Button rightIcon={<Icon name="chevron-down" />}>Options</Button>
|
|
1416
|
+
</MenuTrigger>
|
|
1417
|
+
<MenuContent>
|
|
1418
|
+
<MenuItem onPress={handleEdit}>Edit</MenuItem>
|
|
1419
|
+
<MenuItem onPress={handleDuplicate}>Duplicate</MenuItem>
|
|
1420
|
+
<MenuItem onPress={handleDelete} isDestructive>Delete</MenuItem>
|
|
1421
|
+
</MenuContent>
|
|
1422
|
+
</Menu>
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
---
|
|
1426
|
+
|
|
1427
|
+
#### ActionSheet
|
|
1428
|
+
Bottom sheet (mobile).
|
|
1429
|
+
|
|
1430
|
+
```tsx
|
|
1431
|
+
import { ActionSheet, useDisclosure } from '@urbint/cl';
|
|
1432
|
+
|
|
1433
|
+
function MyComponent() {
|
|
1434
|
+
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
1435
|
+
|
|
1436
|
+
return (
|
|
1437
|
+
<>
|
|
1438
|
+
<Button onPress={onOpen}>Show Actions</Button>
|
|
1439
|
+
|
|
1440
|
+
<ActionSheet
|
|
1441
|
+
isOpen={isOpen}
|
|
1442
|
+
onClose={onClose}
|
|
1443
|
+
actions={[
|
|
1444
|
+
{ label: 'Edit', onPress: handleEdit },
|
|
1445
|
+
{ label: 'Share', onPress: handleShare },
|
|
1446
|
+
{ label: 'Delete', onPress: handleDelete, isDestructive: true },
|
|
1447
|
+
]}
|
|
1448
|
+
/>
|
|
1449
|
+
</>
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
```
|
|
1453
|
+
|
|
1454
|
+
---
|
|
1455
|
+
|
|
1456
|
+
### Action Components
|
|
1457
|
+
|
|
1458
|
+
#### Pressable
|
|
1459
|
+
Base pressable with feedback.
|
|
1460
|
+
|
|
1461
|
+
```tsx
|
|
1462
|
+
import { Pressable } from '@urbint/cl';
|
|
1463
|
+
|
|
1464
|
+
<Pressable onPress={handlePress} onLongPress={handleLongPress}>
|
|
1465
|
+
<Card>
|
|
1466
|
+
<Text>Tap me</Text>
|
|
1467
|
+
</Card>
|
|
1468
|
+
</Pressable>
|
|
1469
|
+
```
|
|
1470
|
+
|
|
1471
|
+
---
|
|
1472
|
+
|
|
1473
|
+
#### Fab
|
|
1474
|
+
Floating action button.
|
|
1475
|
+
|
|
1476
|
+
```tsx
|
|
1477
|
+
import { Fab } from '@urbint/cl';
|
|
1478
|
+
|
|
1479
|
+
<Fab
|
|
1480
|
+
icon={<Icon name="plus" color="white" />}
|
|
1481
|
+
onPress={handleAdd}
|
|
1482
|
+
position="bottom-right"
|
|
1483
|
+
/>
|
|
1484
|
+
|
|
1485
|
+
<Fab
|
|
1486
|
+
icon={<Icon name="plus" />}
|
|
1487
|
+
label="Add Item"
|
|
1488
|
+
position="bottom-right"
|
|
1489
|
+
/>
|
|
1490
|
+
```
|
|
1491
|
+
|
|
1492
|
+
**Props:**
|
|
1493
|
+
| Prop | Type | Default | Description |
|
|
1494
|
+
|------|------|---------|-------------|
|
|
1495
|
+
| icon | ReactNode | required | FAB icon |
|
|
1496
|
+
| label | string | - | Extended FAB text |
|
|
1497
|
+
| position | 'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left' | 'bottom-right' | Screen position |
|
|
1498
|
+
| size | 'sm' \| 'md' \| 'lg' | 'md' | FAB size |
|
|
1499
|
+
| onPress | () => void | - | Press handler |
|
|
1500
|
+
|
|
1501
|
+
---
|
|
1502
|
+
|
|
1503
|
+
#### Accordion
|
|
1504
|
+
Expandable sections with configurable icon position.
|
|
1505
|
+
|
|
1506
|
+
```tsx
|
|
1507
|
+
import { Accordion, AccordionItem, AccordionButton, AccordionPanel } from '@urbint/cl';
|
|
1508
|
+
|
|
1509
|
+
// Basic usage (icon on right by default)
|
|
1510
|
+
<Accordion defaultIndex={['faq-1']} allowMultiple>
|
|
1511
|
+
<AccordionItem value="faq-1">
|
|
1512
|
+
<AccordionButton>What is Urbint CL?</AccordionButton>
|
|
1513
|
+
<AccordionPanel>
|
|
1514
|
+
<Text>Enterprise-ready React Native component library.</Text>
|
|
1515
|
+
</AccordionPanel>
|
|
1516
|
+
</AccordionItem>
|
|
1517
|
+
<AccordionItem value="faq-2">
|
|
1518
|
+
<AccordionButton>How do I install it?</AccordionButton>
|
|
1519
|
+
<AccordionPanel>
|
|
1520
|
+
<Text>npm install @urbint/cl</Text>
|
|
1521
|
+
</AccordionPanel>
|
|
1522
|
+
</AccordionItem>
|
|
1523
|
+
</Accordion>
|
|
1524
|
+
|
|
1525
|
+
// Icon on left for all items
|
|
1526
|
+
<Accordion iconPosition="left" defaultIndex={['item-1']}>
|
|
1527
|
+
<AccordionItem value="item-1">
|
|
1528
|
+
<AccordionButton>Site Conditions</AccordionButton>
|
|
1529
|
+
<AccordionPanel>
|
|
1530
|
+
<Text>Site conditions content...</Text>
|
|
1531
|
+
</AccordionPanel>
|
|
1532
|
+
</AccordionItem>
|
|
1533
|
+
<AccordionItem value="item-2">
|
|
1534
|
+
<AccordionButton>Activities</AccordionButton>
|
|
1535
|
+
<AccordionPanel>
|
|
1536
|
+
<Text>Activities content...</Text>
|
|
1537
|
+
</AccordionPanel>
|
|
1538
|
+
</AccordionItem>
|
|
1539
|
+
</Accordion>
|
|
1540
|
+
|
|
1541
|
+
// Per-item icon position override
|
|
1542
|
+
<Accordion iconPosition="right">
|
|
1543
|
+
<AccordionItem value="item-1">
|
|
1544
|
+
<AccordionButton iconPosition="left">Override to left</AccordionButton>
|
|
1545
|
+
<AccordionPanel>
|
|
1546
|
+
<Text>This item has icon on left.</Text>
|
|
1547
|
+
</AccordionPanel>
|
|
1548
|
+
</AccordionItem>
|
|
1549
|
+
<AccordionItem value="item-2">
|
|
1550
|
+
<AccordionButton>Uses default (right)</AccordionButton>
|
|
1551
|
+
<AccordionPanel>
|
|
1552
|
+
<Text>This item uses default position.</Text>
|
|
1553
|
+
</AccordionPanel>
|
|
1554
|
+
</AccordionItem>
|
|
1555
|
+
</Accordion>
|
|
1556
|
+
```
|
|
1557
|
+
|
|
1558
|
+
**Accordion Props:**
|
|
1559
|
+
| Prop | Type | Default | Description |
|
|
1560
|
+
|------|------|---------|-------------|
|
|
1561
|
+
| defaultIndex | string[] | [] | Initially expanded |
|
|
1562
|
+
| allowMultiple | boolean | false | Multiple open sections |
|
|
1563
|
+
| allowToggle | boolean | true | Allow toggling items |
|
|
1564
|
+
| iconPosition | 'left' \| 'right' | 'right' | Position of expand/collapse icon for all items |
|
|
1565
|
+
| onChange | (index: string[]) => void | - | Change handler |
|
|
1566
|
+
|
|
1567
|
+
**AccordionButton Props:**
|
|
1568
|
+
| Prop | Type | Default | Description |
|
|
1569
|
+
|------|------|---------|-------------|
|
|
1570
|
+
| iconPosition | 'left' \| 'right' | - | Override icon position for this button (inherits from Accordion if not set) |
|
|
1571
|
+
|
|
1572
|
+
---
|
|
1573
|
+
|
|
1574
|
+
### Utility Components
|
|
1575
|
+
|
|
1576
|
+
#### Portal
|
|
1577
|
+
Render outside parent hierarchy.
|
|
1578
|
+
|
|
1579
|
+
```tsx
|
|
1580
|
+
import { Portal } from '@urbint/cl';
|
|
1581
|
+
|
|
1582
|
+
<Portal>
|
|
1583
|
+
<Modal>...</Modal>
|
|
1584
|
+
</Portal>
|
|
1585
|
+
```
|
|
1586
|
+
|
|
1587
|
+
---
|
|
1588
|
+
|
|
1589
|
+
## Hooks
|
|
1590
|
+
|
|
1591
|
+
### useDisclosure
|
|
1592
|
+
Manage open/close state.
|
|
1593
|
+
|
|
1594
|
+
```tsx
|
|
1595
|
+
import { useDisclosure } from '@urbint/cl';
|
|
1596
|
+
|
|
1597
|
+
const { isOpen, onOpen, onClose, onToggle } = useDisclosure();
|
|
1598
|
+
const { isOpen, onOpen, onClose } = useDisclosure({ defaultOpen: true });
|
|
1599
|
+
```
|
|
1600
|
+
|
|
1601
|
+
### useControllableState
|
|
1602
|
+
Controlled/uncontrolled state management.
|
|
1603
|
+
|
|
1604
|
+
```tsx
|
|
1605
|
+
import { useControllableState } from '@urbint/cl';
|
|
1606
|
+
|
|
1607
|
+
const [value, setValue] = useControllableState({
|
|
1608
|
+
value: controlledValue,
|
|
1609
|
+
defaultValue: 'default',
|
|
1610
|
+
onChange: onValueChange,
|
|
1611
|
+
});
|
|
1612
|
+
```
|
|
1613
|
+
|
|
1614
|
+
### useUnistyles
|
|
1615
|
+
Access theme and breakpoints.
|
|
1616
|
+
|
|
1617
|
+
```tsx
|
|
1618
|
+
import { useUnistyles } from 'react-native-unistyles';
|
|
1619
|
+
|
|
1620
|
+
const { theme, breakpoint } = useUnistyles();
|
|
1621
|
+
|
|
1622
|
+
<Box bg={theme.colors.background.primary}>
|
|
1623
|
+
<Text style={{ fontSize: breakpoint === 'xs' ? 14 : 16 }}>
|
|
1624
|
+
Responsive text
|
|
1625
|
+
</Text>
|
|
1626
|
+
</Box>
|
|
1627
|
+
```
|
|
1628
|
+
|
|
1629
|
+
---
|
|
1630
|
+
|
|
1631
|
+
## Theming
|
|
1632
|
+
|
|
1633
|
+
### Creating a Custom Theme
|
|
1634
|
+
|
|
1635
|
+
```tsx
|
|
1636
|
+
// src/styles/customTheme.ts
|
|
1637
|
+
import { lightTheme, darkTheme } from '@urbint/cl';
|
|
1638
|
+
|
|
1639
|
+
export const myLightTheme = {
|
|
1640
|
+
...lightTheme,
|
|
1641
|
+
colors: {
|
|
1642
|
+
...lightTheme.colors,
|
|
1643
|
+
brand: {
|
|
1644
|
+
primary: '#YOUR_PRIMARY_COLOR',
|
|
1645
|
+
secondary: '#YOUR_SECONDARY_COLOR',
|
|
1646
|
+
},
|
|
1647
|
+
},
|
|
1648
|
+
};
|
|
1649
|
+
|
|
1650
|
+
export const myDarkTheme = {
|
|
1651
|
+
...darkTheme,
|
|
1652
|
+
colors: {
|
|
1653
|
+
...darkTheme.colors,
|
|
1654
|
+
brand: {
|
|
1655
|
+
primary: '#YOUR_DARK_PRIMARY',
|
|
1656
|
+
secondary: '#YOUR_DARK_SECONDARY',
|
|
1657
|
+
},
|
|
1658
|
+
},
|
|
1659
|
+
};
|
|
1660
|
+
```
|
|
1661
|
+
|
|
1662
|
+
### Configuring Themes
|
|
1663
|
+
|
|
1664
|
+
```tsx
|
|
1665
|
+
// src/styles/unistyles.ts
|
|
1666
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
1667
|
+
import { myLightTheme, myDarkTheme } from './customTheme';
|
|
1668
|
+
|
|
1669
|
+
StyleSheet.configure({
|
|
1670
|
+
themes: {
|
|
1671
|
+
light: myLightTheme,
|
|
1672
|
+
dark: myDarkTheme,
|
|
1673
|
+
},
|
|
1674
|
+
settings: {
|
|
1675
|
+
adaptiveThemes: true, // Auto-switch based on OS preference
|
|
1676
|
+
},
|
|
1677
|
+
});
|
|
1678
|
+
```
|
|
1679
|
+
|
|
1680
|
+
### Switching Themes
|
|
1681
|
+
|
|
1682
|
+
```tsx
|
|
1683
|
+
import { UnistylesRuntime } from 'react-native-unistyles';
|
|
1684
|
+
|
|
1685
|
+
// Get current theme
|
|
1686
|
+
const currentTheme = UnistylesRuntime.themeName;
|
|
1687
|
+
|
|
1688
|
+
// Set theme
|
|
1689
|
+
UnistylesRuntime.setTheme('dark');
|
|
1690
|
+
|
|
1691
|
+
// Toggle theme
|
|
1692
|
+
const toggleTheme = () => {
|
|
1693
|
+
UnistylesRuntime.setTheme(
|
|
1694
|
+
UnistylesRuntime.themeName === 'light' ? 'dark' : 'light'
|
|
1695
|
+
);
|
|
1696
|
+
};
|
|
1697
|
+
```
|
|
1698
|
+
|
|
1699
|
+
---
|
|
1700
|
+
|
|
1701
|
+
## Best Practices
|
|
1702
|
+
|
|
1703
|
+
### Component Composition
|
|
1704
|
+
```tsx
|
|
1705
|
+
// ✅ Good - compose components with spacing tokens
|
|
1706
|
+
<Card>
|
|
1707
|
+
<CardHeader>
|
|
1708
|
+
<HStack space="md">
|
|
1709
|
+
<Avatar name="John" />
|
|
1710
|
+
<VStack>
|
|
1711
|
+
<Text weight="semiBold">John Doe</Text>
|
|
1712
|
+
<Text variant="caption">Software Engineer</Text>
|
|
1713
|
+
</VStack>
|
|
1714
|
+
</HStack>
|
|
1715
|
+
</CardHeader>
|
|
1716
|
+
<CardBody>
|
|
1717
|
+
<Text>Content here</Text>
|
|
1718
|
+
</CardBody>
|
|
1719
|
+
</Card>
|
|
1720
|
+
```
|
|
1721
|
+
|
|
1722
|
+
### Form Handling
|
|
1723
|
+
```tsx
|
|
1724
|
+
// ✅ Good - use FormControl with spacing tokens
|
|
1725
|
+
<VStack space="lg">
|
|
1726
|
+
<FormControl label="Name" isRequired>
|
|
1727
|
+
<Input value={name} onChange={setName} />
|
|
1728
|
+
</FormControl>
|
|
1729
|
+
|
|
1730
|
+
<FormControl label="Email" isInvalid={!!emailError} errorMessage={emailError}>
|
|
1731
|
+
<Input value={email} onChange={setEmail} />
|
|
1732
|
+
</FormControl>
|
|
1733
|
+
|
|
1734
|
+
<Button onPress={handleSubmit}>Submit</Button>
|
|
1735
|
+
</VStack>
|
|
1736
|
+
```
|
|
1737
|
+
|
|
1738
|
+
### Loading States
|
|
1739
|
+
```tsx
|
|
1740
|
+
// ✅ Good - show loading placeholders with spacing tokens
|
|
1741
|
+
{isLoading ? (
|
|
1742
|
+
<HStack space="md">
|
|
1743
|
+
<SkeletonCircle size={48} />
|
|
1744
|
+
<VStack space="sm" flex={1}>
|
|
1745
|
+
<Skeleton height={16} width="60%" />
|
|
1746
|
+
<Skeleton height={14} width="40%" />
|
|
1747
|
+
</VStack>
|
|
1748
|
+
</HStack>
|
|
1749
|
+
) : (
|
|
1750
|
+
<HStack space="md">
|
|
1751
|
+
<Avatar src={user.avatar} name={user.name} />
|
|
1752
|
+
<VStack>
|
|
1753
|
+
<Text weight="semiBold">{user.name}</Text>
|
|
1754
|
+
<Text variant="caption">{user.role}</Text>
|
|
1755
|
+
</VStack>
|
|
1756
|
+
</HStack>
|
|
1757
|
+
)}
|
|
1758
|
+
```
|
|
1759
|
+
|
|
1760
|
+
### Accessibility
|
|
1761
|
+
```tsx
|
|
1762
|
+
// ✅ Good - provide accessible labels
|
|
1763
|
+
<Button accessibilityLabel="Submit form">Submit</Button>
|
|
1764
|
+
<Icon name="delete" accessibilityLabel="Delete item" />
|
|
1765
|
+
<Input label="Email" accessibilityHint="Enter your email address" />
|
|
1766
|
+
```
|
|
1767
|
+
|
|
1768
|
+
---
|
|
1769
|
+
|
|
1770
|
+
## TypeScript Support
|
|
1771
|
+
|
|
1772
|
+
All components are fully typed. Import types as needed:
|
|
1773
|
+
|
|
1774
|
+
```tsx
|
|
1775
|
+
import type {
|
|
1776
|
+
ButtonProps,
|
|
1777
|
+
InputProps,
|
|
1778
|
+
CardProps,
|
|
1779
|
+
ModalProps,
|
|
1780
|
+
ToastOptions,
|
|
1781
|
+
SpacingToken, // Type for spacing tokens
|
|
1782
|
+
} from '@urbint/cl';
|
|
1783
|
+
```
|
|
1784
|
+
|
|
1785
|
+
### SpacingToken Type
|
|
1786
|
+
The `SpacingToken` type represents all valid spacing token names:
|
|
1787
|
+
|
|
1788
|
+
```tsx
|
|
1789
|
+
type SpacingToken =
|
|
1790
|
+
| 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl'
|
|
1791
|
+
| '0.5x' | 'base' | '2x' | '3x' | '4x' | '6x' | '8x' | '12x' | '18x';
|
|
1792
|
+
```
|
|
1793
|
+
|
|
1794
|
+
Components that accept spacing (Box, HStack, VStack, Grid) use `SpacingToken | number` so you can use either tokens or raw pixel values.
|
|
1795
|
+
|
|
1796
|
+
---
|
|
1797
|
+
|
|
1798
|
+
## Troubleshooting
|
|
1799
|
+
|
|
1800
|
+
### Metro bundler issues
|
|
1801
|
+
```bash
|
|
1802
|
+
# Clear cache and restart
|
|
1803
|
+
npx expo start --clear
|
|
1804
|
+
```
|
|
1805
|
+
|
|
1806
|
+
### Unistyles not working
|
|
1807
|
+
1. Ensure Babel plugin is configured
|
|
1808
|
+
2. Restart Metro bundler
|
|
1809
|
+
3. Check import order (styles before components)
|
|
1810
|
+
|
|
1811
|
+
### Theme not applying
|
|
1812
|
+
```tsx
|
|
1813
|
+
// Make sure to import styles first
|
|
1814
|
+
import '@urbint/cl/styles';
|
|
1815
|
+
// Then import components
|
|
1816
|
+
import { Button } from '@urbint/cl';
|
|
1817
|
+
```
|
|
1818
|
+
|
|
1819
|
+
---
|
|
1820
|
+
|
|
1821
|
+
## MCP Server Integration
|
|
1822
|
+
|
|
1823
|
+
The Urbint Component Library includes an MCP (Model Context Protocol) server that enables AI assistants to discover and use the design system programmatically.
|
|
1824
|
+
|
|
1825
|
+
### Setup
|
|
1826
|
+
|
|
1827
|
+
```bash
|
|
1828
|
+
# Install MCP server dependencies
|
|
1829
|
+
npm run mcp:install
|
|
1830
|
+
|
|
1831
|
+
# Build the MCP server
|
|
1832
|
+
npm run mcp:build
|
|
1833
|
+
```
|
|
1834
|
+
|
|
1835
|
+
### Configure in Cursor IDE
|
|
1836
|
+
|
|
1837
|
+
Add to your Cursor MCP settings (`~/.cursor/mcp.json`):
|
|
1838
|
+
|
|
1839
|
+
```json
|
|
1840
|
+
{
|
|
1841
|
+
"mcpServers": {
|
|
1842
|
+
"urbint-cl": {
|
|
1843
|
+
"command": "node",
|
|
1844
|
+
"args": ["/path/to/urbint-cl/mcp-server/dist/index.js"]
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
```
|
|
1849
|
+
|
|
1850
|
+
### Available MCP Tools
|
|
1851
|
+
|
|
1852
|
+
| Tool | Description |
|
|
1853
|
+
|------|-------------|
|
|
1854
|
+
| `list_components` | List all components, optionally filter by category |
|
|
1855
|
+
| `get_component` | Get detailed component documentation |
|
|
1856
|
+
| `search_components` | Search components by name, description, or tags |
|
|
1857
|
+
| `get_design_tokens` | Get design tokens (colors, spacing, etc.) |
|
|
1858
|
+
| `search_tokens` | Search for specific design tokens |
|
|
1859
|
+
| `generate_component_code` | Generate code snippets for components |
|
|
1860
|
+
| `get_form_pattern` | Generate form pattern code with validation |
|
|
1861
|
+
| `get_layout_pattern` | Generate layout pattern code |
|
|
1862
|
+
|
|
1863
|
+
### Example Usage
|
|
1864
|
+
|
|
1865
|
+
Once configured, ask your AI assistant:
|
|
1866
|
+
|
|
1867
|
+
- "List all form components in the Urbint design system"
|
|
1868
|
+
- "Show me how to use the Select component with multi-select"
|
|
1869
|
+
- "What colors are available in the design system?"
|
|
1870
|
+
- "Generate a login form with email and password"
|
|
1871
|
+
- "Show me a dashboard layout pattern"
|
|
1872
|
+
|
|
1873
|
+
### Available MCP Resources
|
|
1874
|
+
|
|
1875
|
+
- `urbint://docs/overview` - Library overview
|
|
1876
|
+
- `urbint://docs/components` - All components
|
|
1877
|
+
- `urbint://docs/tokens` - Design tokens
|
|
1878
|
+
- `urbint://docs/installation` - Installation guide
|
|
1879
|
+
- `urbint://component/{name}` - Individual component docs
|
|
1880
|
+
|
|
1881
|
+
---
|
|
1882
|
+
|
|
1883
|
+
## Version Compatibility
|
|
1884
|
+
|
|
1885
|
+
| urbint-cl | React Native | Expo SDK | Unistyles |
|
|
1886
|
+
|-----------|--------------|----------|-----------|
|
|
1887
|
+
| 1.x | 0.81+ | 54+ | 3.0+ |
|
|
1888
|
+
|
|
1889
|
+
---
|
|
1890
|
+
|
|
1891
|
+
*Last updated: January 2026*
|
|
1892
|
+
*Documentation version: 1.1.0*
|
|
1893
|
+
|