@castui/cast-ui 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -61
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Button/Button.js +2 -4
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Card/Card.d.ts.map +1 -1
- package/dist/components/Card/Card.js +4 -10
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/default.reference.json +125 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/theme/ThemeProvider.d.ts +6 -4
- package/dist/theme/ThemeProvider.d.ts.map +1 -1
- package/dist/theme/ThemeProvider.js +8 -6
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/createTheme.d.ts +49 -0
- package/dist/theme/createTheme.d.ts.map +1 -0
- package/dist/theme/createTheme.js +85 -0
- package/dist/theme/createTheme.js.map +1 -0
- package/dist/theme/fonts.d.ts +75 -17
- package/dist/theme/fonts.d.ts.map +1 -1
- package/dist/theme/fonts.js +120 -22
- package/dist/theme/fonts.js.map +1 -1
- package/dist/theme/index.d.ts +3 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +2 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/types.d.ts +4 -3
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js +3 -2
- package/dist/theme/types.js.map +1 -1
- package/dist/tokens/generated/default.d.ts +3 -0
- package/dist/tokens/generated/default.d.ts.map +1 -0
- package/dist/tokens/generated/{white-label.js → default.js} +3 -3
- package/dist/tokens/generated/default.js.map +1 -0
- package/dist/tokens/generated/index.d.ts +1 -4
- package/dist/tokens/generated/index.d.ts.map +1 -1
- package/dist/tokens/generated/index.js +1 -4
- package/dist/tokens/generated/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/tokens/generated/consumer.d.ts +0 -3
- package/dist/tokens/generated/consumer.d.ts.map +0 -1
- package/dist/tokens/generated/consumer.js +0 -126
- package/dist/tokens/generated/consumer.js.map +0 -1
- package/dist/tokens/generated/corporate.d.ts +0 -3
- package/dist/tokens/generated/corporate.d.ts.map +0 -1
- package/dist/tokens/generated/corporate.js +0 -126
- package/dist/tokens/generated/corporate.js.map +0 -1
- package/dist/tokens/generated/luxury.d.ts +0 -3
- package/dist/tokens/generated/luxury.d.ts.map +0 -1
- package/dist/tokens/generated/luxury.js +0 -126
- package/dist/tokens/generated/luxury.js.map +0 -1
- package/dist/tokens/generated/white-label.d.ts +0 -3
- package/dist/tokens/generated/white-label.d.ts.map +0 -1
- package/dist/tokens/generated/white-label.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Cast UI
|
|
2
2
|
|
|
3
|
-
A cross-platform design system for React Native (iOS, Android, Web) with
|
|
3
|
+
A cross-platform design system for React Native (iOS, Android, Web) with custom theme support via `createTheme()`. Components are built with vanilla React Native primitives and themed via design tokens exported from Figma.
|
|
4
|
+
|
|
5
|
+
Ships a **Default base theme** that uses system fonts and neutral styling — ready for you to customise with your brand.
|
|
4
6
|
|
|
5
7
|
## Architecture
|
|
6
8
|
|
|
@@ -33,6 +35,12 @@ Example:
|
|
|
33
35
|
|
|
34
36
|
See [`design-tokens/DESIGN-TOKENS-SUMMARY.md`](design-tokens/DESIGN-TOKENS-SUMMARY.md) for the full token reference.
|
|
35
37
|
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
For live examples showing Cast UI components with custom themes (Consumer, Corporate, Luxury), see the companion repo:
|
|
41
|
+
|
|
42
|
+
**[Connagh/cast-ui-examples](https://github.com/Connagh/cast-ui-examples)** — includes a multi-theme website, Expo Snack, and an example Storybook demonstrating how to set up `createTheme()` with your own brand.
|
|
43
|
+
|
|
36
44
|
## Project Structure
|
|
37
45
|
|
|
38
46
|
```
|
|
@@ -42,35 +50,35 @@ cast-ui/
|
|
|
42
50
|
Button/
|
|
43
51
|
Button.tsx RN Pressable + Text, theme-aware
|
|
44
52
|
Button.stories.tsx Storybook stories
|
|
53
|
+
Card/
|
|
54
|
+
Card.tsx RN View + Text, theme-aware
|
|
55
|
+
Card.stories.tsx Storybook stories
|
|
45
56
|
theme/
|
|
46
57
|
types.ts CastTheme TypeScript interface
|
|
58
|
+
createTheme.ts Deep-merge utility for custom themes
|
|
47
59
|
ThemeProvider.tsx React Context provider + useTheme hook
|
|
48
|
-
fonts.ts
|
|
60
|
+
fonts.ts Dynamic font family helpers
|
|
49
61
|
index.ts Barrel export
|
|
50
62
|
tokens/
|
|
51
63
|
build.ts Reads Figma JSON, generates TS theme objects
|
|
52
64
|
generated/ Auto-generated (gitignored)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
corporate.ts
|
|
56
|
-
luxury.ts
|
|
65
|
+
default.ts
|
|
66
|
+
default.reference.json Copy-paste starting point for custom themes
|
|
57
67
|
index.ts
|
|
58
68
|
index.ts Public API
|
|
59
69
|
design-tokens/ Source of truth (Figma export)
|
|
60
|
-
|
|
61
|
-
Consumer.tokens.json Vibrant violet, Poppins
|
|
62
|
-
Corporate.tokens.json Professional blue, Merriweather + Inter
|
|
63
|
-
Luxury.tokens.json Dark gold, Playfair Display + Cormorant Garamond
|
|
70
|
+
Default.tokens.json Default theme (system-ui, slate neutrals)
|
|
64
71
|
DESIGN-TOKENS-SUMMARY.md Complete token reference
|
|
65
72
|
.storybook/
|
|
66
73
|
main.ts Webpack config with react-native-web alias
|
|
67
|
-
preview.ts
|
|
68
|
-
preview-head.html
|
|
74
|
+
preview.ts Decorator wrapping stories in default theme
|
|
75
|
+
preview-head.html (empty — default theme uses system fonts)
|
|
69
76
|
.github/workflows/
|
|
70
77
|
chromatic.yml Visual regression testing on push
|
|
71
78
|
adoption.yml Zeroheight adoption tracking on push to main
|
|
72
79
|
publish.yml Publish to npm on push to main
|
|
73
80
|
dist/ Build output (gitignored)
|
|
81
|
+
default.reference.json Shipped in package for consumers
|
|
74
82
|
tsconfig.json Development TypeScript config
|
|
75
83
|
tsconfig.build.json Library build config (excludes stories)
|
|
76
84
|
```
|
|
@@ -90,7 +98,7 @@ npm install
|
|
|
90
98
|
|
|
91
99
|
### Build Tokens
|
|
92
100
|
|
|
93
|
-
Generates TypeScript theme
|
|
101
|
+
Generates the TypeScript theme object and reference JSON from the Figma token file in `design-tokens/`:
|
|
94
102
|
|
|
95
103
|
```bash
|
|
96
104
|
npm run build:tokens
|
|
@@ -104,7 +112,7 @@ This writes to `src/tokens/generated/` (gitignored). Runs automatically before S
|
|
|
104
112
|
npm run storybook
|
|
105
113
|
```
|
|
106
114
|
|
|
107
|
-
Opens at `http://localhost:6006
|
|
115
|
+
Opens at `http://localhost:6006` showing components in the Default theme. For a multi-theme Storybook with custom themes, see the [example Storybook](https://github.com/Connagh/cast-ui-examples/tree/main/storybook-example) in the examples repo.
|
|
108
116
|
|
|
109
117
|
## Scripts
|
|
110
118
|
|
|
@@ -113,41 +121,98 @@ Opens at `http://localhost:6006`. Use the paintbrush icon in the toolbar to swit
|
|
|
113
121
|
| `npm run build:tokens` | Generate TypeScript theme files from Figma token JSON |
|
|
114
122
|
| `npm run storybook` | Start Storybook dev server (auto-runs `build:tokens`) |
|
|
115
123
|
| `npm run build-storybook` | Build static Storybook (auto-runs `build:tokens`) |
|
|
116
|
-
| `npm run build` | Full library build: tokens + TypeScript compilation to `dist/` |
|
|
124
|
+
| `npm run build` | Full library build: tokens + TypeScript compilation + reference JSON to `dist/` |
|
|
117
125
|
| `npm publish` | Publish to npm (auto-runs `build` via `prepublishOnly`) |
|
|
118
126
|
| `npm run zh:track-package` | Register/update package info with Zeroheight (runs automatically via CI) |
|
|
119
127
|
|
|
120
|
-
##
|
|
128
|
+
## Creating a Custom Theme
|
|
121
129
|
|
|
122
|
-
|
|
130
|
+
Cast UI ships a **Default base theme** that uses system fonts, slate neutrals, and moderate border radii. Create your own branded theme in three steps:
|
|
123
131
|
|
|
124
|
-
|
|
125
|
-
|-------|---------------|------------|---------------|-----------|
|
|
126
|
-
| **White Label** (default) | Slate-900 | system-ui | Moderate (8px buttons) | Neutral, adaptable |
|
|
127
|
-
| **Consumer** | Violet-600 | Poppins | Rounded (24px pill buttons) | Vibrant, friendly |
|
|
128
|
-
| **Corporate** | Blue-600 | Merriweather + Inter | Crisp (4px buttons) | Professional, structured |
|
|
129
|
-
| **Luxury** | Gold-400 on Black | Playfair Display + Cormorant Garamond | Zero (sharp edges) | Premium, elegant |
|
|
132
|
+
### 1. Copy the reference JSON
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
The package includes `default.reference.json` — a complete snapshot of all theme values. Copy it into your project as a starting point:
|
|
132
135
|
|
|
133
|
-
|
|
136
|
+
```bash
|
|
137
|
+
cp node_modules/@castui/cast-ui/dist/default.reference.json ./my-brand-theme.json
|
|
138
|
+
```
|
|
134
139
|
|
|
135
|
-
###
|
|
140
|
+
### 2. Modify desired values
|
|
141
|
+
|
|
142
|
+
Edit `my-brand-theme.json` to change only the values you want. You only need to include the properties you're overriding — everything else inherits from the Default theme:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"name": "my-brand",
|
|
147
|
+
"semantic": {
|
|
148
|
+
"color": {
|
|
149
|
+
"primary": "#553C9A",
|
|
150
|
+
"onPrimary": "#FFFFFF",
|
|
151
|
+
"primaryHover": "#6B46C1",
|
|
152
|
+
"primaryPressed": "#44337A"
|
|
153
|
+
},
|
|
154
|
+
"fontFamily": {
|
|
155
|
+
"brand": "Poppins",
|
|
156
|
+
"interface": "Poppins"
|
|
157
|
+
},
|
|
158
|
+
"borderRadius": {
|
|
159
|
+
"small": 12,
|
|
160
|
+
"medium": 16,
|
|
161
|
+
"large": 24
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
136
166
|
|
|
137
|
-
|
|
167
|
+
### 3. Create the theme and provide it
|
|
138
168
|
|
|
139
169
|
```tsx
|
|
140
|
-
import { CastThemeProvider,
|
|
170
|
+
import { CastThemeProvider, createTheme, googleFontsUrl } from '@castui/cast-ui';
|
|
171
|
+
import overrides from './my-brand-theme.json';
|
|
172
|
+
|
|
173
|
+
const myTheme = createTheme(overrides);
|
|
174
|
+
|
|
175
|
+
// Load any custom fonts (web)
|
|
176
|
+
const fontUrl = googleFontsUrl(myTheme);
|
|
177
|
+
if (fontUrl) {
|
|
178
|
+
const link = document.createElement('link');
|
|
179
|
+
link.href = fontUrl;
|
|
180
|
+
link.rel = 'stylesheet';
|
|
181
|
+
document.head.appendChild(link);
|
|
182
|
+
}
|
|
141
183
|
|
|
142
184
|
export default function App() {
|
|
143
185
|
return (
|
|
144
|
-
<CastThemeProvider theme={
|
|
145
|
-
{/*
|
|
186
|
+
<CastThemeProvider theme={myTheme}>
|
|
187
|
+
{/* your app */}
|
|
146
188
|
</CastThemeProvider>
|
|
147
189
|
);
|
|
148
190
|
}
|
|
149
191
|
```
|
|
150
192
|
|
|
193
|
+
`createTheme()` deep-merges your partial overrides with the Default theme, producing a complete `CastTheme` object. You can also pass a second argument to merge against a different base: `createTheme(overrides, otherBaseTheme)`.
|
|
194
|
+
|
|
195
|
+
## Theme System
|
|
196
|
+
|
|
197
|
+
### ThemeProvider
|
|
198
|
+
|
|
199
|
+
Wrap your app in `CastThemeProvider`. Defaults to the Default base theme:
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import { CastThemeProvider, defaultTheme, createTheme } from '@castui/cast-ui';
|
|
203
|
+
|
|
204
|
+
// Use the default theme as-is...
|
|
205
|
+
<CastThemeProvider theme={defaultTheme}>
|
|
206
|
+
<App />
|
|
207
|
+
</CastThemeProvider>
|
|
208
|
+
|
|
209
|
+
// ...or create a custom theme
|
|
210
|
+
const myTheme = createTheme({ name: 'my-brand', semantic: { color: { primary: '#FF0000' } } });
|
|
211
|
+
<CastThemeProvider theme={myTheme}>
|
|
212
|
+
<App />
|
|
213
|
+
</CastThemeProvider>
|
|
214
|
+
```
|
|
215
|
+
|
|
151
216
|
### useTheme
|
|
152
217
|
|
|
153
218
|
Access the current theme inside any component:
|
|
@@ -176,7 +241,7 @@ function MyComponent() {
|
|
|
176
241
|
Every theme conforms to the `CastTheme` interface (see `src/theme/types.ts`):
|
|
177
242
|
|
|
178
243
|
```
|
|
179
|
-
theme.name
|
|
244
|
+
theme.name string (e.g. 'default', 'my-brand')
|
|
180
245
|
theme.semantic.color.* 30 semantic colours (surface, primary, error, etc.)
|
|
181
246
|
theme.semantic.fontFamily.* brand, interface, data
|
|
182
247
|
theme.semantic.fontSize.* display, h1, h2, h3, body, small, button
|
|
@@ -187,6 +252,7 @@ theme.semantic.paragraphSpacing.* body, editorial
|
|
|
187
252
|
theme.semantic.paragraphIndent.* editorial
|
|
188
253
|
theme.semantic.borderRadius.* small, medium, large
|
|
189
254
|
theme.component.button.* All button tokens (padding, colours, variants, states)
|
|
255
|
+
theme.component.card.* All card tokens (padding, colours, typography, elevation)
|
|
190
256
|
```
|
|
191
257
|
|
|
192
258
|
## Components
|
|
@@ -210,39 +276,103 @@ import { Button } from '@castui/cast-ui';
|
|
|
210
276
|
| `disabled` | `boolean` | `false` | Disabled state |
|
|
211
277
|
| `backgroundColor` | `string` | - | Override background colour |
|
|
212
278
|
|
|
279
|
+
### Card
|
|
280
|
+
|
|
281
|
+
React Native `View` + `Text`. Consumes tokens from `theme.component.card` and `theme.semantic`.
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
import { Card, Button } from '@castui/cast-ui';
|
|
285
|
+
|
|
286
|
+
<Card
|
|
287
|
+
title="Title"
|
|
288
|
+
subtitle="Subtitle"
|
|
289
|
+
body="Body"
|
|
290
|
+
actions={
|
|
291
|
+
<>
|
|
292
|
+
<Button label="Action 1" variant="filled" />
|
|
293
|
+
<Button label="Action 2" variant="outline" />
|
|
294
|
+
</>
|
|
295
|
+
}
|
|
296
|
+
/>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
| Prop | Type | Default | Description |
|
|
300
|
+
|------|------|---------|-------------|
|
|
301
|
+
| `title` | `string` | required | Card heading text |
|
|
302
|
+
| `subtitle` | `string` | - | Optional subtitle below the title |
|
|
303
|
+
| `body` | `string` | - | Optional body text |
|
|
304
|
+
| `actions` | `React.ReactNode` | - | Optional actions row (e.g. Button components) |
|
|
305
|
+
|
|
213
306
|
## Font Handling
|
|
214
307
|
|
|
215
308
|
Components reference font families from the theme tokens. Font **loading** is the consumer's responsibility.
|
|
216
309
|
|
|
217
310
|
### Web
|
|
218
311
|
|
|
219
|
-
|
|
312
|
+
Use `googleFontsUrl()` to generate a Google Fonts `<link>` href for any theme:
|
|
220
313
|
|
|
221
314
|
```ts
|
|
222
315
|
import { googleFontsUrl } from '@castui/cast-ui';
|
|
223
316
|
|
|
224
|
-
const url = googleFontsUrl(
|
|
225
|
-
//
|
|
317
|
+
const url = googleFontsUrl(myTheme);
|
|
318
|
+
// Returns null for themes using only system-ui, or a Google Fonts URL for custom fonts
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Discovering theme fonts
|
|
322
|
+
|
|
323
|
+
Use `getThemeFontFamilies()` to dynamically extract all custom font families from any theme:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { getThemeFontFamilies } from '@castui/cast-ui';
|
|
327
|
+
|
|
328
|
+
const families = getThemeFontFamilies(myTheme);
|
|
329
|
+
// → ['Poppins'] or ['Inter', 'Merriweather'] etc.
|
|
330
|
+
// → [] for the Default theme (system-ui only)
|
|
226
331
|
```
|
|
227
332
|
|
|
228
333
|
### React Native / Expo
|
|
229
334
|
|
|
230
|
-
Load fonts with `expo-font` before rendering
|
|
335
|
+
Load fonts with `expo-font` before rendering. On **Android**, each weight must
|
|
336
|
+
be registered under a distinct name (the Expo Google Fonts convention) because
|
|
337
|
+
Android cannot combine a generic `fontFamily` with a numeric `fontWeight` for
|
|
338
|
+
custom fonts.
|
|
231
339
|
|
|
232
340
|
```ts
|
|
233
341
|
import { useFonts } from 'expo-font';
|
|
234
|
-
import {
|
|
235
|
-
|
|
342
|
+
import {
|
|
343
|
+
Poppins_400Regular,
|
|
344
|
+
Poppins_500Medium,
|
|
345
|
+
Poppins_700Bold,
|
|
346
|
+
} from '@expo-google-fonts/poppins';
|
|
347
|
+
|
|
348
|
+
const [loaded] = useFonts({
|
|
349
|
+
Poppins: Poppins_400Regular, // weight 400 → bare name
|
|
350
|
+
Poppins_500Medium: Poppins_500Medium, // weight 500
|
|
351
|
+
Poppins_700Bold: Poppins_700Bold, // weight 700
|
|
352
|
+
});
|
|
236
353
|
```
|
|
237
354
|
|
|
238
|
-
The
|
|
355
|
+
The naming convention is:
|
|
356
|
+
|
|
357
|
+
| Weight | Registration Key |
|
|
358
|
+
|--------|-----------------|
|
|
359
|
+
| 400 | `"FontName"` |
|
|
360
|
+
| 500 | `"FontName_500Medium"` |
|
|
361
|
+
| 700 | `"FontName_700Bold"` |
|
|
239
362
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
363
|
+
Components use `resolveFont()` internally so the correct font name is selected
|
|
364
|
+
automatically on each platform:
|
|
365
|
+
|
|
366
|
+
- **iOS / Web** — `{ fontFamily, fontWeight }` passed through unchanged.
|
|
367
|
+
- **Android** — maps to the weight-specific registered name (e.g. `"Poppins_700Bold"`) and sets `fontWeight: 'normal'`.
|
|
368
|
+
- **system-ui** — omits `fontFamily` (platform default) on all platforms.
|
|
369
|
+
|
|
370
|
+
The **Default** theme uses `system-ui` (platform default) and requires no font loading.
|
|
371
|
+
|
|
372
|
+
> **Custom Themes:** The convention works for any font — register each weight
|
|
373
|
+
> under `FontName`, `FontName_500Medium`, and `FontName_700Bold` and
|
|
374
|
+
> `resolveFont()` will handle the rest. The `ANDROID_WEIGHT_SUFFIX` map is
|
|
375
|
+
> exported if you need to build registration keys programmatically.
|
|
246
376
|
|
|
247
377
|
## Consumer Installation
|
|
248
378
|
|
|
@@ -257,20 +387,23 @@ import {
|
|
|
257
387
|
CastThemeProvider,
|
|
258
388
|
useTheme,
|
|
259
389
|
Button,
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
390
|
+
Card,
|
|
391
|
+
defaultTheme,
|
|
392
|
+
createTheme,
|
|
393
|
+
googleFontsUrl,
|
|
394
|
+
getThemeFontFamilies,
|
|
395
|
+
resolveFont,
|
|
396
|
+
ANDROID_WEIGHT_SUFFIX,
|
|
264
397
|
} from '@castui/cast-ui';
|
|
398
|
+
|
|
399
|
+
import type { CastTheme, DeepPartial } from '@castui/cast-ui';
|
|
265
400
|
```
|
|
266
401
|
|
|
267
402
|
## Storybook
|
|
268
403
|
|
|
269
404
|
Storybook runs React Native components in the browser via React Native Web. The webpack config in `.storybook/main.ts` aliases `react-native` to `react-native-web`.
|
|
270
405
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
The toolbar provides a paintbrush dropdown to switch between all four themes live. This is configured via `globalTypes` and a decorator in `.storybook/preview.ts` that wraps every story in `CastThemeProvider`.
|
|
406
|
+
The built-in Storybook shows components in the **Default theme** only. For a multi-theme Storybook demonstrating custom themes via `createTheme()`, see the [example Storybook](https://github.com/Connagh/cast-ui-examples/tree/main/storybook-example) in the examples repo.
|
|
274
407
|
|
|
275
408
|
### Chromatic
|
|
276
409
|
|
|
@@ -278,18 +411,18 @@ Visual regression testing runs on every push via the GitHub Actions workflow at
|
|
|
278
411
|
|
|
279
412
|
## Token Build Pipeline
|
|
280
413
|
|
|
281
|
-
The build script (`src/tokens/build.ts`) reads Figma-exported JSON from `design-tokens/` and generates fully-resolved TypeScript theme
|
|
414
|
+
The build script (`src/tokens/build.ts`) reads the Figma-exported JSON from `design-tokens/` and generates a fully-resolved TypeScript theme object plus a reference JSON.
|
|
282
415
|
|
|
283
416
|
**What it does:**
|
|
284
417
|
|
|
285
|
-
1. Reads
|
|
418
|
+
1. Reads `Default.tokens.json`
|
|
286
419
|
2. Recursively resolves all `{Primitive.Colour.Slate-900}` style alias references through the three-tier chain
|
|
287
420
|
3. Extracts hex values from Figma's colour object format (`{ colorSpace, components, hex }`)
|
|
288
|
-
4. Outputs typed
|
|
421
|
+
4. Outputs `default.ts` (typed theme object) and `default.reference.json` (copy-paste starting point) to `src/tokens/generated/`
|
|
289
422
|
|
|
290
|
-
**When to re-run:** After updating
|
|
423
|
+
**When to re-run:** After updating `design-tokens/Default.tokens.json`. The script runs automatically before Storybook and library builds.
|
|
291
424
|
|
|
292
|
-
**
|
|
425
|
+
**Creating a custom theme:** Copy `default.reference.json` from the published package, modify the values you want, and pass the overrides to `createTheme()`. See [Creating a Custom Theme](#creating-a-custom-theme) above.
|
|
293
426
|
|
|
294
427
|
## Adding a New Component
|
|
295
428
|
|
|
@@ -298,7 +431,7 @@ The build script (`src/tokens/build.ts`) reads Figma-exported JSON from `design-
|
|
|
298
431
|
3. Use only React Native primitives (`View`, `Text`, `Pressable`, `ScrollView`, etc.)
|
|
299
432
|
4. Create `ComponentName.stories.tsx` alongside the component
|
|
300
433
|
5. Export the component and its types from `src/index.ts`
|
|
301
|
-
6. If the component needs new design tokens, add them to
|
|
434
|
+
6. If the component needs new design tokens, add them to `Default.tokens.json` and update `src/theme/types.ts`
|
|
302
435
|
|
|
303
436
|
## Adoption Tracking
|
|
304
437
|
|
|
@@ -377,7 +510,7 @@ This means merging a PR to `main` does **not** automatically publish to npm. Onl
|
|
|
377
510
|
**To publish a new version:**
|
|
378
511
|
|
|
379
512
|
1. Create a feature branch and make your changes
|
|
380
|
-
2. Update the `version` field in `package.json` (e.g. `0.
|
|
513
|
+
2. Update the `version` field in `package.json` (e.g. `0.3.0` → `0.4.0`)
|
|
381
514
|
3. Push the branch and open a PR to `main`
|
|
382
515
|
4. Chromatic runs and creates status checks on the PR
|
|
383
516
|
5. Review and accept any visual changes in the Chromatic UI
|
|
@@ -392,9 +525,9 @@ This means merging a PR to `main` does **not** automatically publish to npm. Onl
|
|
|
392
525
|
|
|
393
526
|
| Change type | Bump | Example |
|
|
394
527
|
|-------------|------|---------|
|
|
395
|
-
| Bug fix or minor tweak | Patch | `0.
|
|
396
|
-
| New component or feature | Minor | `0.
|
|
397
|
-
| Breaking API change | Major | `0.
|
|
528
|
+
| Bug fix or minor tweak | Patch | `0.3.0` → `0.3.1` |
|
|
529
|
+
| New component or feature | Minor | `0.3.0` → `0.4.0` |
|
|
530
|
+
| Breaking API change | Major | `0.9.0` → `1.0.0` |
|
|
398
531
|
|
|
399
532
|
**Package details:**
|
|
400
533
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAOtB,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC;IAChE,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,iCAAiC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,OAAkB,EAClB,eAAe,EACf,QAAgB,EAChB,GAAG,cAAc,EAClB,EAAE,WAAW,2CAuEb"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Pressable, Text, } from 'react-native';
|
|
4
|
-
import { useTheme } from '../../theme';
|
|
4
|
+
import { useTheme, resolveFont } from '../../theme';
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Component
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
@@ -58,13 +58,11 @@ export function Button({ label, variant = 'filled', backgroundColor, disabled =
|
|
|
58
58
|
}),
|
|
59
59
|
opacity: disabled ? 0.6 : 1,
|
|
60
60
|
};
|
|
61
|
-
const fontFamily = bt.fontFamily === 'system-ui' ? undefined : bt.fontFamily;
|
|
62
61
|
const textStyle = {
|
|
63
62
|
color: resolveContent(),
|
|
64
63
|
fontSize: bt.textSize,
|
|
65
|
-
fontWeight: String(bt.fontWeight),
|
|
66
64
|
lineHeight: bt.textSize * bt.lineHeight,
|
|
67
|
-
...(fontFamily
|
|
65
|
+
...resolveFont(bt.fontFamily, bt.fontWeight),
|
|
68
66
|
};
|
|
69
67
|
return (_jsx(Pressable, { ...pressableProps, disabled: disabled, style: containerStyle, ...{
|
|
70
68
|
onHoverIn: () => setHovered(true),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EACL,SAAS,EACT,IAAI,
|
|
1
|
+
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/Card/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAOtB,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;IACzD,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAMD;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,EACnB,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,GAAG,SAAS,EACb,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/Card/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAOtB,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;IACzD,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAMD;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,EACnB,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,GAAG,SAAS,EACb,EAAE,SAAS,2CA0DX"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { View, Text, } from 'react-native';
|
|
3
|
-
import { useTheme } from '../../theme';
|
|
3
|
+
import { useTheme, resolveFont } from '../../theme';
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
5
|
// Component
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
@@ -28,32 +28,26 @@ export function Card({ title, subtitle, body, actions, ...viewProps }) {
|
|
|
28
28
|
? { boxShadow: '0 1px 3px rgba(0,0,0,0.12)' }
|
|
29
29
|
: {}),
|
|
30
30
|
};
|
|
31
|
-
const headingFontFamily = ct.headingFontFamily === 'system-ui' ? undefined : ct.headingFontFamily;
|
|
32
31
|
const titleStyle = {
|
|
33
32
|
fontSize: ct.headingSize,
|
|
34
|
-
fontWeight: String(ct.headingWeight),
|
|
35
33
|
lineHeight: ct.headingSize * sem.lineHeight.body,
|
|
36
34
|
letterSpacing: sem.letterSpacing.heading,
|
|
37
35
|
color: sem.color.onSurface,
|
|
38
|
-
...(headingFontFamily
|
|
36
|
+
...resolveFont(ct.headingFontFamily, ct.headingWeight),
|
|
39
37
|
};
|
|
40
|
-
const subtitleFontFamily = sem.fontFamily.interface === 'system-ui' ? undefined : sem.fontFamily.interface;
|
|
41
38
|
const subtitleStyle = {
|
|
42
39
|
fontSize: sem.fontSize.small,
|
|
43
|
-
fontWeight: String(sem.fontWeight.body),
|
|
44
40
|
lineHeight: sem.fontSize.small * sem.lineHeight.body,
|
|
45
41
|
letterSpacing: sem.letterSpacing.body,
|
|
46
42
|
color: sem.color.onSurfaceMuted,
|
|
47
|
-
...(
|
|
43
|
+
...resolveFont(sem.fontFamily.interface, sem.fontWeight.body),
|
|
48
44
|
};
|
|
49
|
-
const bodyFontFamily = ct.bodyFontFamily === 'system-ui' ? undefined : ct.bodyFontFamily;
|
|
50
45
|
const bodyStyle = {
|
|
51
46
|
fontSize: ct.bodySize,
|
|
52
|
-
fontWeight: String(ct.bodyWeight),
|
|
53
47
|
lineHeight: ct.bodySize * sem.lineHeight.body,
|
|
54
48
|
letterSpacing: sem.letterSpacing.body,
|
|
55
49
|
color: sem.color.onSurfaceMuted,
|
|
56
|
-
...(bodyFontFamily
|
|
50
|
+
...resolveFont(ct.bodyFontFamily, ct.bodyWeight),
|
|
57
51
|
};
|
|
58
52
|
const actionsStyle = {
|
|
59
53
|
flexDirection: 'row',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.js","sourceRoot":"","sources":["../../../src/components/Card/Card.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,IAAI,EACJ,IAAI,GAIL,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Card.js","sourceRoot":"","sources":["../../../src/components/Card/Card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "default",
|
|
3
|
+
"semantic": {
|
|
4
|
+
"color": {
|
|
5
|
+
"surface": "#FFFFFF",
|
|
6
|
+
"onSurface": "#0F172A",
|
|
7
|
+
"onSurfaceMuted": "#475569",
|
|
8
|
+
"surfaceContainer": "#F8FAFC",
|
|
9
|
+
"primary": "#0F172A",
|
|
10
|
+
"onPrimary": "#FFFFFF",
|
|
11
|
+
"primaryHover": "#1E293B",
|
|
12
|
+
"primaryPressed": "#475569",
|
|
13
|
+
"secondary": "#E2E8F0",
|
|
14
|
+
"onSecondary": "#0F172A",
|
|
15
|
+
"success": "#0C6F1E",
|
|
16
|
+
"onSuccess": "#FFFFFF",
|
|
17
|
+
"error": "#6F0C0C",
|
|
18
|
+
"onError": "#FFFFFF",
|
|
19
|
+
"warning": "#947C3E",
|
|
20
|
+
"onWarning": "#FFFFFF",
|
|
21
|
+
"border": "#E2E8F0",
|
|
22
|
+
"borderSubtle": "#F8FAFC",
|
|
23
|
+
"disabledContainer": "#E2E8F0",
|
|
24
|
+
"onDisabled": "#94A3B8",
|
|
25
|
+
"primaryContainer": "#E2E8F0",
|
|
26
|
+
"onPrimaryContainer": "#0F172A",
|
|
27
|
+
"secondaryContainer": "#F8FAFC",
|
|
28
|
+
"onSecondaryContainer": "#1E293B",
|
|
29
|
+
"errorContainer": "#FDF2F2",
|
|
30
|
+
"onErrorContainer": "#4A0808",
|
|
31
|
+
"successContainer": "#F0FDF1",
|
|
32
|
+
"onSuccessContainer": "#084A14",
|
|
33
|
+
"warningContainer": "#FDF8EB",
|
|
34
|
+
"onWarningContainer": "#6B592D"
|
|
35
|
+
},
|
|
36
|
+
"fontFamily": {
|
|
37
|
+
"brand": "system-ui",
|
|
38
|
+
"interface": "system-ui",
|
|
39
|
+
"data": "JetBrains Mono"
|
|
40
|
+
},
|
|
41
|
+
"fontSize": {
|
|
42
|
+
"display": 39,
|
|
43
|
+
"h1": 31,
|
|
44
|
+
"h2": 25,
|
|
45
|
+
"h3": 20,
|
|
46
|
+
"body": 16,
|
|
47
|
+
"small": 12.800000190734863,
|
|
48
|
+
"button": 16
|
|
49
|
+
},
|
|
50
|
+
"fontWeight": {
|
|
51
|
+
"heading": 700,
|
|
52
|
+
"body": 400,
|
|
53
|
+
"button": 500
|
|
54
|
+
},
|
|
55
|
+
"lineHeight": {
|
|
56
|
+
"heading": 1.2000000476837158,
|
|
57
|
+
"body": 1.5,
|
|
58
|
+
"uiLabel": 1
|
|
59
|
+
},
|
|
60
|
+
"letterSpacing": {
|
|
61
|
+
"heading": -0.019999999552965164,
|
|
62
|
+
"body": 0,
|
|
63
|
+
"label": 0.019999999552965164
|
|
64
|
+
},
|
|
65
|
+
"paragraphSpacing": {
|
|
66
|
+
"body": 16,
|
|
67
|
+
"editorial": 24
|
|
68
|
+
},
|
|
69
|
+
"paragraphIndent": {
|
|
70
|
+
"editorial": 0
|
|
71
|
+
},
|
|
72
|
+
"borderRadius": {
|
|
73
|
+
"small": 4,
|
|
74
|
+
"medium": 8,
|
|
75
|
+
"large": 12
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"component": {
|
|
79
|
+
"button": {
|
|
80
|
+
"paddingHorizontal": 16,
|
|
81
|
+
"paddingVertical": 8,
|
|
82
|
+
"gap": 8,
|
|
83
|
+
"cornerRadius": 8,
|
|
84
|
+
"borderWidth": 2,
|
|
85
|
+
"textSize": 16,
|
|
86
|
+
"fontWeight": 500,
|
|
87
|
+
"lineHeight": 1,
|
|
88
|
+
"fontFamily": "system-ui",
|
|
89
|
+
"filled": {
|
|
90
|
+
"background": "#0F172A",
|
|
91
|
+
"content": "#FFFFFF"
|
|
92
|
+
},
|
|
93
|
+
"outline": {
|
|
94
|
+
"background": "#FFFFFF",
|
|
95
|
+
"border": "#0F172A",
|
|
96
|
+
"content": "#0F172A"
|
|
97
|
+
},
|
|
98
|
+
"text": {
|
|
99
|
+
"background": "#FFFFFF",
|
|
100
|
+
"content": "#0F172A"
|
|
101
|
+
},
|
|
102
|
+
"state": {
|
|
103
|
+
"hoverBackground": "#1E293B",
|
|
104
|
+
"pressedBackground": "#475569",
|
|
105
|
+
"disabledBackground": "#E2E8F0",
|
|
106
|
+
"disabledContent": "#94A3B8"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"card": {
|
|
110
|
+
"padding": 16,
|
|
111
|
+
"gap": 12,
|
|
112
|
+
"background": "#F8FAFC",
|
|
113
|
+
"stroke": "#E2E8F0",
|
|
114
|
+
"strokeWidth": 2,
|
|
115
|
+
"cornerRadius": 12,
|
|
116
|
+
"elevation": 1,
|
|
117
|
+
"headingSize": 20,
|
|
118
|
+
"headingWeight": 700,
|
|
119
|
+
"headingFontFamily": "system-ui",
|
|
120
|
+
"bodySize": 16,
|
|
121
|
+
"bodyWeight": 400,
|
|
122
|
+
"bodyFontFamily": "system-ui"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|