@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,799 @@
|
|
|
1
|
+
# Frosted UI Color System
|
|
2
|
+
|
|
3
|
+
> **For AI/LLM Code Generation**: This document explains the Frosted UI color system for React Native. Follow these guidelines exactly to produce consistent, accessible, and beautiful UIs.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Frosted UI uses a **semantic color system** built on 12-step color palettes based on [Radix Colors](https://www.radix-ui.com/colors/docs/palette-composition/understanding-the-scale). Each color has solid shades (1-12) and alpha/transparent shades (a1-a12). Colors are theme-aware and automatically adapt to light and dark modes.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Color Types
|
|
12
|
+
|
|
13
|
+
### AccentColor (27 Named Colors)
|
|
14
|
+
|
|
15
|
+
These are the core palette colors available in the design system:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
type AccentColor =
|
|
19
|
+
| 'tomato'
|
|
20
|
+
| 'red'
|
|
21
|
+
| 'ruby'
|
|
22
|
+
| 'crimson' // Reds
|
|
23
|
+
| 'pink'
|
|
24
|
+
| 'plum'
|
|
25
|
+
| 'purple'
|
|
26
|
+
| 'violet' // Purples/Pinks
|
|
27
|
+
| 'iris'
|
|
28
|
+
| 'indigo' // Indigos
|
|
29
|
+
| 'blue'
|
|
30
|
+
| 'cyan'
|
|
31
|
+
| 'sky' // Blues
|
|
32
|
+
| 'teal'
|
|
33
|
+
| 'jade'
|
|
34
|
+
| 'green'
|
|
35
|
+
| 'grass'
|
|
36
|
+
| 'mint' // Greens
|
|
37
|
+
| 'lime'
|
|
38
|
+
| 'lemon'
|
|
39
|
+
| 'yellow'
|
|
40
|
+
| 'amber' // Yellows
|
|
41
|
+
| 'orange' // Orange
|
|
42
|
+
| 'brown'
|
|
43
|
+
| 'gold'
|
|
44
|
+
| 'bronze' // Browns
|
|
45
|
+
| 'magenta' // Magenta
|
|
46
|
+
| 'gray'; // Neutral
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### SemanticColor (Contextual Meaning)
|
|
50
|
+
|
|
51
|
+
Semantic colors map to accent colors based on app configuration:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
type SemanticColor = 'danger' | 'warning' | 'success' | 'info';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Default mappings:**
|
|
58
|
+
|
|
59
|
+
- `danger` → `red` (alternatives: `tomato`, `ruby`)
|
|
60
|
+
- `warning` → `amber` (alternative: `yellow`)
|
|
61
|
+
- `success` → `green` (alternatives: `teal`, `jade`, `grass`)
|
|
62
|
+
- `info` → `sky` (alternative: `blue`)
|
|
63
|
+
|
|
64
|
+
### DynamicAccentColor
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
type DynamicAccentColor = 'accent';
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The special `'accent'` color uses the app's configured accent color from `ThemeProvider`. **This is the default for most components.**
|
|
71
|
+
|
|
72
|
+
### Color (Union Type)
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
type Color = AccentColor | SemanticColor | DynamicAccentColor;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This is what component `color` props accept.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Color Palette Structure
|
|
83
|
+
|
|
84
|
+
Frosted UI's color system is based on [Radix Colors](https://www.radix-ui.com/colors/docs/palette-composition/understanding-the-scale). Each palette has 12 steps, where each step was designed for specific use cases.
|
|
85
|
+
|
|
86
|
+
### Quick Reference Table
|
|
87
|
+
|
|
88
|
+
| Step | Primary Use Case |
|
|
89
|
+
| ------------ | --------------------------------------- |
|
|
90
|
+
| `1` | Very subtle background |
|
|
91
|
+
| `2` | Subtle background |
|
|
92
|
+
| `3` | UI element background |
|
|
93
|
+
| `4` | Hovered UI element background |
|
|
94
|
+
| `5` | Active / Selected UI element background |
|
|
95
|
+
| `6` | Subtle borders and separators |
|
|
96
|
+
| `7` | UI element border and focus rings |
|
|
97
|
+
| `8` | Hovered UI element border |
|
|
98
|
+
| `9` | Solid backgrounds |
|
|
99
|
+
| `10` | Hovered solid backgrounds |
|
|
100
|
+
| `11` | Low-contrast text |
|
|
101
|
+
| `12` | High-contrast text |
|
|
102
|
+
| `9-contrast` | Text color designed for use ON shade 9 |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### Steps 1–2: Backgrounds
|
|
107
|
+
|
|
108
|
+
Step `2` is designed for app backgrounds and subtle component backgrounds.
|
|
109
|
+
|
|
110
|
+
**Appropriate use cases:**
|
|
111
|
+
|
|
112
|
+
- Striped table background (alternating rows)
|
|
113
|
+
- Code block background
|
|
114
|
+
- Card background
|
|
115
|
+
- Sidebar background
|
|
116
|
+
- Canvas area background
|
|
117
|
+
- Section backgrounds
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Main app background
|
|
121
|
+
backgroundColor: colors.background; // Uses white in light mode and gray['1'] in dark mode
|
|
122
|
+
|
|
123
|
+
// Subtle colored background for a section
|
|
124
|
+
backgroundColor: gray['2']; // or palette['2']
|
|
125
|
+
|
|
126
|
+
// Card with subtle tint
|
|
127
|
+
backgroundColor: palette.a2;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### Steps 3–5: Component Backgrounds
|
|
133
|
+
|
|
134
|
+
Steps `3`, `4`, and `5` are designed for interactive UI component backgrounds.
|
|
135
|
+
|
|
136
|
+
| Step | State |
|
|
137
|
+
| ---- | --------------------------------- |
|
|
138
|
+
| `3` | **Default** state |
|
|
139
|
+
| `4` | **Hover** state |
|
|
140
|
+
| `5` | **Pressed** or **Selected** state |
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// Interactive list item
|
|
144
|
+
const listItemStyle = {
|
|
145
|
+
backgroundColor: isSelected
|
|
146
|
+
? palette.a5 // Selected
|
|
147
|
+
: isHovered
|
|
148
|
+
? palette.a4 // Hover
|
|
149
|
+
: palette.a3, // Default
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// If component has transparent default state, use 3 for hover
|
|
153
|
+
const ghostButtonHover = {
|
|
154
|
+
backgroundColor: isHovered ? palette.a3 : 'transparent',
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Important:** Steps `11` and `12` (text colors) are guaranteed to have sufficient contrast when used on step `2`, `3`, `4` and `5` backgrounds from the same scale.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Steps 6–8: Borders
|
|
163
|
+
|
|
164
|
+
Steps `6`, `7`, and `8` are designed for borders and separators.
|
|
165
|
+
|
|
166
|
+
| Step | Use Case |
|
|
167
|
+
| ---- | --------------------------------------------------------------------------------------------- |
|
|
168
|
+
| `6` | Subtle borders on **non-interactive** elements (cards, alerts, separators, sidebars, headers) |
|
|
169
|
+
| `7` | Subtle borders on **interactive** elements (buttons, inputs) |
|
|
170
|
+
| `8` | **Stronger** borders on interactive elements, **focus rings** |
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Non-interactive card border - use the stroke token
|
|
174
|
+
borderColor: colors.stroke;
|
|
175
|
+
|
|
176
|
+
// Interactive input border
|
|
177
|
+
borderColor: isFocused ? palette.a8 : isHovered ? gray.a7 : colors.stroke;
|
|
178
|
+
|
|
179
|
+
// Separator/divider - use the stroke token
|
|
180
|
+
backgroundColor: colors.stroke;
|
|
181
|
+
|
|
182
|
+
// Focus ring (accessibility critical!)
|
|
183
|
+
outlineColor: palette.a8;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### Steps 9–10: Solid Backgrounds
|
|
189
|
+
|
|
190
|
+
Steps `9` and `10` are designed for solid, high-chroma backgrounds.
|
|
191
|
+
|
|
192
|
+
**Step `9` is the purest step**—it has the highest chroma (color saturation) with the least amount of white or black mixed in. This makes it ideal for:
|
|
193
|
+
|
|
194
|
+
- Solid button backgrounds
|
|
195
|
+
- Website/App section backgrounds
|
|
196
|
+
- Header backgrounds
|
|
197
|
+
- Badge backgrounds
|
|
198
|
+
- Progress bar fills
|
|
199
|
+
- Graphics and logos
|
|
200
|
+
- Accent borders
|
|
201
|
+
- Colored shadows
|
|
202
|
+
|
|
203
|
+
**Step `10`** is designed for hover states where step `9` is the default.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// Solid button
|
|
207
|
+
const solidButtonStyle = {
|
|
208
|
+
backgroundColor: isPressed
|
|
209
|
+
? palette['10'] // with brightness filter
|
|
210
|
+
: isHovered
|
|
211
|
+
? palette['10']
|
|
212
|
+
: palette['9'],
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// Progress bar indicator
|
|
216
|
+
backgroundColor: palette['9'];
|
|
217
|
+
|
|
218
|
+
// Checkbox when checked
|
|
219
|
+
backgroundColor: palette['9'];
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Contrast Text on Step 9
|
|
223
|
+
|
|
224
|
+
Most colors use **white** text on step 9. However, these lighter colors require **dark** text:
|
|
225
|
+
|
|
226
|
+
| Color | `9-contrast` value |
|
|
227
|
+
| --------- | ------------------ |
|
|
228
|
+
| `sky` | Dark (`#1C2024`) |
|
|
229
|
+
| `mint` | Dark (`#1A211E`) |
|
|
230
|
+
| `lime` | Dark (`#162715`) |
|
|
231
|
+
| `yellow` | Dark (`#21201C`) |
|
|
232
|
+
| `amber` | Dark (`#21201C`) |
|
|
233
|
+
| `lemon` | Dark (`#20240D`) |
|
|
234
|
+
| `magenta` | Dark (`#141212`) |
|
|
235
|
+
|
|
236
|
+
**Always use `palette['9-contrast']`** for text on solid backgrounds—never assume white will work.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// ✅ Correct: Use 9-contrast
|
|
240
|
+
<View style={{ backgroundColor: palette['9'] }}>
|
|
241
|
+
<Text style={{ color: palette['9-contrast'] }}>Always readable</Text>
|
|
242
|
+
</View>
|
|
243
|
+
|
|
244
|
+
// ❌ Wrong: Hardcoded white fails on yellow, amber, sky, etc.
|
|
245
|
+
<View style={{ backgroundColor: palette['9'] }}>
|
|
246
|
+
<Text style={{ color: 'white' }}>May be unreadable!</Text>
|
|
247
|
+
</View>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Steps 11–12: Text
|
|
253
|
+
|
|
254
|
+
Steps `11` and `12` are designed for text.
|
|
255
|
+
|
|
256
|
+
| Step | Use Case | Contrast Level |
|
|
257
|
+
| ---- | ------------------------------------------ | -------------------- |
|
|
258
|
+
| `11` | Low-contrast text, secondary text, icons | APCA Lc 60 on step 2 |
|
|
259
|
+
| `12` | High-contrast text, primary text, headings | APCA Lc 90 on step 2 |
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// Primary text (high contrast)
|
|
263
|
+
color: gray['12'];
|
|
264
|
+
|
|
265
|
+
// Secondary text (lower contrast but still accessible)
|
|
266
|
+
color: gray['11']; // or gray.a11
|
|
267
|
+
|
|
268
|
+
// Tertiary text
|
|
269
|
+
color: gray['10']; // or gray.a10
|
|
270
|
+
|
|
271
|
+
// Colored text that's accessible
|
|
272
|
+
color: palette['11']; // or palette.a11
|
|
273
|
+
|
|
274
|
+
// Icon color (matches low-contrast text)
|
|
275
|
+
color: palette.a11;
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### Alpha Shades (Transparent Variants)
|
|
281
|
+
|
|
282
|
+
Every solid shade has a corresponding alpha (transparent) shade: `a1`, `a2`, `a3`... `a12`.
|
|
283
|
+
|
|
284
|
+
**When to use alpha shades:**
|
|
285
|
+
|
|
286
|
+
| Prefer Alpha (`aX`) | Prefer Solid (`X`) |
|
|
287
|
+
| -------------------------------- | -------------------------------- |
|
|
288
|
+
| Overlays on images/gradients | Standalone solid surfaces |
|
|
289
|
+
| Soft/ghost component backgrounds | Solid buttons |
|
|
290
|
+
| Borders (blend better) | When exact color matching needed |
|
|
291
|
+
| Layered UI elements | |
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// ✅ Alpha shades blend naturally over any background
|
|
295
|
+
backgroundColor: palette.a3; // Soft button bg
|
|
296
|
+
borderColor: palette.a6; // Border
|
|
297
|
+
|
|
298
|
+
// ✅ Solid shades for pure solid fills
|
|
299
|
+
backgroundColor: palette['9']; // Solid button
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Key insight:** Alpha shades produce more natural, less jarring results when layered over varied backgrounds (images, gradients, other colors).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### Black & White Alpha Palettes
|
|
307
|
+
|
|
308
|
+
In addition to colored palettes, Frosted UI provides `black` and `white` alpha-only palettes for overlays and universal transparency effects:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
colors.palettes.black.a1; // through a12 - black with increasing opacity
|
|
312
|
+
colors.palettes.white.a1; // through a12 - white with increasing opacity
|
|
313
|
+
|
|
314
|
+
// Example: Overlay for modal backdrop
|
|
315
|
+
backgroundColor: colors.palettes.black.a6; // Semi-transparent black overlay
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Component Variants & Color Usage
|
|
321
|
+
|
|
322
|
+
### Automatic Text Colors
|
|
323
|
+
|
|
324
|
+
**Components automatically style their child `<Text>` elements.** When you pass `<Text>` as a child to components like `Button`, `Badge`, `Callout`, etc., the text color is automatically set based on the component's `color` and `variant` props.
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
// ✅ Text automatically gets the correct color - no manual styling needed
|
|
328
|
+
<Button color="danger" variant="solid">
|
|
329
|
+
<Text>Delete Account</Text>
|
|
330
|
+
</Button>
|
|
331
|
+
|
|
332
|
+
<Badge color="success" variant="soft">
|
|
333
|
+
<Text>Completed</Text>
|
|
334
|
+
</Badge>
|
|
335
|
+
|
|
336
|
+
<Callout.Root color="warning">
|
|
337
|
+
<Callout.Text>
|
|
338
|
+
<Text>Please review before proceeding</Text>
|
|
339
|
+
</Callout.Text>
|
|
340
|
+
</Callout.Root>
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Do NOT manually override text colors inside components** unless you have a specific design requirement. The component handles contrast and accessibility automatically.
|
|
344
|
+
|
|
345
|
+
```tsx
|
|
346
|
+
// ❌ Bad: Unnecessary manual color override
|
|
347
|
+
<Button color="accent" variant="solid">
|
|
348
|
+
<Text style={{ color: 'white' }}>Submit</Text>
|
|
349
|
+
</Button>
|
|
350
|
+
|
|
351
|
+
// ✅ Good: Let Button handle text color automatically
|
|
352
|
+
<Button color="accent" variant="solid">
|
|
353
|
+
<Text>Submit</Text>
|
|
354
|
+
</Button>
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### The Standard Variants
|
|
360
|
+
|
|
361
|
+
Many components support these variants. Here's how they use color:
|
|
362
|
+
|
|
363
|
+
#### 1. `solid` — High-emphasis, primary actions
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
{
|
|
367
|
+
backgroundColor: palette['9'], // Primary color
|
|
368
|
+
color: palette['9-contrast'], // Contrast text (white or dark)
|
|
369
|
+
}
|
|
370
|
+
// Hover: palette['10']
|
|
371
|
+
// Pressed: palette['10'] with brightness(0.92) filter
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### 2. `soft` — Medium-emphasis, secondary actions
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
{
|
|
378
|
+
backgroundColor: palette.a3, // Subtle transparent background
|
|
379
|
+
color: palette.a11 || palette['11'], // Readable text
|
|
380
|
+
}
|
|
381
|
+
// Hover: palette.a4
|
|
382
|
+
// Pressed: palette.a5
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### 3. `surface` — Low-emphasis, neutral containers
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
{
|
|
389
|
+
backgroundColor: palette.a2, // Very subtle background
|
|
390
|
+
borderColor: palette.a6 || palette.a7, // Visible border
|
|
391
|
+
borderWidth: 1,
|
|
392
|
+
color: palette.a11, // Text
|
|
393
|
+
}
|
|
394
|
+
// Often used with panelSolid background and gray borders
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### 4. `outline` — Minimal, text-only with border
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
{
|
|
401
|
+
backgroundColor: 'transparent',
|
|
402
|
+
borderColor: palette.a7 || palette.a8,
|
|
403
|
+
borderWidth: 1,
|
|
404
|
+
color: palette.a11,
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
#### 5. `ghost` — No background, just text
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
{
|
|
412
|
+
backgroundColor: 'transparent', // Or palette.a3 on hover
|
|
413
|
+
color: palette.a11,
|
|
414
|
+
}
|
|
415
|
+
// Hover: palette.a3
|
|
416
|
+
// Pressed: palette.a4
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Common Patterns
|
|
422
|
+
|
|
423
|
+
### Focus Rings
|
|
424
|
+
|
|
425
|
+
Always use `a8` for focus outlines:
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
const focusStyle = focused
|
|
429
|
+
? {
|
|
430
|
+
outlineWidth: 2,
|
|
431
|
+
outlineStyle: 'solid',
|
|
432
|
+
outlineColor: palette.a8,
|
|
433
|
+
outlineOffset: 2,
|
|
434
|
+
}
|
|
435
|
+
: undefined;
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Disabled States
|
|
439
|
+
|
|
440
|
+
Use gray palette with alpha shades:
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
const disabledStyle = {
|
|
444
|
+
backgroundColor: gray.a3,
|
|
445
|
+
color: gray.a8, // Dimmed text
|
|
446
|
+
};
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Text Colors
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
// Default text (no color specified)
|
|
453
|
+
color: gray['12']; // High contrast foreground
|
|
454
|
+
|
|
455
|
+
// Secondary text
|
|
456
|
+
color: gray.a11;
|
|
457
|
+
|
|
458
|
+
// Tertiary text (placeholders, descriptions)
|
|
459
|
+
color: gray.a10;
|
|
460
|
+
|
|
461
|
+
// Colored, accessible text
|
|
462
|
+
color: palette.a11; // Or palette['11']
|
|
463
|
+
|
|
464
|
+
// Text on solid backgrounds
|
|
465
|
+
color: palette['9-contrast']; // White or dark based on palette, designed to be readable on palette['9'] shade.
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Borders & Separators
|
|
469
|
+
|
|
470
|
+
**Use `colors.stroke` for default gray borders and separators.** This is a pre-defined semantic token that provides the correct gray border color for the current theme.
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// Default border/separator - USE THIS for gray borders
|
|
474
|
+
borderColor: colors.stroke; // Pre-defined semantic token (gray.a5 in light, gray.a4 in dark)
|
|
475
|
+
|
|
476
|
+
// Separator component
|
|
477
|
+
backgroundColor: colors.stroke;
|
|
478
|
+
|
|
479
|
+
// Colored separator (when you need a tinted separator)
|
|
480
|
+
backgroundColor: palette.a6;
|
|
481
|
+
|
|
482
|
+
// Input border states
|
|
483
|
+
borderColor: colors.stroke; // Default - use the stroke token
|
|
484
|
+
borderColor: gray.a7; // Hover
|
|
485
|
+
borderColor: palette.a8; // Focus
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Important:** Prefer `colors.stroke` over manually using `gray.a5` or `gray.a6` for default borders. The stroke token ensures consistency across the design system.
|
|
489
|
+
|
|
490
|
+
### Theme Surface & Stroke Tokens
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
// Screen background (the default app background color)
|
|
494
|
+
colors.background; // 'white' in light, gray['1'] in dark
|
|
495
|
+
|
|
496
|
+
// Panel/Card solid
|
|
497
|
+
colors.panelSolid; // Elevated surface, used for bottom sheets, side drawers, dialogs, popovers, dropdowns.
|
|
498
|
+
|
|
499
|
+
// Panel translucent (with backdrop blur)
|
|
500
|
+
colors.panelTranslucent; // Semi-transparent. Used for bottom sheets, side drawers, dialogs, popovers, dropdowns, but needs to be combined with backdrop blur
|
|
501
|
+
|
|
502
|
+
// Surface (subtle overlay)
|
|
503
|
+
colors.surface; // Used in text field, text area background color in a 'surface' variant
|
|
504
|
+
|
|
505
|
+
// Default border/separator color (IMPORTANT - use this for gray borders!)
|
|
506
|
+
colors.stroke; // gray.a5 in light, gray.a4 in dark - use for separators, card borders, input borders
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Accessing Colors in Components
|
|
512
|
+
|
|
513
|
+
### Using `useThemeTokens`
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
import { useThemeTokens } from '@frosted-ui/react-native';
|
|
517
|
+
|
|
518
|
+
function MyComponent({ color }: { color?: Color }) {
|
|
519
|
+
const { colors, isDark } = useThemeTokens();
|
|
520
|
+
|
|
521
|
+
// Get the palette for the specified color (defaults to 'accent')
|
|
522
|
+
const palette = colors.palettes[color ?? 'accent'];
|
|
523
|
+
|
|
524
|
+
// Gray is always available for neutral/disabled states
|
|
525
|
+
const gray = colors.palettes.gray;
|
|
526
|
+
|
|
527
|
+
// Theme surfaces and stroke
|
|
528
|
+
const background = colors.background;
|
|
529
|
+
const panelBg = colors.panelSolid;
|
|
530
|
+
const borderColor = colors.stroke; // Use for default gray borders
|
|
531
|
+
|
|
532
|
+
return (
|
|
533
|
+
<View
|
|
534
|
+
style={{
|
|
535
|
+
backgroundColor: palette.a3,
|
|
536
|
+
borderColor: colors.stroke, // Use stroke token for gray borders
|
|
537
|
+
borderWidth: 1,
|
|
538
|
+
}}>
|
|
539
|
+
<Text style={{ color: palette['11'] }}>Hello</Text>
|
|
540
|
+
</View>
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### Semantic Colors Are Pre-resolved
|
|
546
|
+
|
|
547
|
+
`useThemeTokens` automatically adds semantic palettes:
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
const { colors } = useThemeTokens();
|
|
551
|
+
|
|
552
|
+
// These work automatically:
|
|
553
|
+
colors.palettes.accent; // → The app's accent color palette
|
|
554
|
+
colors.palettes.danger; // → The app's danger color palette
|
|
555
|
+
colors.palettes.warning; // → The app's warning color palette
|
|
556
|
+
colors.palettes.success; // → The app's success color palette
|
|
557
|
+
colors.palettes.info; // → The app's info color palette
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## ThemeProvider Configuration
|
|
563
|
+
|
|
564
|
+
Apps wrap their root in `ThemeProvider` to set colors:
|
|
565
|
+
|
|
566
|
+
```tsx
|
|
567
|
+
<ThemeProvider
|
|
568
|
+
accentColor="purple" // Default: 'blue'
|
|
569
|
+
dangerColor="tomato" // Default: 'red' (must be: tomato | red | ruby)
|
|
570
|
+
warningColor="yellow" // Default: 'amber' (must be: yellow | amber)
|
|
571
|
+
successColor="teal" // Default: 'green' (must be: teal | jade | green | grass)
|
|
572
|
+
infoColor="blue" // Default: 'sky' (must be: blue | sky)
|
|
573
|
+
>
|
|
574
|
+
<App />
|
|
575
|
+
</ThemeProvider>
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## ✅ DO's
|
|
581
|
+
|
|
582
|
+
### Use semantic colors for status/feedback
|
|
583
|
+
|
|
584
|
+
```tsx
|
|
585
|
+
// ✅ Good: Uses semantic 'danger' - adapts to app config
|
|
586
|
+
<Button color="danger">Delete</Button>
|
|
587
|
+
<Badge color="success">Completed</Badge>
|
|
588
|
+
<Callout color="warning">
|
|
589
|
+
<Text>Please review before proceeding</Text>
|
|
590
|
+
</Callout>
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Default to 'accent' (or omit color prop)
|
|
594
|
+
|
|
595
|
+
```tsx
|
|
596
|
+
// ✅ Good: Uses app's accent color
|
|
597
|
+
<Button>Submit</Button>
|
|
598
|
+
<Button color="accent">Submit</Button> // Explicit but same result
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Use alpha shades for overlays and soft backgrounds
|
|
602
|
+
|
|
603
|
+
```tsx
|
|
604
|
+
// ✅ Good: Transparent shades blend naturally
|
|
605
|
+
backgroundColor: palette.a3;
|
|
606
|
+
borderColor: palette.a6;
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Use gray for neutral/disabled states
|
|
610
|
+
|
|
611
|
+
```tsx
|
|
612
|
+
// ✅ Good: Consistent disabled appearance
|
|
613
|
+
const disabledTextColor = gray.a8;
|
|
614
|
+
const disabledBackground = gray.a3;
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Use '9-contrast' for text on solid backgrounds
|
|
618
|
+
|
|
619
|
+
```tsx
|
|
620
|
+
// ✅ Good: Ensures readable text on any solid color
|
|
621
|
+
<View style={{ backgroundColor: palette['9'] }}>
|
|
622
|
+
<Text style={{ color: palette['9-contrast'] }}>Visible</Text>
|
|
623
|
+
</View>
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### Respect variant conventions
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
// ✅ Good: Each variant has a specific visual weight
|
|
630
|
+
<Button variant="solid">Primary Action</Button> // High emphasis
|
|
631
|
+
<Button variant="soft">Secondary</Button> // Medium emphasis
|
|
632
|
+
<Button variant="ghost">Tertiary</Button> // Low emphasis
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### Use the correct shade for each interaction state
|
|
636
|
+
|
|
637
|
+
```tsx
|
|
638
|
+
// ✅ Good: Follows the 3-4-5 pattern for component states
|
|
639
|
+
const bgColor = isSelected
|
|
640
|
+
? palette.a5 // Selected/Active
|
|
641
|
+
: isHovered
|
|
642
|
+
? palette.a4 // Hover
|
|
643
|
+
: palette.a3; // Default
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## ❌ DON'Ts
|
|
649
|
+
|
|
650
|
+
### Don't hardcode color values
|
|
651
|
+
|
|
652
|
+
```tsx
|
|
653
|
+
// ❌ Bad: Hardcoded colors break theming
|
|
654
|
+
<View style={{ backgroundColor: '#3B82F6' }}>
|
|
655
|
+
|
|
656
|
+
// ✅ Good: Use palette shades
|
|
657
|
+
<View style={{ backgroundColor: palette['9'] }}>
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### Don't mix shade numbers arbitrarily
|
|
661
|
+
|
|
662
|
+
```tsx
|
|
663
|
+
// ❌ Bad: Random shade numbers create visual inconsistency
|
|
664
|
+
backgroundColor: palette['4']; // Why 4? Use established patterns
|
|
665
|
+
|
|
666
|
+
// ✅ Good: Follow the variant patterns
|
|
667
|
+
backgroundColor: palette.a3; // Soft background (established pattern)
|
|
668
|
+
backgroundColor: palette['9']; // Solid background (established pattern)
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
### Don't use solid shades where alpha shades work better
|
|
672
|
+
|
|
673
|
+
```tsx
|
|
674
|
+
// ❌ Bad: Solid shade may look harsh over images/gradients
|
|
675
|
+
backgroundColor: palette['3'];
|
|
676
|
+
|
|
677
|
+
// ✅ Good: Alpha shade blends naturally
|
|
678
|
+
backgroundColor: palette.a3;
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Don't use incorrect contrast combinations
|
|
682
|
+
|
|
683
|
+
```tsx
|
|
684
|
+
// ❌ Bad: Low contrast, hard to read
|
|
685
|
+
<View style={{ backgroundColor: palette['9'] }}>
|
|
686
|
+
<Text style={{ color: palette['11'] }}>Hard to read</Text>
|
|
687
|
+
</View>
|
|
688
|
+
|
|
689
|
+
// ✅ Good: Use the contrast color for shade 9
|
|
690
|
+
<View style={{ backgroundColor: palette['9'] }}>
|
|
691
|
+
<Text style={{ color: palette['9-contrast'] }}>Easy to read</Text>
|
|
692
|
+
</View>
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Don't ignore the gray palette for neutral states
|
|
696
|
+
|
|
697
|
+
```tsx
|
|
698
|
+
// ❌ Bad: Using accent color for disabled state
|
|
699
|
+
const disabledColor = palette.a5;
|
|
700
|
+
|
|
701
|
+
// ✅ Good: Disabled states use gray
|
|
702
|
+
const disabledColor = gray.a8;
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### Don't create custom status colors
|
|
706
|
+
|
|
707
|
+
```tsx
|
|
708
|
+
// ❌ Bad: Custom colors for statuses
|
|
709
|
+
<Badge color="tomato">Error</Badge> // Should use semantic color
|
|
710
|
+
|
|
711
|
+
// ✅ Good: Use semantic colors for status
|
|
712
|
+
<Badge color="danger">Error</Badge>
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
### Don't skip focus states
|
|
716
|
+
|
|
717
|
+
```tsx
|
|
718
|
+
// ❌ Bad: No focus indication
|
|
719
|
+
<Pressable style={{ ... }}>
|
|
720
|
+
|
|
721
|
+
// ✅ Good: Include focus ring using a8
|
|
722
|
+
<Pressable
|
|
723
|
+
style={({ focused }) => ({
|
|
724
|
+
...(focused && {
|
|
725
|
+
outlineWidth: 2,
|
|
726
|
+
outlineColor: palette.a8,
|
|
727
|
+
})
|
|
728
|
+
})}
|
|
729
|
+
>
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### Don't override component colors unnecessarily
|
|
733
|
+
|
|
734
|
+
```tsx
|
|
735
|
+
// ❌ Bad: Overriding Button's built-in text color
|
|
736
|
+
<Button color="danger">
|
|
737
|
+
<Text style={{ color: 'red' }}>Delete</Text>
|
|
738
|
+
</Button>
|
|
739
|
+
|
|
740
|
+
// ✅ Good: Let components handle their own colors
|
|
741
|
+
<Button color="danger">
|
|
742
|
+
<Text>Delete</Text>
|
|
743
|
+
</Button>
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
## Quick Reference: Shade Cheatsheet
|
|
749
|
+
|
|
750
|
+
> **Variable definitions:**
|
|
751
|
+
>
|
|
752
|
+
> - `colors` = the return value of `useThemeTokens()` → `const { colors } = useThemeTokens();`
|
|
753
|
+
> - `palette` = `colors.palettes[color]` where `color` is the component's color prop (e.g., `'accent'`, `'danger'`, `'blue'`)
|
|
754
|
+
> - `gray` = `colors.palettes.gray` — the base neutral palette, used for text, borders, disabled states, and neutral UI elements
|
|
755
|
+
|
|
756
|
+
### Semantic Tokens (use these first)
|
|
757
|
+
|
|
758
|
+
| Use Case | Token |
|
|
759
|
+
| -------------------------- | ------------------- |
|
|
760
|
+
| App background | `colors.background` |
|
|
761
|
+
| Panel / card background | `colors.panelSolid` |
|
|
762
|
+
| Default border / separator | `colors.stroke` |
|
|
763
|
+
|
|
764
|
+
### Colored Elements (using `palette` from component's color)
|
|
765
|
+
|
|
766
|
+
| Use Case | Shade |
|
|
767
|
+
| ------------------------------ | ----------------------- |
|
|
768
|
+
| Subtle tinted background | `palette.a2` |
|
|
769
|
+
| Component background (default) | `palette.a3` |
|
|
770
|
+
| Component background (hover) | `palette.a4` |
|
|
771
|
+
| Component background (active) | `palette.a5` |
|
|
772
|
+
| Colored border | `palette.a6` |
|
|
773
|
+
| Interactive border (hover) | `palette.a7` |
|
|
774
|
+
| Focus ring | `palette.a8` |
|
|
775
|
+
| Solid background | `palette['9']` |
|
|
776
|
+
| Solid background (hover) | `palette['10']` |
|
|
777
|
+
| Colored text / icon | `palette.a11` |
|
|
778
|
+
| Text on solid background | `palette['9-contrast']` |
|
|
779
|
+
|
|
780
|
+
### Neutral / Gray Elements (using `gray` palette)
|
|
781
|
+
|
|
782
|
+
| Use Case | Shade |
|
|
783
|
+
| --------------------------- | ------------ |
|
|
784
|
+
| Default foreground text | `gray['12']` |
|
|
785
|
+
| Secondary text | `gray.a11` |
|
|
786
|
+
| Tertiary / placeholder text | `gray.a10` |
|
|
787
|
+
| Disabled text | `gray.a8` |
|
|
788
|
+
| Disabled background | `gray.a3` |
|
|
789
|
+
| Interactive border (hover) | `gray.a7` |
|
|
790
|
+
|
|
791
|
+
---
|
|
792
|
+
|
|
793
|
+
## Color Accessibility Notes
|
|
794
|
+
|
|
795
|
+
- All shade 9 colors meet WCAG contrast requirements with their `9-contrast` value
|
|
796
|
+
- Steps `11` and `12` are guaranteed APCA Lc 60 and Lc 90 contrast respectively on step `2` backgrounds
|
|
797
|
+
- Some light colors (`sky`, `mint`, `yellow`, `amber`, `lemon`, `lime`, `magenta`) use dark text for `9-contrast` instead of white
|
|
798
|
+
- Always test color combinations in both light and dark modes
|
|
799
|
+
- Use semantic colors (`danger`, `warning`, `success`, `info`) for status indicators to ensure proper contrast is maintained across theme configurations
|