@castui/cast-ui 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -61
- 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 +7 -5
- 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 +41 -17
- package/dist/theme/fonts.d.ts.map +1 -1
- package/dist/theme/fonts.js +63 -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
|
|
|
@@ -35,9 +37,9 @@ See [`design-tokens/DESIGN-TOKENS-SUMMARY.md`](design-tokens/DESIGN-TOKENS-SUMMA
|
|
|
35
37
|
|
|
36
38
|
## Examples
|
|
37
39
|
|
|
38
|
-
For live examples showing Cast UI components
|
|
40
|
+
For live examples showing Cast UI components with custom themes (Consumer, Corporate, Luxury), see the companion repo:
|
|
39
41
|
|
|
40
|
-
**[Connagh/cast-ui-examples](https://github.com/Connagh/cast-ui-examples)** (
|
|
42
|
+
**[Connagh/cast-ui-examples](https://github.com/Connagh/cast-ui-examples)** — includes an Expo Snack demo showing `createTheme()` with custom themes running cross-platform (iOS, Android, Web).
|
|
41
43
|
|
|
42
44
|
## Project Structure
|
|
43
45
|
|
|
@@ -53,33 +55,30 @@ cast-ui/
|
|
|
53
55
|
Card.stories.tsx Storybook stories
|
|
54
56
|
theme/
|
|
55
57
|
types.ts CastTheme TypeScript interface
|
|
58
|
+
createTheme.ts Deep-merge utility for custom themes
|
|
56
59
|
ThemeProvider.tsx React Context provider + useTheme hook
|
|
57
|
-
fonts.ts
|
|
60
|
+
fonts.ts Dynamic font family helpers
|
|
58
61
|
index.ts Barrel export
|
|
59
62
|
tokens/
|
|
60
63
|
build.ts Reads Figma JSON, generates TS theme objects
|
|
61
64
|
generated/ Auto-generated (gitignored)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
corporate.ts
|
|
65
|
-
luxury.ts
|
|
65
|
+
default.ts
|
|
66
|
+
default.reference.json Copy-paste starting point for custom themes
|
|
66
67
|
index.ts
|
|
67
68
|
index.ts Public API
|
|
68
69
|
design-tokens/ Source of truth (Figma export)
|
|
69
|
-
|
|
70
|
-
Consumer.tokens.json Vibrant violet, Poppins
|
|
71
|
-
Corporate.tokens.json Professional blue, Merriweather + Inter
|
|
72
|
-
Luxury.tokens.json Dark gold, Playfair Display + Cormorant Garamond
|
|
70
|
+
Default.tokens.json Default theme (system-ui, slate neutrals)
|
|
73
71
|
DESIGN-TOKENS-SUMMARY.md Complete token reference
|
|
74
72
|
.storybook/
|
|
75
73
|
main.ts Webpack config with react-native-web alias
|
|
76
|
-
preview.ts
|
|
77
|
-
preview-head.html
|
|
74
|
+
preview.ts Decorator wrapping stories in default theme
|
|
75
|
+
preview-head.html (empty — default theme uses system fonts)
|
|
78
76
|
.github/workflows/
|
|
79
77
|
chromatic.yml Visual regression testing on push
|
|
80
78
|
adoption.yml Zeroheight adoption tracking on push to main
|
|
81
79
|
publish.yml Publish to npm on push to main
|
|
82
80
|
dist/ Build output (gitignored)
|
|
81
|
+
default.reference.json Shipped in package for consumers
|
|
83
82
|
tsconfig.json Development TypeScript config
|
|
84
83
|
tsconfig.build.json Library build config (excludes stories)
|
|
85
84
|
```
|
|
@@ -99,7 +98,7 @@ npm install
|
|
|
99
98
|
|
|
100
99
|
### Build Tokens
|
|
101
100
|
|
|
102
|
-
Generates TypeScript theme
|
|
101
|
+
Generates the TypeScript theme object and reference JSON from the Figma token file in `design-tokens/`:
|
|
103
102
|
|
|
104
103
|
```bash
|
|
105
104
|
npm run build:tokens
|
|
@@ -113,7 +112,7 @@ This writes to `src/tokens/generated/` (gitignored). Runs automatically before S
|
|
|
113
112
|
npm run storybook
|
|
114
113
|
```
|
|
115
114
|
|
|
116
|
-
Opens at `http://localhost:6006
|
|
115
|
+
Opens at `http://localhost:6006` showing components in the Default theme.
|
|
117
116
|
|
|
118
117
|
## Scripts
|
|
119
118
|
|
|
@@ -122,41 +121,98 @@ Opens at `http://localhost:6006`. Use the paintbrush icon in the toolbar to swit
|
|
|
122
121
|
| `npm run build:tokens` | Generate TypeScript theme files from Figma token JSON |
|
|
123
122
|
| `npm run storybook` | Start Storybook dev server (auto-runs `build:tokens`) |
|
|
124
123
|
| `npm run build-storybook` | Build static Storybook (auto-runs `build:tokens`) |
|
|
125
|
-
| `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/` |
|
|
126
125
|
| `npm publish` | Publish to npm (auto-runs `build` via `prepublishOnly`) |
|
|
127
126
|
| `npm run zh:track-package` | Register/update package info with Zeroheight (runs automatically via CI) |
|
|
128
127
|
|
|
129
|
-
##
|
|
128
|
+
## Creating a Custom Theme
|
|
130
129
|
|
|
131
|
-
|
|
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:
|
|
132
131
|
|
|
133
|
-
|
|
134
|
-
|-------|---------------|------------|---------------|-----------|
|
|
135
|
-
| **White Label** (default) | Slate-900 | system-ui | Moderate (8px buttons) | Neutral, adaptable |
|
|
136
|
-
| **Consumer** | Violet-600 | Poppins | Rounded (24px pill buttons) | Vibrant, friendly |
|
|
137
|
-
| **Corporate** | Blue-600 | Merriweather + Inter | Crisp (4px buttons) | Professional, structured |
|
|
138
|
-
| **Luxury** | Gold-400 on Black | Playfair Display + Cormorant Garamond | Zero (sharp edges) | Premium, elegant |
|
|
132
|
+
### 1. Copy the reference JSON
|
|
139
133
|
|
|
140
|
-
|
|
134
|
+
The package includes `default.reference.json` — a complete snapshot of all theme values. Copy it into your project as a starting point:
|
|
141
135
|
|
|
142
|
-
|
|
136
|
+
```bash
|
|
137
|
+
cp node_modules/@castui/cast-ui/dist/default.reference.json ./my-brand-theme.json
|
|
138
|
+
```
|
|
143
139
|
|
|
144
|
-
###
|
|
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
|
+
```
|
|
145
166
|
|
|
146
|
-
|
|
167
|
+
### 3. Create the theme and provide it
|
|
147
168
|
|
|
148
169
|
```tsx
|
|
149
|
-
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
|
+
}
|
|
150
183
|
|
|
151
184
|
export default function App() {
|
|
152
185
|
return (
|
|
153
|
-
<CastThemeProvider theme={
|
|
154
|
-
{/*
|
|
186
|
+
<CastThemeProvider theme={myTheme}>
|
|
187
|
+
{/* your app */}
|
|
155
188
|
</CastThemeProvider>
|
|
156
189
|
);
|
|
157
190
|
}
|
|
158
191
|
```
|
|
159
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
|
+
|
|
160
216
|
### useTheme
|
|
161
217
|
|
|
162
218
|
Access the current theme inside any component:
|
|
@@ -185,7 +241,7 @@ function MyComponent() {
|
|
|
185
241
|
Every theme conforms to the `CastTheme` interface (see `src/theme/types.ts`):
|
|
186
242
|
|
|
187
243
|
```
|
|
188
|
-
theme.name
|
|
244
|
+
theme.name string (e.g. 'default', 'my-brand')
|
|
189
245
|
theme.semantic.color.* 30 semantic colours (surface, primary, error, etc.)
|
|
190
246
|
theme.semantic.fontFamily.* brand, interface, data
|
|
191
247
|
theme.semantic.fontSize.* display, h1, h2, h3, body, small, button
|
|
@@ -253,13 +309,25 @@ Components reference font families from the theme tokens. Font **loading** is th
|
|
|
253
309
|
|
|
254
310
|
### Web
|
|
255
311
|
|
|
256
|
-
|
|
312
|
+
Use `googleFontsUrl()` to generate a Google Fonts `<link>` href for any theme:
|
|
257
313
|
|
|
258
314
|
```ts
|
|
259
315
|
import { googleFontsUrl } from '@castui/cast-ui';
|
|
260
316
|
|
|
261
|
-
const url = googleFontsUrl(
|
|
262
|
-
//
|
|
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)
|
|
263
331
|
```
|
|
264
332
|
|
|
265
333
|
### React Native / Expo
|
|
@@ -299,14 +367,7 @@ automatically on each platform:
|
|
|
299
367
|
- **Android** — maps to the weight-specific registered name (e.g. `"Poppins_700Bold"`) and sets `fontWeight: 'normal'`.
|
|
300
368
|
- **system-ui** — omits `fontFamily` (platform default) on all platforms.
|
|
301
369
|
|
|
302
|
-
The **
|
|
303
|
-
|
|
304
|
-
| Theme | Fonts to Load |
|
|
305
|
-
|-------|---------------|
|
|
306
|
-
| White Label | None (system default) |
|
|
307
|
-
| Consumer | Poppins |
|
|
308
|
-
| Corporate | Inter, Merriweather |
|
|
309
|
-
| Luxury | Playfair Display, Cormorant Garamond |
|
|
370
|
+
The **Default** theme uses `system-ui` (platform default) and requires no font loading.
|
|
310
371
|
|
|
311
372
|
> **Custom Themes:** The convention works for any font — register each weight
|
|
312
373
|
> under `FontName`, `FontName_500Medium`, and `FontName_700Bold` and
|
|
@@ -326,22 +387,23 @@ import {
|
|
|
326
387
|
CastThemeProvider,
|
|
327
388
|
useTheme,
|
|
328
389
|
Button,
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
390
|
+
Card,
|
|
391
|
+
defaultTheme,
|
|
392
|
+
createTheme,
|
|
393
|
+
googleFontsUrl,
|
|
394
|
+
getThemeFontFamilies,
|
|
333
395
|
resolveFont,
|
|
334
396
|
ANDROID_WEIGHT_SUFFIX,
|
|
335
397
|
} from '@castui/cast-ui';
|
|
398
|
+
|
|
399
|
+
import type { CastTheme, DeepPartial } from '@castui/cast-ui';
|
|
336
400
|
```
|
|
337
401
|
|
|
338
402
|
## Storybook
|
|
339
403
|
|
|
340
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`.
|
|
341
405
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
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**. For a cross-platform demo with custom themes, see the [Expo Snack](https://github.com/Connagh/cast-ui-examples/tree/main/expo-snack) in the examples repo.
|
|
345
407
|
|
|
346
408
|
### Chromatic
|
|
347
409
|
|
|
@@ -349,18 +411,18 @@ Visual regression testing runs on every push via the GitHub Actions workflow at
|
|
|
349
411
|
|
|
350
412
|
## Token Build Pipeline
|
|
351
413
|
|
|
352
|
-
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.
|
|
353
415
|
|
|
354
416
|
**What it does:**
|
|
355
417
|
|
|
356
|
-
1. Reads
|
|
418
|
+
1. Reads `Default.tokens.json`
|
|
357
419
|
2. Recursively resolves all `{Primitive.Colour.Slate-900}` style alias references through the three-tier chain
|
|
358
420
|
3. Extracts hex values from Figma's colour object format (`{ colorSpace, components, hex }`)
|
|
359
|
-
4. Outputs typed
|
|
421
|
+
4. Outputs `default.ts` (typed theme object) and `default.reference.json` (copy-paste starting point) to `src/tokens/generated/`
|
|
360
422
|
|
|
361
|
-
**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.
|
|
362
424
|
|
|
363
|
-
**
|
|
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.
|
|
364
426
|
|
|
365
427
|
## Adding a New Component
|
|
366
428
|
|
|
@@ -369,7 +431,7 @@ The build script (`src/tokens/build.ts`) reads Figma-exported JSON from `design-
|
|
|
369
431
|
3. Use only React Native primitives (`View`, `Text`, `Pressable`, `ScrollView`, etc.)
|
|
370
432
|
4. Create `ComponentName.stories.tsx` alongside the component
|
|
371
433
|
5. Export the component and its types from `src/index.ts`
|
|
372
|
-
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`
|
|
373
435
|
|
|
374
436
|
## Adoption Tracking
|
|
375
437
|
|
|
@@ -448,7 +510,7 @@ This means merging a PR to `main` does **not** automatically publish to npm. Onl
|
|
|
448
510
|
**To publish a new version:**
|
|
449
511
|
|
|
450
512
|
1. Create a feature branch and make your changes
|
|
451
|
-
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`)
|
|
452
514
|
3. Push the branch and open a PR to `main`
|
|
453
515
|
4. Chromatic runs and creates status checks on the PR
|
|
454
516
|
5. Review and accept any visual changes in the Chromatic UI
|
|
@@ -463,9 +525,9 @@ This means merging a PR to `main` does **not** automatically publish to npm. Onl
|
|
|
463
525
|
|
|
464
526
|
| Change type | Bump | Example |
|
|
465
527
|
|-------------|------|---------|
|
|
466
|
-
| Bug fix or minor tweak | Patch | `0.
|
|
467
|
-
| New component or feature | Minor | `0.
|
|
468
|
-
| 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` |
|
|
469
531
|
|
|
470
532
|
**Package details:**
|
|
471
533
|
|
|
@@ -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
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { CastThemeProvider, useTheme } from './theme';
|
|
2
2
|
export type { CastThemeProviderProps } from './theme';
|
|
3
3
|
export type { CastTheme, ThemeName, SemanticTokens, ComponentTokens, ButtonTokens, CardTokens, } from './theme';
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
4
|
+
export { createTheme } from './theme';
|
|
5
|
+
export type { DeepPartial } from './theme';
|
|
6
|
+
export { getThemeFontFamilies, googleFontsUrl, resolveFont, ANDROID_WEIGHT_SUFFIX } from './theme';
|
|
7
|
+
export { defaultTheme } from './tokens/generated';
|
|
6
8
|
export { Button } from './components/Button/Button';
|
|
7
9
|
export type { ButtonProps, ButtonVariant } from './components/Button/Button';
|
|
8
10
|
export { Card } from './components/Card/Card';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EACV,SAAS,EACT,SAAS,EACT,cAAc,EACd,eAAe,EACf,YAAY,EACZ,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EACV,SAAS,EACT,SAAS,EACT,cAAc,EACd,eAAe,EACf,YAAY,EACZ,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGnG,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE7E,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Theme system
|
|
5
5
|
export { CastThemeProvider, useTheme } from './theme';
|
|
6
|
-
export {
|
|
6
|
+
export { createTheme } from './theme';
|
|
7
|
+
export { getThemeFontFamilies, googleFontsUrl, resolveFont, ANDROID_WEIGHT_SUFFIX } from './theme';
|
|
7
8
|
// Theme objects
|
|
8
|
-
export {
|
|
9
|
+
export { defaultTheme } from './tokens/generated';
|
|
9
10
|
// Components
|
|
10
11
|
export { Button } from './components/Button/Button';
|
|
11
12
|
export { Card } from './components/Card/Card';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAUtD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAUtD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEnG,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,aAAa;AACb,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { CastTheme } from './types';
|
|
3
3
|
export interface CastThemeProviderProps {
|
|
4
|
-
/** The theme object to provide. Defaults to
|
|
4
|
+
/** The theme object to provide. Defaults to the Default base theme. */
|
|
5
5
|
theme?: CastTheme;
|
|
6
|
-
children
|
|
6
|
+
children?: React.ReactNode;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Wraps the component tree with the selected Cast theme.
|
|
10
10
|
*
|
|
11
11
|
* ```tsx
|
|
12
|
-
* import { CastThemeProvider } from '@castui/cast-ui';
|
|
13
|
-
* import
|
|
12
|
+
* import { CastThemeProvider, createTheme } from '@castui/cast-ui';
|
|
13
|
+
* import overrides from './my-brand.json';
|
|
14
14
|
*
|
|
15
|
-
*
|
|
15
|
+
* const myTheme = createTheme(overrides);
|
|
16
|
+
*
|
|
17
|
+
* <CastThemeProvider theme={myTheme}>
|
|
16
18
|
* <App />
|
|
17
19
|
* </CastThemeProvider>
|
|
18
20
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAazC,MAAM,WAAW,sBAAsB;IACrC,
|
|
1
|
+
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAazC,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAoB,EACpB,QAAQ,GACT,EAAE,sBAAsB,2CAIxB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,IAAI,SAAS,CAEpC"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { defaultTheme } from '../tokens/generated';
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
5
|
// Context
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
|
-
const ThemeContext = createContext(
|
|
7
|
+
const ThemeContext = createContext(defaultTheme);
|
|
8
8
|
/**
|
|
9
9
|
* Wraps the component tree with the selected Cast theme.
|
|
10
10
|
*
|
|
11
11
|
* ```tsx
|
|
12
|
-
* import { CastThemeProvider } from '@castui/cast-ui';
|
|
13
|
-
* import
|
|
12
|
+
* import { CastThemeProvider, createTheme } from '@castui/cast-ui';
|
|
13
|
+
* import overrides from './my-brand.json';
|
|
14
14
|
*
|
|
15
|
-
*
|
|
15
|
+
* const myTheme = createTheme(overrides);
|
|
16
|
+
*
|
|
17
|
+
* <CastThemeProvider theme={myTheme}>
|
|
16
18
|
* <App />
|
|
17
19
|
* </CastThemeProvider>
|
|
18
20
|
* ```
|
|
19
21
|
*/
|
|
20
|
-
export function CastThemeProvider({ theme =
|
|
22
|
+
export function CastThemeProvider({ theme = defaultTheme, children, }) {
|
|
21
23
|
return (_jsx(ThemeContext.Provider, { value: theme, children: children }));
|
|
22
24
|
}
|
|
23
25
|
// ---------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.js","sourceRoot":"","sources":["../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ThemeProvider.js","sourceRoot":"","sources":["../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,YAAY,GAAG,aAAa,CAAY,YAAY,CAAC,CAAC;AAY5D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,KAAK,GAAG,YAAY,EACpB,QAAQ,GACe;IACvB,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAyB,CACxE,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme creation utility.
|
|
3
|
+
*
|
|
4
|
+
* `createTheme()` deep-merges partial overrides with the default base theme,
|
|
5
|
+
* producing a complete `CastTheme` object. This is the primary API for
|
|
6
|
+
* creating custom branded themes.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createTheme, defaultTheme } from '@castui/cast-ui';
|
|
10
|
+
* import overrides from './my-brand.json';
|
|
11
|
+
*
|
|
12
|
+
* const myTheme = createTheme(overrides);
|
|
13
|
+
* // → complete CastTheme with your overrides applied on top of defaultTheme
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import type { CastTheme } from './types';
|
|
17
|
+
/**
|
|
18
|
+
* Recursively makes all properties of `T` optional.
|
|
19
|
+
* Useful for typing partial theme overrides passed to `createTheme()`.
|
|
20
|
+
*/
|
|
21
|
+
export type DeepPartial<T> = {
|
|
22
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Create a complete `CastTheme` by deep-merging partial overrides with a
|
|
26
|
+
* base theme (defaults to `defaultTheme`).
|
|
27
|
+
*
|
|
28
|
+
* Works with both small partial overrides *and* complete theme objects
|
|
29
|
+
* exported from Figma.
|
|
30
|
+
*
|
|
31
|
+
* @param overrides – Partial theme values to apply on top of the base.
|
|
32
|
+
* @param base – Optional base theme. Defaults to `defaultTheme`.
|
|
33
|
+
* @returns A complete, merged `CastTheme` object.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Minimal override – only change the primary colour
|
|
38
|
+
* const myTheme = createTheme({
|
|
39
|
+
* name: 'my-brand',
|
|
40
|
+
* semantic: { color: { primary: '#FF0000' } },
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* // Full override from a JSON file
|
|
44
|
+
* import overrides from './my-brand.json';
|
|
45
|
+
* const myTheme = createTheme(overrides);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function createTheme(overrides: DeepPartial<CastTheme>, base?: CastTheme): CastTheme;
|
|
49
|
+
//# sourceMappingURL=createTheme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTheme.d.ts","sourceRoot":"","sources":["../../src/theme/createTheme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAMzC;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAC;AA0DF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC,EACjC,IAAI,CAAC,EAAE,SAAS,GACf,SAAS,CAMX"}
|