@frosted-ui/react-native 0.0.1-canary.93 → 0.0.1-canary.95
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/README.md +18 -5
- package/dist/components/avatar.d.ts.map +1 -1
- package/dist/components/avatar.js +1 -0
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.d.ts.map +1 -1
- package/dist/components/badge.js +2 -0
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +2 -1
- package/dist/components/card.js.map +1 -1
- package/dist/components/circular-progress.d.ts +21 -0
- package/dist/components/circular-progress.d.ts.map +1 -0
- package/dist/components/circular-progress.js +78 -0
- package/dist/components/circular-progress.js.map +1 -0
- package/dist/components/heading.d.ts +2 -2
- package/dist/components/heading.d.ts.map +1 -1
- package/dist/components/icon-button.js +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/link.d.ts +19 -0
- package/dist/components/link.d.ts.map +1 -0
- package/dist/components/link.js +68 -0
- package/dist/components/link.js.map +1 -0
- package/dist/components/list.d.ts +37 -0
- package/dist/components/list.d.ts.map +1 -0
- package/dist/components/list.js +112 -0
- package/dist/components/list.js.map +1 -0
- package/dist/components/select.js +1 -1
- package/dist/components/separator.d.ts.map +1 -1
- package/dist/components/separator.js +2 -3
- package/dist/components/separator.js.map +1 -1
- package/dist/components/slider.d.ts +30 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +248 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/components/text-area.d.ts.map +1 -1
- package/dist/components/text-area.js +1 -1
- package/dist/components/text-area.js.map +1 -1
- package/dist/components/text-field.d.ts.map +1 -1
- package/dist/components/text-field.js +41 -3
- package/dist/components/text-field.js.map +1 -1
- package/dist/components/text.d.ts +2 -2
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js +11 -2
- package/dist/components/text.js.map +1 -1
- package/docs/llm/COLOR_SYSTEM.md +799 -0
- package/docs/llm/COMPONENTS.md +1329 -0
- package/docs/llm/DESIGN_PATTERNS.md +2567 -0
- package/docs/llm/README.md +118 -0
- package/docs/llm/TYPOGRAPHY.md +516 -0
- package/package.json +9 -3
|
@@ -0,0 +1,1329 @@
|
|
|
1
|
+
# Frosted UI Components Reference
|
|
2
|
+
|
|
3
|
+
> **Critical**: Always import components from `@frosted-ui/react-native`, never from React Native directly for UI elements.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Button, Text, Card, Dialog, Slider, CircularProgress } from '@frosted-ui/react-native';
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Component Types
|
|
12
|
+
|
|
13
|
+
Frosted UI has two component patterns:
|
|
14
|
+
|
|
15
|
+
1. **Simple Components** — Single import, use directly with props
|
|
16
|
+
2. **Compound Components** — Dot notation (e.g., `Dialog.Root`, `Dialog.Content`)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Text Handling in Components
|
|
21
|
+
|
|
22
|
+
Some components automatically wrap text, others require explicit `<Text>` components:
|
|
23
|
+
|
|
24
|
+
### Components that auto-wrap text (pass plain strings):
|
|
25
|
+
|
|
26
|
+
These components internally render `<Text>`, so **do NOT wrap children in `<Text>`**:
|
|
27
|
+
|
|
28
|
+
| Component | Children |
|
|
29
|
+
| --------------------------- | ------------------ |
|
|
30
|
+
| `Link` | Plain string |
|
|
31
|
+
| `List.ItemTitle` | Plain string |
|
|
32
|
+
| `List.ItemDescription` | Plain string |
|
|
33
|
+
| `Select.Item` | Plain string |
|
|
34
|
+
| `Select.Label` | Plain string |
|
|
35
|
+
| `DropdownMenu.Item` | Plain string |
|
|
36
|
+
| `DropdownMenu.CheckboxItem` | Plain string |
|
|
37
|
+
| `DropdownMenu.RadioItem` | Plain string |
|
|
38
|
+
| `DropdownMenu.SubTrigger` | Plain string |
|
|
39
|
+
| `DropdownMenu.Label` | Plain string |
|
|
40
|
+
| `ContextMenu.Item` | Plain string |
|
|
41
|
+
| `ContextMenu.CheckboxItem` | Plain string |
|
|
42
|
+
| `ContextMenu.RadioItem` | Plain string |
|
|
43
|
+
| `ContextMenu.SubTrigger` | Plain string |
|
|
44
|
+
| `ContextMenu.Label` | Plain string |
|
|
45
|
+
| `Tabs.Trigger` | String or `<Text>` |
|
|
46
|
+
| `SegmentedControl.Trigger` | String or `<Text>` |
|
|
47
|
+
| `Accordion.Trigger` | Plain string |
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
// ✅ Correct
|
|
51
|
+
<Link onPress={() => {}}>Click here</Link>
|
|
52
|
+
<Select.Item value="1" label="Option 1">Option 1</Select.Item>
|
|
53
|
+
<DropdownMenu.Item>Edit</DropdownMenu.Item>
|
|
54
|
+
|
|
55
|
+
// ❌ Wrong - double-wrapped text
|
|
56
|
+
<Link onPress={() => {}}><Text>Click here</Text></Link>
|
|
57
|
+
<Select.Item value="1" label="Option 1"><Text>Option 1</Text></Select.Item>
|
|
58
|
+
<DropdownMenu.Item><Text>Edit</Text></DropdownMenu.Item>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Components that style children via context:
|
|
62
|
+
|
|
63
|
+
These use `TextStyleContext` to auto-style nested `<Text>` and `<Icon>`. **You must explicitly use `<Text>` for text content:**
|
|
64
|
+
|
|
65
|
+
| Component | Children |
|
|
66
|
+
| -------------- | --------------------------- |
|
|
67
|
+
| `Button` | `<Text>`, `<Icon>`, or both |
|
|
68
|
+
| `IconButton` | `<Icon>` only (no text) |
|
|
69
|
+
| `Badge` | `<Text>`, `<Icon>`, or both |
|
|
70
|
+
| `Callout.Root` | `<Text>`, `<Icon>`, etc. |
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// ✅ Correct - Text/Icon auto-styled by parent
|
|
74
|
+
<Button variant="solid">
|
|
75
|
+
<Text>Submit</Text>
|
|
76
|
+
</Button>
|
|
77
|
+
|
|
78
|
+
<IconButton variant="soft">
|
|
79
|
+
<Icon as={Settings} />
|
|
80
|
+
</IconButton>
|
|
81
|
+
|
|
82
|
+
<Badge color="success">
|
|
83
|
+
<Text>Active</Text>
|
|
84
|
+
</Badge>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Simple Components
|
|
90
|
+
|
|
91
|
+
### Button
|
|
92
|
+
|
|
93
|
+
Interactive button with variants and sizes.
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
<Button variant="solid" size="2" color="accent" onPress={handlePress}>
|
|
97
|
+
<Text>Click me</Text>
|
|
98
|
+
</Button>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Prop | Type | Default | Description |
|
|
102
|
+
| ---------- | ------------------------------------------- | ----------- | -------------- |
|
|
103
|
+
| `variant` | `'solid' \| 'soft' \| 'surface' \| 'ghost'` | `'surface'` | Visual style |
|
|
104
|
+
| `size` | `'1' \| '2' \| '3' \| '4'` | `'3'` | Button size |
|
|
105
|
+
| `color` | `Color` | `'accent'` | Color theme |
|
|
106
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
107
|
+
|
|
108
|
+
**Note**: Child `<Text>` components automatically receive correct styling.
|
|
109
|
+
|
|
110
|
+
#### Button Variants Guide
|
|
111
|
+
|
|
112
|
+
**Recommended pattern for most UIs:**
|
|
113
|
+
|
|
114
|
+
- **Primary action**: `variant="solid"`
|
|
115
|
+
- **Secondary action**: `variant="soft" color="gray"`
|
|
116
|
+
|
|
117
|
+
| Variant | Visual Style | When to Use |
|
|
118
|
+
| --------- | ---------------------------------------------- | -------------------------------------------------------------------- |
|
|
119
|
+
| `solid` | Vivid colored background, contrast text | **Primary CTA**: "Submit", "Save", "Continue". One per view. |
|
|
120
|
+
| `soft` | Tinted translucent background | **Secondary** (with `color="gray"`): "Cancel", "Back", "Dismiss" |
|
|
121
|
+
| `surface` | Neutral background, gray border, subtle shadow | Toolbar buttons, settings ("Edit", "Manage"), pairs with form inputs |
|
|
122
|
+
| `ghost` | Transparent, no border | Tertiary/inline actions, text-links, minimal UI |
|
|
123
|
+
|
|
124
|
+
> **Note**: `soft` with a non-gray color (e.g., `color="accent"`) is used for colored but less prominent actions like filter chips or toggle buttons.
|
|
125
|
+
|
|
126
|
+
> **IconButton**: Supports all the same variants as Button. Choose variant based on the same hierarchy rules above.
|
|
127
|
+
|
|
128
|
+
**Choosing the right variant:**
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
{
|
|
132
|
+
/* Primary action — use solid */
|
|
133
|
+
}
|
|
134
|
+
<Button variant="solid" color="accent">
|
|
135
|
+
<Text>Save Changes</Text>
|
|
136
|
+
</Button>;
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
/* Secondary action — use soft (often gray) */
|
|
140
|
+
}
|
|
141
|
+
<Button variant="soft" color="gray">
|
|
142
|
+
<Text>Cancel</Text>
|
|
143
|
+
</Button>;
|
|
144
|
+
|
|
145
|
+
{
|
|
146
|
+
/* Neutral/toolbar — use surface (default) */
|
|
147
|
+
}
|
|
148
|
+
<Button variant="surface">
|
|
149
|
+
<Text>Edit Profile</Text>
|
|
150
|
+
</Button>;
|
|
151
|
+
|
|
152
|
+
{
|
|
153
|
+
/* Tertiary/inline — use ghost */
|
|
154
|
+
}
|
|
155
|
+
<Button variant="ghost">
|
|
156
|
+
<Text>Learn more</Text>
|
|
157
|
+
</Button>;
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Common pairings:**
|
|
161
|
+
|
|
162
|
+
- **Dialog actions**: `solid` (confirm) + `soft color="gray"` (cancel)
|
|
163
|
+
- **Toolbars**: `surface` buttons alongside `TextField.Input` and `Select`
|
|
164
|
+
- **Inline text actions**: `ghost` for link-style buttons
|
|
165
|
+
- **Destructive actions**: Any variant with `color="danger"`
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### IconButton
|
|
170
|
+
|
|
171
|
+
Square button for icons only. Same API as Button.
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { X } from 'lucide-react-native';
|
|
175
|
+
|
|
176
|
+
<IconButton variant="ghost" onPress={handleClose}>
|
|
177
|
+
<Icon as={X} />
|
|
178
|
+
</IconButton>;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### Icon
|
|
184
|
+
|
|
185
|
+
Wrapper for Lucide icons with automatic color inheritance.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { ArrowRight } from 'lucide-react-native';
|
|
189
|
+
|
|
190
|
+
<Icon as={ArrowRight} size={16} />;
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
| Prop | Type | Default | Description |
|
|
194
|
+
| ------- | ------------ | --------- | ------------------------- |
|
|
195
|
+
| `as` | `LucideIcon` | required | The Lucide icon component |
|
|
196
|
+
| `size` | `number` | `14` | Icon size in pixels |
|
|
197
|
+
| `color` | `string` | inherited | Override color |
|
|
198
|
+
|
|
199
|
+
**Note**: Inside Button, Badge, or Callout, Icon inherits the parent's text color automatically.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### Badge
|
|
204
|
+
|
|
205
|
+
Small label for status or categories.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
<Badge variant="soft" size="1" color="success">
|
|
209
|
+
<Text>Active</Text>
|
|
210
|
+
</Badge>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
| Prop | Type | Default | Description |
|
|
214
|
+
| --------- | --------------------------------------------- | ---------- | ------------ |
|
|
215
|
+
| `variant` | `'solid' \| 'soft' \| 'surface' \| 'outline'` | `'soft'` | Visual style |
|
|
216
|
+
| `size` | `'1' \| '2'` | `'1'` | Badge size |
|
|
217
|
+
| `color` | `Color` | `'accent'` | Color theme |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### Link
|
|
222
|
+
|
|
223
|
+
Pressable text link with accent color.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
<Link onPress={() => navigation.navigate('Terms')}>Terms of Service</Link>
|
|
227
|
+
|
|
228
|
+
<Text>
|
|
229
|
+
Read our <Link onPress={() => {}}>Privacy Policy</Link>.
|
|
230
|
+
</Text>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| Prop | Type | Default | Description |
|
|
234
|
+
| ----------- | ------------------------------- | ---------- | --------------------------- |
|
|
235
|
+
| `size` | `'0'-'9'` | `'3'` | Text size |
|
|
236
|
+
| `weight` | `'light' \| ... \| 'bold'` | — | Font weight |
|
|
237
|
+
| `color` | `Color` | `'accent'` | Link color (uses a11 shade) |
|
|
238
|
+
| `underline` | `'auto' \| 'hover' \| 'always'` | `'auto'` | Underline behavior |
|
|
239
|
+
| `onPress` | `() => void` | — | Press handler |
|
|
240
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
241
|
+
|
|
242
|
+
> **Note**: `underline="auto"` shows underline on press (mobile equivalent of hover). Use `underline="always"` for always-visible underlines.
|
|
243
|
+
|
|
244
|
+
> **Inheritance**: When nested inside `<Text>`, Link inherits the parent's `size` and `weight`. This makes inline links match the surrounding text automatically.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### Avatar
|
|
249
|
+
|
|
250
|
+
User avatar with image or fallback initials.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
<Avatar src="https://example.com/photo.jpg" fallback="John Doe" size="3" shape="circle" />
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Prop | Type | Default | Description |
|
|
257
|
+
| ---------- | ---------------------- | ---------- | ---------------------------- |
|
|
258
|
+
| `src` | `string` | — | Image URL |
|
|
259
|
+
| `fallback` | `string \| ReactNode` | required | Initials or fallback content |
|
|
260
|
+
| `size` | `'0'-'9'` | `'3'` | Avatar size (16px to 160px) |
|
|
261
|
+
| `shape` | `'circle' \| 'square'` | `'circle'` | Avatar shape |
|
|
262
|
+
| `color` | `Color` | `'gray'` | Fallback background color |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### Card
|
|
267
|
+
|
|
268
|
+
Container with optional border and shadow.
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
<Card variant="surface">
|
|
272
|
+
<Text>Card content</Text>
|
|
273
|
+
</Card>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
| Prop | Type | Default | Description |
|
|
277
|
+
| --------- | -------------------------------- | ----------- | ------------ |
|
|
278
|
+
| `variant` | `'soft' \| 'surface' \| 'ghost'` | `'surface'` | Visual style |
|
|
279
|
+
|
|
280
|
+
#### Card Variants
|
|
281
|
+
|
|
282
|
+
| Variant | Visual Style | Use Case |
|
|
283
|
+
| --------- | ----------------------------------- | -------------------------------------------------- |
|
|
284
|
+
| `surface` | Solid bg, border, shadow | **Default** — Messages, profiles, elevated content |
|
|
285
|
+
| `soft` | Translucent tinted background | Tips, promotions, feature highlights |
|
|
286
|
+
| `ghost` | No background/border (padding only) | Section grouping, layout containers |
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
### List
|
|
291
|
+
|
|
292
|
+
Structured list container with items, slots, and separators. Renders a `Card` internally.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
<List.Root variant="surface">
|
|
296
|
+
<List.Item onPress={() => {}}>
|
|
297
|
+
<List.ItemSlot>
|
|
298
|
+
<Icon as={Bell} size={20} />
|
|
299
|
+
</List.ItemSlot>
|
|
300
|
+
<List.ItemContent>
|
|
301
|
+
<List.ItemTitle>Notifications</List.ItemTitle>
|
|
302
|
+
<List.ItemDescription>Manage alerts and sounds</List.ItemDescription>
|
|
303
|
+
</List.ItemContent>
|
|
304
|
+
<List.ItemSlot>
|
|
305
|
+
<Icon as={ChevronRight} size={16} />
|
|
306
|
+
</List.ItemSlot>
|
|
307
|
+
</List.Item>
|
|
308
|
+
<List.Separator />
|
|
309
|
+
<List.Item onPress={() => {}}>
|
|
310
|
+
<List.ItemSlot>
|
|
311
|
+
<Avatar fallback="JD" size="3" />
|
|
312
|
+
</List.ItemSlot>
|
|
313
|
+
<List.ItemContent>
|
|
314
|
+
<List.ItemTitle>John Doe</List.ItemTitle>
|
|
315
|
+
<List.ItemDescription>john@example.com</List.ItemDescription>
|
|
316
|
+
</List.ItemContent>
|
|
317
|
+
<List.ItemSlot>
|
|
318
|
+
<Badge color="success" size="1">
|
|
319
|
+
<Text>Active</Text>
|
|
320
|
+
</Badge>
|
|
321
|
+
</List.ItemSlot>
|
|
322
|
+
</List.Item>
|
|
323
|
+
</List.Root>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### List Components
|
|
327
|
+
|
|
328
|
+
| Component | Purpose |
|
|
329
|
+
| ---------------------- | ---------------------------------------------- |
|
|
330
|
+
| `List.Root` | Container (renders Card with `padding: 0`) |
|
|
331
|
+
| `List.Item` | Pressable row with hover/press states |
|
|
332
|
+
| `List.ItemSlot` | Left/right slot for icons, avatars, controls |
|
|
333
|
+
| `List.ItemContent` | Flexible center area for title and description |
|
|
334
|
+
| `List.ItemTitle` | Primary text (medium weight, auto-styled) |
|
|
335
|
+
| `List.ItemDescription` | Secondary text (gray, auto-styled) |
|
|
336
|
+
| `List.Separator` | Full-width divider between items |
|
|
337
|
+
|
|
338
|
+
#### List.Root Props
|
|
339
|
+
|
|
340
|
+
| Prop | Type | Default | Description |
|
|
341
|
+
| --------- | -------------------------------- | ----------- | ----------------- |
|
|
342
|
+
| `variant` | `'soft' \| 'surface' \| 'ghost'` | `'surface'` | Card visual style |
|
|
343
|
+
|
|
344
|
+
#### List.Item Props
|
|
345
|
+
|
|
346
|
+
| Prop | Type | Default | Description |
|
|
347
|
+
| ---------- | ------------ | ------- | ---------------------------------- |
|
|
348
|
+
| `onPress` | `() => void` | — | Makes item interactive (pressable) |
|
|
349
|
+
| `disabled` | `boolean` | `false` | Disables press handling |
|
|
350
|
+
| `style` | `ViewStyle` | — | Custom styles |
|
|
351
|
+
|
|
352
|
+
#### List.ItemTitle & List.ItemDescription
|
|
353
|
+
|
|
354
|
+
These render styled `<Text>` directly — pass plain strings:
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
// ✅ Correct
|
|
358
|
+
<List.ItemTitle>Settings</List.ItemTitle>
|
|
359
|
+
<List.ItemDescription>Manage your preferences</List.ItemDescription>
|
|
360
|
+
|
|
361
|
+
// ❌ Wrong - don't wrap in Text
|
|
362
|
+
<List.ItemTitle><Text>Settings</Text></List.ItemTitle>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
#### Common List Patterns
|
|
366
|
+
|
|
367
|
+
**Settings List:**
|
|
368
|
+
|
|
369
|
+
```tsx
|
|
370
|
+
<List.Root>
|
|
371
|
+
<List.Item>
|
|
372
|
+
<List.ItemSlot>
|
|
373
|
+
<View style={iconBoxStyle}>
|
|
374
|
+
<Icon as={Bell} size={20} color={colors.palettes.blue.a11} />
|
|
375
|
+
</View>
|
|
376
|
+
</List.ItemSlot>
|
|
377
|
+
<List.ItemContent>
|
|
378
|
+
<List.ItemTitle>Notifications</List.ItemTitle>
|
|
379
|
+
</List.ItemContent>
|
|
380
|
+
<List.ItemSlot>
|
|
381
|
+
<Switch checked={enabled} onCheckedChange={setEnabled} />
|
|
382
|
+
</List.ItemSlot>
|
|
383
|
+
</List.Item>
|
|
384
|
+
</List.Root>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Contact List with Avatars:**
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
<List.Root>
|
|
391
|
+
<List.Item onPress={() => {}}>
|
|
392
|
+
<List.ItemSlot>
|
|
393
|
+
<Avatar fallback="AK" size="3" color="blue" />
|
|
394
|
+
</List.ItemSlot>
|
|
395
|
+
<List.ItemContent>
|
|
396
|
+
<List.ItemTitle>Alex Kim</List.ItemTitle>
|
|
397
|
+
<List.ItemDescription>alex@example.com</List.ItemDescription>
|
|
398
|
+
</List.ItemContent>
|
|
399
|
+
<List.ItemSlot>
|
|
400
|
+
<Badge color="success" size="1">
|
|
401
|
+
<Text>Online</Text>
|
|
402
|
+
</Badge>
|
|
403
|
+
</List.ItemSlot>
|
|
404
|
+
</List.Item>
|
|
405
|
+
</List.Root>
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**With RadioGroup (Shipping Options):**
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
<RadioGroup.Root value={selected} onValueChange={setSelected}>
|
|
412
|
+
<List.Root>
|
|
413
|
+
<List.Item onPress={() => setSelected('standard')}>
|
|
414
|
+
<List.ItemSlot>
|
|
415
|
+
<RadioGroup.Item value="standard" />
|
|
416
|
+
</List.ItemSlot>
|
|
417
|
+
<List.ItemContent>
|
|
418
|
+
<List.ItemTitle>Standard Shipping</List.ItemTitle>
|
|
419
|
+
<List.ItemDescription>5-7 business days</List.ItemDescription>
|
|
420
|
+
</List.ItemContent>
|
|
421
|
+
<List.ItemSlot>
|
|
422
|
+
<Text weight="medium" color="success">
|
|
423
|
+
Free
|
|
424
|
+
</Text>
|
|
425
|
+
</List.ItemSlot>
|
|
426
|
+
</List.Item>
|
|
427
|
+
</List.Root>
|
|
428
|
+
</RadioGroup.Root>
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
### Separator
|
|
434
|
+
|
|
435
|
+
Visual divider between content.
|
|
436
|
+
|
|
437
|
+
```tsx
|
|
438
|
+
<Separator size="4" orientation="horizontal" />
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
| Prop | Type | Default | Description |
|
|
442
|
+
| ------------- | ---------------------------- | -------------- | ------------------------------- |
|
|
443
|
+
| `size` | `'1' \| '2' \| '3' \| '4'` | `'1'` | Length (16px, 32px, 64px, 100%) |
|
|
444
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direction |
|
|
445
|
+
| `color` | `Color` | `'gray'` | Separator color |
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
### Checkbox
|
|
450
|
+
|
|
451
|
+
Controlled checkbox input.
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
<Checkbox checked={isChecked} onCheckedChange={setIsChecked} size="2" color="accent" />
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
| Prop | Type | Default | Description |
|
|
458
|
+
| ----------------- | ---------------------------- | ---------- | ------------------------ |
|
|
459
|
+
| `checked` | `boolean` | — | Controlled checked state |
|
|
460
|
+
| `onCheckedChange` | `(checked: boolean) => void` | — | Change handler |
|
|
461
|
+
| `size` | `'1' \| '2' \| '3'` | `'2'` | Checkbox size |
|
|
462
|
+
| `color` | `Color` | `'accent'` | Checked color |
|
|
463
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### Switch
|
|
468
|
+
|
|
469
|
+
Toggle switch input.
|
|
470
|
+
|
|
471
|
+
```tsx
|
|
472
|
+
<Switch checked={isEnabled} onCheckedChange={setIsEnabled} size="2" color="accent" />
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
| Prop | Type | Default | Description |
|
|
476
|
+
| ----------------- | ---------------------------- | ---------- | ------------------------ |
|
|
477
|
+
| `checked` | `boolean` | — | Controlled checked state |
|
|
478
|
+
| `onCheckedChange` | `(checked: boolean) => void` | — | Change handler |
|
|
479
|
+
| `size` | `'1' \| '2' \| '3'` | `'2'` | Switch size |
|
|
480
|
+
| `color` | `Color` | `'accent'` | Active color |
|
|
481
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
### Progress
|
|
486
|
+
|
|
487
|
+
Progress bar indicator.
|
|
488
|
+
|
|
489
|
+
```tsx
|
|
490
|
+
<Progress value={75} max={100} size="2" color="accent" />
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
| Prop | Type | Default | Description |
|
|
494
|
+
| ------- | --------- | ---------- | ------------------------ |
|
|
495
|
+
| `value` | `number` | `0` | Current progress |
|
|
496
|
+
| `max` | `number` | `100` | Maximum value |
|
|
497
|
+
| `size` | `'1'-'6'` | `'6'` | Bar height (2px to 16px) |
|
|
498
|
+
| `color` | `Color` | `'accent'` | Fill color |
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
### CircularProgress
|
|
503
|
+
|
|
504
|
+
Circular progress indicator with SVG rendering.
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
<CircularProgress value={75} max={100} size="5" color="accent" />
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
| Prop | Type | Default | Description |
|
|
511
|
+
| ------- | --------- | ---------- | ---------------------------- |
|
|
512
|
+
| `value` | `number` | `0` | Current progress |
|
|
513
|
+
| `max` | `number` | `100` | Maximum value |
|
|
514
|
+
| `size` | `'1'-'9'` | `'3'` | Ring size (16px to 72px) |
|
|
515
|
+
| `color` | `Color` | `'accent'` | Progress indicator color |
|
|
516
|
+
|
|
517
|
+
#### Size Reference
|
|
518
|
+
|
|
519
|
+
| Size | Diameter | Stroke Width | Use Case |
|
|
520
|
+
| ----- | -------- | ------------ | ------------------------------ |
|
|
521
|
+
| `'1'` | 16px | 3px | Inline indicators |
|
|
522
|
+
| `'2'` | 20px | 4px | Compact UI |
|
|
523
|
+
| `'3'` | 24px | 5px | **Default** — small indicators |
|
|
524
|
+
| `'4'` | 32px | 5px | List items, stats |
|
|
525
|
+
| `'5'` | 40px | 6px | Card displays |
|
|
526
|
+
| `'6'` | 48px | 7px | Prominent indicators |
|
|
527
|
+
| `'7'` | 56px | 8px | Dashboard widgets |
|
|
528
|
+
| `'8'` | 64px | 9px | Large displays |
|
|
529
|
+
| `'9'` | 72px | 10px | Hero/featured metrics |
|
|
530
|
+
|
|
531
|
+
#### Common Patterns
|
|
532
|
+
|
|
533
|
+
**With value inside:**
|
|
534
|
+
|
|
535
|
+
```tsx
|
|
536
|
+
<View style={{ position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
|
|
537
|
+
<CircularProgress size="6" value={75} color="cyan" />
|
|
538
|
+
<View style={{ position: 'absolute' }}>
|
|
539
|
+
<Text size="2" weight="bold">75%</Text>
|
|
540
|
+
</View>
|
|
541
|
+
</View>
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**System health dashboard:**
|
|
545
|
+
|
|
546
|
+
```tsx
|
|
547
|
+
<View style={{ flexDirection: 'row', gap: 16 }}>
|
|
548
|
+
<View style={{ alignItems: 'center', gap: 4 }}>
|
|
549
|
+
<CircularProgress size="5" value={42} color="cyan" />
|
|
550
|
+
<Text size="1" color="gray">CPU</Text>
|
|
551
|
+
</View>
|
|
552
|
+
<View style={{ alignItems: 'center', gap: 4 }}>
|
|
553
|
+
<CircularProgress size="5" value={68} color="violet" />
|
|
554
|
+
<Text size="1" color="gray">Memory</Text>
|
|
555
|
+
</View>
|
|
556
|
+
<View style={{ alignItems: 'center', gap: 4 }}>
|
|
557
|
+
<CircularProgress size="5" value={85} color="orange" />
|
|
558
|
+
<Text size="1" color="gray">Disk</Text>
|
|
559
|
+
</View>
|
|
560
|
+
</View>
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
### Slider
|
|
566
|
+
|
|
567
|
+
Draggable slider for selecting a value from a range.
|
|
568
|
+
|
|
569
|
+
```tsx
|
|
570
|
+
const [volume, setVolume] = React.useState(50);
|
|
571
|
+
|
|
572
|
+
<Slider value={volume} onValueChange={setVolume} min={0} max={100} />;
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
| Prop | Type | Default | Description |
|
|
576
|
+
| --------------- | ------------------------- | ---------- | ---------------------------- |
|
|
577
|
+
| `value` | `number` | — | Controlled value |
|
|
578
|
+
| `defaultValue` | `number` | `50` | Initial value (uncontrolled) |
|
|
579
|
+
| `min` | `number` | `0` | Minimum value |
|
|
580
|
+
| `max` | `number` | `100` | Maximum value |
|
|
581
|
+
| `step` | `number` | `1` | Step increment |
|
|
582
|
+
| `onValueChange` | `(value: number) => void` | — | Change handler |
|
|
583
|
+
| `size` | `'1' \| '2' \| '3'` | `'2'` | Track and thumb size |
|
|
584
|
+
| `color` | `Color` | `'accent'` | Range fill color |
|
|
585
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
586
|
+
|
|
587
|
+
#### Slider with Label Pattern
|
|
588
|
+
|
|
589
|
+
```tsx
|
|
590
|
+
function VolumeSlider() {
|
|
591
|
+
const [value, setValue] = React.useState(75);
|
|
592
|
+
return (
|
|
593
|
+
<View style={{ gap: 8 }}>
|
|
594
|
+
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
595
|
+
<Text size="2">Volume</Text>
|
|
596
|
+
<Text size="2" color="gray">
|
|
597
|
+
{value}%
|
|
598
|
+
</Text>
|
|
599
|
+
</View>
|
|
600
|
+
<Slider value={value} onValueChange={setValue} />
|
|
601
|
+
</View>
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
#### Custom Range Example
|
|
607
|
+
|
|
608
|
+
```tsx
|
|
609
|
+
{
|
|
610
|
+
/* Playback speed: 0.5x to 2.0x */
|
|
611
|
+
}
|
|
612
|
+
<Slider
|
|
613
|
+
value={playbackSpeed}
|
|
614
|
+
onValueChange={setPlaybackSpeed}
|
|
615
|
+
min={50}
|
|
616
|
+
max={200}
|
|
617
|
+
step={25}
|
|
618
|
+
color="purple"
|
|
619
|
+
/>;
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
### Spinner
|
|
625
|
+
|
|
626
|
+
Loading indicator.
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
<Spinner size="2" />;
|
|
630
|
+
|
|
631
|
+
{
|
|
632
|
+
/* Or wrap content to show spinner while loading */
|
|
633
|
+
}
|
|
634
|
+
<Spinner loading={isLoading}>
|
|
635
|
+
<Text>Content</Text>
|
|
636
|
+
</Spinner>;
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
| Prop | Type | Default | Description |
|
|
640
|
+
| ---------- | ----------- | ------- | ----------------------------- |
|
|
641
|
+
| `size` | `'1'-'6'` | `'2'` | Spinner size |
|
|
642
|
+
| `loading` | `boolean` | `true` | Show spinner |
|
|
643
|
+
| `children` | `ReactNode` | — | Content to hide while loading |
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
### Tooltip
|
|
648
|
+
|
|
649
|
+
Hover/press tooltip.
|
|
650
|
+
|
|
651
|
+
```tsx
|
|
652
|
+
<Tooltip content="Helpful information">
|
|
653
|
+
<Button>
|
|
654
|
+
<Text>Hover me</Text>
|
|
655
|
+
</Button>
|
|
656
|
+
</Tooltip>
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
| Prop | Type | Default | Description |
|
|
660
|
+
| --------------- | ---------------------------------------- | -------- | ------------------------- |
|
|
661
|
+
| `content` | `ReactNode` | required | Tooltip content |
|
|
662
|
+
| `delayDuration` | `number` | `400` | Delay before showing (ms) |
|
|
663
|
+
| `side` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | Position |
|
|
664
|
+
| `sideOffset` | `number` | `4` | Offset from trigger |
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
### AspectRatio
|
|
669
|
+
|
|
670
|
+
Maintains aspect ratio for child content.
|
|
671
|
+
|
|
672
|
+
```tsx
|
|
673
|
+
<AspectRatio ratio={16 / 9}>
|
|
674
|
+
<Image source={{ uri: '...' }} style={{ width: '100%', height: '100%' }} />
|
|
675
|
+
</AspectRatio>
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
## Compound Components
|
|
681
|
+
|
|
682
|
+
### TextField
|
|
683
|
+
|
|
684
|
+
Text input with optional slots for icons/buttons.
|
|
685
|
+
|
|
686
|
+
```tsx
|
|
687
|
+
{
|
|
688
|
+
/* Simple usage */
|
|
689
|
+
}
|
|
690
|
+
<TextField.Input placeholder="Enter text..." />;
|
|
691
|
+
|
|
692
|
+
{
|
|
693
|
+
/* With slots */
|
|
694
|
+
}
|
|
695
|
+
<TextField.Root variant="surface">
|
|
696
|
+
<TextField.Slot>
|
|
697
|
+
<Icon as={Search} size={16} />
|
|
698
|
+
</TextField.Slot>
|
|
699
|
+
<TextField.Input placeholder="Search..." />
|
|
700
|
+
<TextField.Slot>
|
|
701
|
+
<IconButton variant="ghost" size="1">
|
|
702
|
+
<Icon as={X} size={14} />
|
|
703
|
+
</IconButton>
|
|
704
|
+
</TextField.Slot>
|
|
705
|
+
</TextField.Root>;
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**TextField.Root Props:**
|
|
709
|
+
| Prop | Type | Default |
|
|
710
|
+
|------|------|---------|
|
|
711
|
+
| `size` | `'1' \| '2' \| '3' \| '4'` | `'3'` |
|
|
712
|
+
| `variant` | `'surface' \| 'soft'` | `'surface'` |
|
|
713
|
+
| `color` | `Color` | — |
|
|
714
|
+
| `disabled` | `boolean` | `false` |
|
|
715
|
+
|
|
716
|
+
**TextField.Input**: Accepts all React Native `TextInput` props.
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
### TextArea
|
|
721
|
+
|
|
722
|
+
Multi-line text input.
|
|
723
|
+
|
|
724
|
+
```tsx
|
|
725
|
+
<TextArea placeholder="Write a message..." />
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
| Prop | Type | Default |
|
|
729
|
+
| --------- | -------------------------- | ----------- |
|
|
730
|
+
| `size` | `'1' \| '2' \| '3' \| '4'` | `'3'` |
|
|
731
|
+
| `variant` | `'surface' \| 'soft'` | `'surface'` |
|
|
732
|
+
| `color` | `Color` | — |
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
### Select
|
|
737
|
+
|
|
738
|
+
Dropdown selection.
|
|
739
|
+
|
|
740
|
+
```tsx
|
|
741
|
+
<Select.Root value={value} onValueChange={setValue}>
|
|
742
|
+
<Select.Trigger>
|
|
743
|
+
<Select.Value placeholder="Choose option..." />
|
|
744
|
+
</Select.Trigger>
|
|
745
|
+
<Select.Content>
|
|
746
|
+
<Select.Item value="option1" label="Option 1">
|
|
747
|
+
Option 1
|
|
748
|
+
</Select.Item>
|
|
749
|
+
<Select.Item value="option2" label="Option 2">
|
|
750
|
+
Option 2
|
|
751
|
+
</Select.Item>
|
|
752
|
+
<Select.Separator />
|
|
753
|
+
<Select.Group>
|
|
754
|
+
<Select.Label>More Options</Select.Label>
|
|
755
|
+
<Select.Item value="option3" label="Option 3">
|
|
756
|
+
Option 3
|
|
757
|
+
</Select.Item>
|
|
758
|
+
</Select.Group>
|
|
759
|
+
</Select.Content>
|
|
760
|
+
</Select.Root>
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
> **Note**: `Select.Item` children should be plain text, not wrapped in `<Text>`. The component handles text styling internally.
|
|
764
|
+
|
|
765
|
+
**Select.Root Props:**
|
|
766
|
+
| Prop | Type | Default |
|
|
767
|
+
|------|------|---------|
|
|
768
|
+
| `size` | `'1' \| '2' \| '3' \| '4'` | `'3'` |
|
|
769
|
+
| `value` | `{ value: string; label: string }` | — |
|
|
770
|
+
| `onValueChange` | `(value) => void` | — |
|
|
771
|
+
|
|
772
|
+
**Select.Trigger Props:**
|
|
773
|
+
| Prop | Type | Default |
|
|
774
|
+
|------|------|---------|
|
|
775
|
+
| `variant` | `'surface' \| 'soft' \| 'ghost'` | `'surface'` |
|
|
776
|
+
| `color` | `Color` | — |
|
|
777
|
+
|
|
778
|
+
**Select.Content Props:**
|
|
779
|
+
| Prop | Type | Default |
|
|
780
|
+
|------|------|---------|
|
|
781
|
+
| `align` | `'start' \| 'center' \| 'end'` | `'start'` |
|
|
782
|
+
|
|
783
|
+
**Select.Item Props:**
|
|
784
|
+
| Prop | Type | Required |
|
|
785
|
+
|------|------|----------|
|
|
786
|
+
| `value` | `string` | Yes |
|
|
787
|
+
| `label` | `string` | Yes |
|
|
788
|
+
| `children` | `string` (plain text) | Yes |
|
|
789
|
+
|
|
790
|
+
> **Tip**: Use `align="end"` when the trigger is on the right side of the screen, `align="start"` when on the left.
|
|
791
|
+
|
|
792
|
+
---
|
|
793
|
+
|
|
794
|
+
### RadioGroup
|
|
795
|
+
|
|
796
|
+
Radio button group.
|
|
797
|
+
|
|
798
|
+
```tsx
|
|
799
|
+
<RadioGroup.Root value={selected} onValueChange={setSelected}>
|
|
800
|
+
<View style={{ gap: 8 }}>
|
|
801
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
802
|
+
<RadioGroup.Item value="option1" />
|
|
803
|
+
<Text>Option 1</Text>
|
|
804
|
+
</View>
|
|
805
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
806
|
+
<RadioGroup.Item value="option2" />
|
|
807
|
+
<Text>Option 2</Text>
|
|
808
|
+
</View>
|
|
809
|
+
</View>
|
|
810
|
+
</RadioGroup.Root>
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
**RadioGroup.Root Props:**
|
|
814
|
+
| Prop | Type | Default |
|
|
815
|
+
|------|------|---------|
|
|
816
|
+
| `value` | `string` | — |
|
|
817
|
+
| `onValueChange` | `(value: string) => void` | — |
|
|
818
|
+
| `size` | `'1' \| '2' \| '3'` | `'2'` |
|
|
819
|
+
| `color` | `Color` | `'accent'` |
|
|
820
|
+
|
|
821
|
+
---
|
|
822
|
+
|
|
823
|
+
### Dialog
|
|
824
|
+
|
|
825
|
+
Modal dialog.
|
|
826
|
+
|
|
827
|
+
```tsx
|
|
828
|
+
<Dialog.Root open={isOpen} onOpenChange={setIsOpen}>
|
|
829
|
+
<Dialog.Trigger>
|
|
830
|
+
<Button>
|
|
831
|
+
<Text>Open Dialog</Text>
|
|
832
|
+
</Button>
|
|
833
|
+
</Dialog.Trigger>
|
|
834
|
+
<Dialog.Content size="3">
|
|
835
|
+
<Dialog.Title>Dialog Title</Dialog.Title>
|
|
836
|
+
<Dialog.Description>This is a description of the dialog.</Dialog.Description>
|
|
837
|
+
|
|
838
|
+
{/* Your content here */}
|
|
839
|
+
|
|
840
|
+
<View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
|
|
841
|
+
<Dialog.Close>
|
|
842
|
+
<Button variant="soft" color="gray">
|
|
843
|
+
<Text>Cancel</Text>
|
|
844
|
+
</Button>
|
|
845
|
+
</Dialog.Close>
|
|
846
|
+
<Dialog.Close>
|
|
847
|
+
<Button variant="solid">
|
|
848
|
+
<Text>Confirm</Text>
|
|
849
|
+
</Button>
|
|
850
|
+
</Dialog.Close>
|
|
851
|
+
</View>
|
|
852
|
+
</Dialog.Content>
|
|
853
|
+
</Dialog.Root>
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
**Dialog.Content Props:**
|
|
857
|
+
| Prop | Type | Default |
|
|
858
|
+
|------|------|---------|
|
|
859
|
+
| `size` | `'1' \| '2' \| '3' \| '4'` | `'3'` |
|
|
860
|
+
|
|
861
|
+
---
|
|
862
|
+
|
|
863
|
+
### AlertDialog
|
|
864
|
+
|
|
865
|
+
Confirmation dialog with action/cancel pattern.
|
|
866
|
+
|
|
867
|
+
```tsx
|
|
868
|
+
<AlertDialog.Root>
|
|
869
|
+
<AlertDialog.Trigger>
|
|
870
|
+
<Button color="danger">
|
|
871
|
+
<Text>Delete</Text>
|
|
872
|
+
</Button>
|
|
873
|
+
</AlertDialog.Trigger>
|
|
874
|
+
<AlertDialog.Content>
|
|
875
|
+
<AlertDialog.Header>
|
|
876
|
+
<AlertDialog.Title>Delete Item</AlertDialog.Title>
|
|
877
|
+
<AlertDialog.Description>This action cannot be undone.</AlertDialog.Description>
|
|
878
|
+
</AlertDialog.Header>
|
|
879
|
+
<AlertDialog.Footer>
|
|
880
|
+
<AlertDialog.Cancel>
|
|
881
|
+
<Button variant="soft" color="gray">
|
|
882
|
+
<Text>Cancel</Text>
|
|
883
|
+
</Button>
|
|
884
|
+
</AlertDialog.Cancel>
|
|
885
|
+
<AlertDialog.Action>
|
|
886
|
+
<Button variant="solid" color="danger">
|
|
887
|
+
<Text>Delete</Text>
|
|
888
|
+
</Button>
|
|
889
|
+
</AlertDialog.Action>
|
|
890
|
+
</AlertDialog.Footer>
|
|
891
|
+
</AlertDialog.Content>
|
|
892
|
+
</AlertDialog.Root>
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
|
|
897
|
+
### Popover
|
|
898
|
+
|
|
899
|
+
Floating content panel.
|
|
900
|
+
|
|
901
|
+
```tsx
|
|
902
|
+
<Popover.Root>
|
|
903
|
+
<Popover.Trigger>
|
|
904
|
+
<Button>
|
|
905
|
+
<Text>Open Popover</Text>
|
|
906
|
+
</Button>
|
|
907
|
+
</Popover.Trigger>
|
|
908
|
+
<Popover.Content align="start">
|
|
909
|
+
<View style={{ padding: 16 }}>
|
|
910
|
+
<Text>Popover content</Text>
|
|
911
|
+
</View>
|
|
912
|
+
</Popover.Content>
|
|
913
|
+
</Popover.Root>
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
**Popover.Content Props:**
|
|
917
|
+
| Prop | Type | Default |
|
|
918
|
+
|------|------|---------|
|
|
919
|
+
| `align` | `'start' \| 'center' \| 'end'` | `'center'` |
|
|
920
|
+
|
|
921
|
+
> **Tip**: Use `align="end"` when trigger is on the right, `align="start"` when on the left.
|
|
922
|
+
|
|
923
|
+
---
|
|
924
|
+
|
|
925
|
+
### DropdownMenu
|
|
926
|
+
|
|
927
|
+
Menu triggered by button press.
|
|
928
|
+
|
|
929
|
+
```tsx
|
|
930
|
+
<DropdownMenu.Root>
|
|
931
|
+
<DropdownMenu.Trigger>
|
|
932
|
+
<Button>
|
|
933
|
+
<Text>Actions</Text>
|
|
934
|
+
</Button>
|
|
935
|
+
</DropdownMenu.Trigger>
|
|
936
|
+
<DropdownMenu.Content align="end">
|
|
937
|
+
<DropdownMenu.Item onSelect={() => handleEdit()}>Edit</DropdownMenu.Item>
|
|
938
|
+
<DropdownMenu.Item onSelect={() => handleDuplicate()}>Duplicate</DropdownMenu.Item>
|
|
939
|
+
<DropdownMenu.Separator />
|
|
940
|
+
<DropdownMenu.Item onSelect={() => handleDelete()} color="danger">
|
|
941
|
+
Delete
|
|
942
|
+
</DropdownMenu.Item>
|
|
943
|
+
</DropdownMenu.Content>
|
|
944
|
+
</DropdownMenu.Root>
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
> **Note**: `DropdownMenu.Item` children should be plain text, not wrapped in `<Text>`. The component handles text styling internally.
|
|
948
|
+
|
|
949
|
+
**DropdownMenu.Content Props:**
|
|
950
|
+
| Prop | Type | Default |
|
|
951
|
+
|------|------|---------|
|
|
952
|
+
| `align` | `'start' \| 'center' \| 'end'` | `'start'` |
|
|
953
|
+
|
|
954
|
+
> **Tip**: Use `align="end"` when trigger is on the right, `align="start"` when on the left.
|
|
955
|
+
|
|
956
|
+
---
|
|
957
|
+
|
|
958
|
+
### ContextMenu
|
|
959
|
+
|
|
960
|
+
Long-press menu (mobile) or right-click menu (web).
|
|
961
|
+
|
|
962
|
+
```tsx
|
|
963
|
+
<ContextMenu.Root>
|
|
964
|
+
<ContextMenu.Trigger>
|
|
965
|
+
<Card>
|
|
966
|
+
<Text>Long press me</Text>
|
|
967
|
+
</Card>
|
|
968
|
+
</ContextMenu.Trigger>
|
|
969
|
+
<ContextMenu.Content>
|
|
970
|
+
<ContextMenu.Item onSelect={() => handleAction()}>Action</ContextMenu.Item>
|
|
971
|
+
</ContextMenu.Content>
|
|
972
|
+
</ContextMenu.Root>
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
> **Note**: `ContextMenu.Item` children should be plain text, not wrapped in `<Text>`. The component handles text styling internally.
|
|
976
|
+
|
|
977
|
+
---
|
|
978
|
+
|
|
979
|
+
### Tabs
|
|
980
|
+
|
|
981
|
+
Tabbed content panels.
|
|
982
|
+
|
|
983
|
+
```tsx
|
|
984
|
+
<Tabs.Root value={activeTab} onValueChange={setActiveTab}>
|
|
985
|
+
<Tabs.List>
|
|
986
|
+
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
|
|
987
|
+
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
|
|
988
|
+
</Tabs.List>
|
|
989
|
+
<Tabs.Content value="tab1">
|
|
990
|
+
<Text>Content for tab 1</Text>
|
|
991
|
+
</Tabs.Content>
|
|
992
|
+
<Tabs.Content value="tab2">
|
|
993
|
+
<Text>Content for tab 2</Text>
|
|
994
|
+
</Tabs.Content>
|
|
995
|
+
</Tabs.Root>
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
> **Note**: `Tabs.Trigger` auto-wraps string children in `<Text>`. You can pass plain strings or `<Text>` components.
|
|
999
|
+
|
|
1000
|
+
**Tabs.Root Props:**
|
|
1001
|
+
| Prop | Type | Default |
|
|
1002
|
+
|------|------|---------|
|
|
1003
|
+
| `value` | `string` | — |
|
|
1004
|
+
| `onValueChange` | `(value: string) => void` | — |
|
|
1005
|
+
| `size` | `'1' \| '2'` | `'2'` |
|
|
1006
|
+
| `color` | `Color` | `'accent'` |
|
|
1007
|
+
|
|
1008
|
+
---
|
|
1009
|
+
|
|
1010
|
+
### SegmentedControl
|
|
1011
|
+
|
|
1012
|
+
Segmented selection control.
|
|
1013
|
+
|
|
1014
|
+
```tsx
|
|
1015
|
+
<SegmentedControl.Root value={view} onValueChange={setView}>
|
|
1016
|
+
<SegmentedControl.List>
|
|
1017
|
+
<SegmentedControl.Trigger value="list">List</SegmentedControl.Trigger>
|
|
1018
|
+
<SegmentedControl.Trigger value="grid">Grid</SegmentedControl.Trigger>
|
|
1019
|
+
</SegmentedControl.List>
|
|
1020
|
+
</SegmentedControl.Root>
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
> **Note**: `SegmentedControl.Trigger` auto-wraps string children in `<Text>`. You can pass plain strings or `<Text>` components.
|
|
1024
|
+
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
### Accordion
|
|
1028
|
+
|
|
1029
|
+
Collapsible content sections.
|
|
1030
|
+
|
|
1031
|
+
```tsx
|
|
1032
|
+
<Accordion.Root type="single" collapsible>
|
|
1033
|
+
<Accordion.Item value="item1">
|
|
1034
|
+
<Accordion.Trigger>Section 1</Accordion.Trigger>
|
|
1035
|
+
<Accordion.Content>
|
|
1036
|
+
<Text>Content for section 1</Text>
|
|
1037
|
+
</Accordion.Content>
|
|
1038
|
+
</Accordion.Item>
|
|
1039
|
+
<Accordion.Item value="item2">
|
|
1040
|
+
<Accordion.Trigger>Section 2</Accordion.Trigger>
|
|
1041
|
+
<Accordion.Content>
|
|
1042
|
+
<Text>Content for section 2</Text>
|
|
1043
|
+
</Accordion.Content>
|
|
1044
|
+
</Accordion.Item>
|
|
1045
|
+
</Accordion.Root>
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
> **Note**: `Accordion.Trigger` internally wraps children in `<Text>`. Pass plain strings, not `<Text>` components.
|
|
1049
|
+
|
|
1050
|
+
---
|
|
1051
|
+
|
|
1052
|
+
### Callout
|
|
1053
|
+
|
|
1054
|
+
Highlighted message box.
|
|
1055
|
+
|
|
1056
|
+
```tsx
|
|
1057
|
+
import { Info } from 'lucide-react-native';
|
|
1058
|
+
|
|
1059
|
+
<Callout.Root variant="soft" color="info">
|
|
1060
|
+
<Callout.Icon>
|
|
1061
|
+
<Icon as={Info} size={16} />
|
|
1062
|
+
</Callout.Icon>
|
|
1063
|
+
<Callout.Text>
|
|
1064
|
+
<Text>This is an informational message.</Text>
|
|
1065
|
+
</Callout.Text>
|
|
1066
|
+
</Callout.Root>;
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
**Callout.Root Props:**
|
|
1070
|
+
| Prop | Type | Default |
|
|
1071
|
+
|------|------|---------|
|
|
1072
|
+
| `variant` | `'soft' \| 'surface' \| 'outline'` | `'soft'` |
|
|
1073
|
+
| `size` | `'1' \| '2' \| '3'` | `'2'` |
|
|
1074
|
+
| `color` | `Color` | `'accent'` |
|
|
1075
|
+
|
|
1076
|
+
---
|
|
1077
|
+
|
|
1078
|
+
### Skeleton
|
|
1079
|
+
|
|
1080
|
+
Loading placeholder that matches actual component dimensions.
|
|
1081
|
+
|
|
1082
|
+
**Skeleton.Avatar** — Uses the same `size` and `shape` props as `<Avatar>`. The skeleton will have identical dimensions to a real avatar.
|
|
1083
|
+
|
|
1084
|
+
```tsx
|
|
1085
|
+
{/* These have identical dimensions */}
|
|
1086
|
+
<Avatar fallback="JD" size="3" shape="circle" />
|
|
1087
|
+
<Skeleton.Avatar size="3" shape="circle" />
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
**Skeleton.Text** — Uses the same `size` scale as `<Text>` and `<Heading>`. The skeleton height matches the text's `lineHeight`, and the inner bar matches the `fontSize`.
|
|
1091
|
+
|
|
1092
|
+
```tsx
|
|
1093
|
+
{/* These align perfectly when swapped */}
|
|
1094
|
+
<Text size="2">Loading complete</Text>
|
|
1095
|
+
<Skeleton.Text size="2" />
|
|
1096
|
+
|
|
1097
|
+
{/* Match a Heading */}
|
|
1098
|
+
<Heading size="6">Page Title</Heading>
|
|
1099
|
+
<Skeleton.Text size="6" />
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
**Skeleton.Rect** — For custom shapes. Define dimensions via `style`.
|
|
1103
|
+
|
|
1104
|
+
```tsx
|
|
1105
|
+
<Skeleton.Rect style={{ width: 200, height: 100, borderRadius: 8 }} />
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
| Component | Props | Matches |
|
|
1109
|
+
| ----------------- | --------------------------- | ---------------------------------- |
|
|
1110
|
+
| `Skeleton.Avatar` | `size` (`'0'-'9'`), `shape` | `<Avatar>` dimensions exactly |
|
|
1111
|
+
| `Skeleton.Text` | `size` (`'0'-'9'`) | `<Text>` / `<Heading>` line height |
|
|
1112
|
+
| `Skeleton.Rect` | `style` | Custom dimensions |
|
|
1113
|
+
|
|
1114
|
+
---
|
|
1115
|
+
|
|
1116
|
+
### HoverCard
|
|
1117
|
+
|
|
1118
|
+
Card shown on hover (web) or press (mobile).
|
|
1119
|
+
|
|
1120
|
+
```tsx
|
|
1121
|
+
<HoverCard.Root>
|
|
1122
|
+
<HoverCard.Trigger>
|
|
1123
|
+
<Text>@username</Text>
|
|
1124
|
+
</HoverCard.Trigger>
|
|
1125
|
+
<HoverCard.Content>
|
|
1126
|
+
<View style={{ padding: 16 }}>
|
|
1127
|
+
<Avatar fallback="U" />
|
|
1128
|
+
<Text>User profile info</Text>
|
|
1129
|
+
</View>
|
|
1130
|
+
</HoverCard.Content>
|
|
1131
|
+
</HoverCard.Root>
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
## Quick Reference: Sizes
|
|
1137
|
+
|
|
1138
|
+
| Component | Sizes Available |
|
|
1139
|
+
| ---------------------------- | -------------------------- |
|
|
1140
|
+
| Button, IconButton | `'1'`, `'2'`, `'3'`, `'4'` |
|
|
1141
|
+
| Badge | `'1'`, `'2'` |
|
|
1142
|
+
| Avatar | `'0'` - `'9'` |
|
|
1143
|
+
| Checkbox, Switch, RadioGroup | `'1'`, `'2'`, `'3'` |
|
|
1144
|
+
| TextField, TextArea, Select | `'1'`, `'2'`, `'3'`, `'4'` |
|
|
1145
|
+
| Slider | `'1'`, `'2'`, `'3'` |
|
|
1146
|
+
| Progress, Spinner | `'1'` - `'6'` |
|
|
1147
|
+
| CircularProgress | `'1'` - `'9'` |
|
|
1148
|
+
| Tabs | `'1'`, `'2'` |
|
|
1149
|
+
| Callout | `'1'`, `'2'`, `'3'` |
|
|
1150
|
+
| Dialog | `'1'`, `'2'`, `'3'`, `'4'` |
|
|
1151
|
+
|
|
1152
|
+
---
|
|
1153
|
+
|
|
1154
|
+
## Size Dimensions (pixels)
|
|
1155
|
+
|
|
1156
|
+
Use this table to choose the right size for your layout.
|
|
1157
|
+
|
|
1158
|
+
### Button / IconButton / Select / TextField
|
|
1159
|
+
|
|
1160
|
+
All share the same height scale. IconButton is square (width = height).
|
|
1161
|
+
|
|
1162
|
+
| Size | Height | Use Case |
|
|
1163
|
+
| ----- | ------ | -------------------------------------------------- |
|
|
1164
|
+
| `'1'` | 24px | Compact UI, inline actions, table rows |
|
|
1165
|
+
| `'2'` | 32px | Smaller forms, secondary areas |
|
|
1166
|
+
| `'3'` | 40px | **Default** — mobile-first, touch-friendly |
|
|
1167
|
+
| `'4'` | 48px | Hero CTAs, buy buttons, prominent conversion flows |
|
|
1168
|
+
|
|
1169
|
+
### Badge
|
|
1170
|
+
|
|
1171
|
+
| Size | Height | Use Case |
|
|
1172
|
+
| ----- | ------ | -------------------------------------- |
|
|
1173
|
+
| `'1'` | 20px | **Default** — inline status indicators |
|
|
1174
|
+
| `'2'` | 28px | Emphasized badges, standalone labels |
|
|
1175
|
+
|
|
1176
|
+
### Avatar
|
|
1177
|
+
|
|
1178
|
+
| Size | Dimensions | Use Case |
|
|
1179
|
+
| ----- | ---------- | -------------------------------------- |
|
|
1180
|
+
| `'0'` | 16×16px | Tiny indicators |
|
|
1181
|
+
| `'1'` | 24×24px | Inline mentions, compact lists |
|
|
1182
|
+
| `'2'` | 32×32px | List items, comments |
|
|
1183
|
+
| `'3'` | 40×40px | **Default** — standard profile display |
|
|
1184
|
+
| `'4'` | 48×48px | Card headers, user info |
|
|
1185
|
+
| `'5'` | 64×64px | Profile sections |
|
|
1186
|
+
| `'6'` | 80×80px | Profile pages |
|
|
1187
|
+
| `'7'` | 96×96px | Large profile display |
|
|
1188
|
+
| `'8'` | 128×128px | Hero profile |
|
|
1189
|
+
| `'9'` | 160×160px | Full profile page |
|
|
1190
|
+
|
|
1191
|
+
### Checkbox / RadioGroup
|
|
1192
|
+
|
|
1193
|
+
| Size | Dimensions | Use Case |
|
|
1194
|
+
| ----- | ---------- | ----------------------------- |
|
|
1195
|
+
| `'1'` | 16×16px | Compact forms, dense lists |
|
|
1196
|
+
| `'2'` | 20×20px | **Default** — standard forms |
|
|
1197
|
+
| `'3'` | 24×24px | Touch-friendly, accessibility |
|
|
1198
|
+
|
|
1199
|
+
### Switch
|
|
1200
|
+
|
|
1201
|
+
| Size | Dimensions (W×H) | Use Case |
|
|
1202
|
+
| ----- | ---------------- | --------------------------------- |
|
|
1203
|
+
| `'1'` | 28×16px | Compact settings |
|
|
1204
|
+
| `'2'` | 42×24px | **Default** — standard toggles |
|
|
1205
|
+
| `'3'` | 56×32px | Touch-friendly, prominent toggles |
|
|
1206
|
+
|
|
1207
|
+
### Slider
|
|
1208
|
+
|
|
1209
|
+
| Size | Track Height | Thumb Size | Use Case |
|
|
1210
|
+
| ----- | ------------ | ---------- | --------------------------------- |
|
|
1211
|
+
| `'1'` | 6px | ~14px | Compact controls, dense UI |
|
|
1212
|
+
| `'2'` | 8px | ~16px | **Default** — standard sliders |
|
|
1213
|
+
| `'3'` | 10px | ~18px | Touch-friendly, prominent sliders |
|
|
1214
|
+
|
|
1215
|
+
### Spinner
|
|
1216
|
+
|
|
1217
|
+
| Size | Dimensions | Use Case |
|
|
1218
|
+
| ----- | ---------- | ----------------------------- |
|
|
1219
|
+
| `'1'` | 12×12px | Inline loading indicators |
|
|
1220
|
+
| `'2'` | 16×16px | **Default** — button spinners |
|
|
1221
|
+
| `'3'` | 20×20px | Small loading states |
|
|
1222
|
+
| `'4'` | 24×24px | Card loading |
|
|
1223
|
+
| `'5'` | 32×32px | Section loading |
|
|
1224
|
+
| `'6'` | 40×40px | Page loading |
|
|
1225
|
+
|
|
1226
|
+
### CircularProgress
|
|
1227
|
+
|
|
1228
|
+
| Size | Diameter | Stroke | Use Case |
|
|
1229
|
+
| ----- | -------- | ------ | ------------------------------ |
|
|
1230
|
+
| `'1'` | 16px | 3px | Inline indicators |
|
|
1231
|
+
| `'2'` | 20px | 4px | Compact UI |
|
|
1232
|
+
| `'3'` | 24px | 5px | **Default** — small indicators |
|
|
1233
|
+
| `'4'` | 32px | 5px | List items, stats |
|
|
1234
|
+
| `'5'` | 40px | 6px | Card displays |
|
|
1235
|
+
| `'6'` | 48px | 7px | Prominent indicators |
|
|
1236
|
+
| `'7'` | 56px | 8px | Dashboard widgets |
|
|
1237
|
+
| `'8'` | 64px | 9px | Large displays |
|
|
1238
|
+
| `'9'` | 72px | 10px | Hero/featured metrics |
|
|
1239
|
+
|
|
1240
|
+
---
|
|
1241
|
+
|
|
1242
|
+
## Common Patterns
|
|
1243
|
+
|
|
1244
|
+
### Form with Label
|
|
1245
|
+
|
|
1246
|
+
```tsx
|
|
1247
|
+
<View style={{ gap: 8 }}>
|
|
1248
|
+
<Label nativeID="email">Email</Label>
|
|
1249
|
+
<TextField.Input
|
|
1250
|
+
placeholder="you@example.com"
|
|
1251
|
+
aria-labelledby="email"
|
|
1252
|
+
keyboardType="email-address"
|
|
1253
|
+
/>
|
|
1254
|
+
</View>
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
### Button with Icon
|
|
1258
|
+
|
|
1259
|
+
```tsx
|
|
1260
|
+
<Button>
|
|
1261
|
+
<Icon as={Plus} size={16} />
|
|
1262
|
+
<Text>Add Item</Text>
|
|
1263
|
+
</Button>
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
### Loading State
|
|
1267
|
+
|
|
1268
|
+
```tsx
|
|
1269
|
+
<Button disabled={isLoading}>
|
|
1270
|
+
<Spinner loading={isLoading} size="1">
|
|
1271
|
+
<Text>Submit</Text>
|
|
1272
|
+
</Spinner>
|
|
1273
|
+
</Button>
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
### List Item with Avatar
|
|
1277
|
+
|
|
1278
|
+
```tsx
|
|
1279
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
|
|
1280
|
+
<Avatar fallback="JD" size="2" />
|
|
1281
|
+
<View style={{ flex: 1 }}>
|
|
1282
|
+
<Text weight="medium">John Doe</Text>
|
|
1283
|
+
<Text size="1" color="gray">
|
|
1284
|
+
john@example.com
|
|
1285
|
+
</Text>
|
|
1286
|
+
</View>
|
|
1287
|
+
<Badge color="success">
|
|
1288
|
+
<Text>Active</Text>
|
|
1289
|
+
</Badge>
|
|
1290
|
+
</View>
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
---
|
|
1294
|
+
|
|
1295
|
+
## Do's and Don'ts
|
|
1296
|
+
|
|
1297
|
+
### ✅ Do
|
|
1298
|
+
|
|
1299
|
+
```tsx
|
|
1300
|
+
// Use Text inside Button (auto-styled)
|
|
1301
|
+
<Button>
|
|
1302
|
+
<Text>Click me</Text>
|
|
1303
|
+
</Button>
|
|
1304
|
+
|
|
1305
|
+
// Use compound component pattern correctly
|
|
1306
|
+
<TextField.Root>
|
|
1307
|
+
<TextField.Input placeholder="..." />
|
|
1308
|
+
</TextField.Root>
|
|
1309
|
+
|
|
1310
|
+
// Use semantic colors
|
|
1311
|
+
<Button color="danger">
|
|
1312
|
+
<Text>Delete</Text>
|
|
1313
|
+
</Button>
|
|
1314
|
+
```
|
|
1315
|
+
|
|
1316
|
+
### ❌ Don't
|
|
1317
|
+
|
|
1318
|
+
```tsx
|
|
1319
|
+
// Don't use raw strings in Button
|
|
1320
|
+
<Button>Click me</Button>;
|
|
1321
|
+
|
|
1322
|
+
// Don't import TextInput from react-native
|
|
1323
|
+
import { TextInput } from 'react-native';
|
|
1324
|
+
|
|
1325
|
+
// Don't manually style Text inside components
|
|
1326
|
+
<Button>
|
|
1327
|
+
<Text style={{ color: 'white' }}>Click</Text>
|
|
1328
|
+
</Button>;
|
|
1329
|
+
```
|