@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.
Files changed (50) hide show
  1. package/README.md +123 -61
  2. package/dist/default.reference.json +125 -0
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +3 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/theme/ThemeProvider.d.ts +7 -5
  8. package/dist/theme/ThemeProvider.d.ts.map +1 -1
  9. package/dist/theme/ThemeProvider.js +8 -6
  10. package/dist/theme/ThemeProvider.js.map +1 -1
  11. package/dist/theme/createTheme.d.ts +49 -0
  12. package/dist/theme/createTheme.d.ts.map +1 -0
  13. package/dist/theme/createTheme.js +85 -0
  14. package/dist/theme/createTheme.js.map +1 -0
  15. package/dist/theme/fonts.d.ts +41 -17
  16. package/dist/theme/fonts.d.ts.map +1 -1
  17. package/dist/theme/fonts.js +63 -22
  18. package/dist/theme/fonts.js.map +1 -1
  19. package/dist/theme/index.d.ts +3 -1
  20. package/dist/theme/index.d.ts.map +1 -1
  21. package/dist/theme/index.js +2 -1
  22. package/dist/theme/index.js.map +1 -1
  23. package/dist/theme/types.d.ts +4 -3
  24. package/dist/theme/types.d.ts.map +1 -1
  25. package/dist/theme/types.js +3 -2
  26. package/dist/theme/types.js.map +1 -1
  27. package/dist/tokens/generated/default.d.ts +3 -0
  28. package/dist/tokens/generated/default.d.ts.map +1 -0
  29. package/dist/tokens/generated/{white-label.js → default.js} +3 -3
  30. package/dist/tokens/generated/default.js.map +1 -0
  31. package/dist/tokens/generated/index.d.ts +1 -4
  32. package/dist/tokens/generated/index.d.ts.map +1 -1
  33. package/dist/tokens/generated/index.js +1 -4
  34. package/dist/tokens/generated/index.js.map +1 -1
  35. package/package.json +2 -2
  36. package/dist/tokens/generated/consumer.d.ts +0 -3
  37. package/dist/tokens/generated/consumer.d.ts.map +0 -1
  38. package/dist/tokens/generated/consumer.js +0 -126
  39. package/dist/tokens/generated/consumer.js.map +0 -1
  40. package/dist/tokens/generated/corporate.d.ts +0 -3
  41. package/dist/tokens/generated/corporate.d.ts.map +0 -1
  42. package/dist/tokens/generated/corporate.js +0 -126
  43. package/dist/tokens/generated/corporate.js.map +0 -1
  44. package/dist/tokens/generated/luxury.d.ts +0 -3
  45. package/dist/tokens/generated/luxury.d.ts.map +0 -1
  46. package/dist/tokens/generated/luxury.js +0 -126
  47. package/dist/tokens/generated/luxury.js.map +0 -1
  48. package/dist/tokens/generated/white-label.d.ts +0 -3
  49. package/dist/tokens/generated/white-label.d.ts.map +0 -1
  50. 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 multi-theme support. Components are built with vanilla React Native primitives and themed via design tokens exported from Figma.
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 and theming in action, see the companion repo:
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)** (in progress)
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 Per-theme font family helpers
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
- white-label.ts
63
- consumer.ts
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
- White label.tokens.json Default theme (system-ui, slate neutrals)
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 Theme switcher toolbar + decorator
77
- preview-head.html Google Fonts <link> tags
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 objects from the Figma JSON files in `design-tokens/`:
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`. Use the paintbrush icon in the toolbar to switch between all four themes.
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
- ## Themes
128
+ ## Creating a Custom Theme
130
129
 
131
- Four themes share the same component API but produce completely different visual identities:
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
- | Theme | Primary Colour | Typography | Border Radius | Character |
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
- When themes switch, **all of the following change simultaneously**: colour palette, font families, border radius, spacing rhythm, elevation, font weight, paragraph spacing, and paragraph indent.
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
- ## Theme System
136
+ ```bash
137
+ cp node_modules/@castui/cast-ui/dist/default.reference.json ./my-brand-theme.json
138
+ ```
143
139
 
144
- ### ThemeProvider
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
- Wrap your app in `CastThemeProvider`. Defaults to White Label:
167
+ ### 3. Create the theme and provide it
147
168
 
148
169
  ```tsx
149
- import { CastThemeProvider, consumer } from '@castui/cast-ui';
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={consumer}>
154
- {/* components here */}
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 'white-label' | 'consumer' | 'corporate' | 'luxury'
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
- Load fonts via a `<link>` tag or use the helper:
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('luxury');
262
- // "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;700&family=Cormorant+Garamond:wght@400;500;700&display=swap"
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 **White Label** theme uses `system-ui` (platform default) and requires no font loading.
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
- whiteLabel,
330
- consumer,
331
- corporate,
332
- luxury,
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
- ### Theme Switcher
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 objects.
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 each `*.tokens.json` file
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 TypeScript files to `src/tokens/generated/`
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 any `design-tokens/*.tokens.json` file. The script runs automatically before Storybook and library builds.
423
+ **When to re-run:** After updating `design-tokens/Default.tokens.json`. The script runs automatically before Storybook and library builds.
362
424
 
363
- **Adding a new theme:** Add a new `.tokens.json` file to `design-tokens/`, add an entry to the `THEMES` array in `src/tokens/build.ts`, add the theme name to the `ThemeName` union in `src/theme/types.ts`, and update the toolbar items in `.storybook/preview.ts`.
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 all four `*.tokens.json` files and update `src/theme/types.ts`
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.1.0` → `0.1.1`)
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.1.0` → `0.1.1` |
467
- | New component or feature | Minor | `0.1.0` → `0.2.0` |
468
- | Breaking API change | Major | `0.1.0` → `1.0.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 { THEME_FONT_FAMILIES, googleFontsUrl, resolveFont, ANDROID_WEIGHT_SUFFIX } from './theme';
5
- export { whiteLabel, consumer, corporate, luxury, } from './tokens/generated';
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';
@@ -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,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGlG,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,MAAM,GACP,MAAM,oBAAoB,CAAC;AAG5B,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"}
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 { THEME_FONT_FAMILIES, googleFontsUrl, resolveFont, ANDROID_WEIGHT_SUFFIX } from './theme';
6
+ export { createTheme } from './theme';
7
+ export { getThemeFontFamilies, googleFontsUrl, resolveFont, ANDROID_WEIGHT_SUFFIX } from './theme';
7
8
  // Theme objects
8
- export { whiteLabel, consumer, corporate, luxury, } from './tokens/generated';
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,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAElG,gBAAgB;AAChB,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,MAAM,GACP,MAAM,oBAAoB,CAAC;AAE5B,aAAa;AACb,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC"}
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 White Label. */
4
+ /** The theme object to provide. Defaults to the Default base theme. */
5
5
  theme?: CastTheme;
6
- children: React.ReactNode;
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 { consumer } from '@castui/cast-ui/tokens/generated';
12
+ * import { CastThemeProvider, createTheme } from '@castui/cast-ui';
13
+ * import overrides from './my-brand.json';
14
14
  *
15
- * <CastThemeProvider theme={consumer}>
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,4DAA4D;IAC5D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAkB,EAClB,QAAQ,GACT,EAAE,sBAAsB,2CAIxB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,IAAI,SAAS,CAEpC"}
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 { whiteLabel } from '../tokens/generated';
3
+ import { defaultTheme } from '../tokens/generated';
4
4
  // ---------------------------------------------------------------------------
5
5
  // Context
6
6
  // ---------------------------------------------------------------------------
7
- const ThemeContext = createContext(whiteLabel);
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 { consumer } from '@castui/cast-ui/tokens/generated';
12
+ * import { CastThemeProvider, createTheme } from '@castui/cast-ui';
13
+ * import overrides from './my-brand.json';
14
14
  *
15
- * <CastThemeProvider theme={consumer}>
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 = whiteLabel, children, }) {
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,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,YAAY,GAAG,aAAa,CAAY,UAAU,CAAC,CAAC;AAY1D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,KAAK,GAAG,UAAU,EAClB,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"}
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"}