@castui/cast-ui 0.1.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +352 -0
  3. package/dist/components/Button/Button.d.ts +18 -0
  4. package/dist/components/Button/Button.d.ts.map +1 -0
  5. package/dist/components/Button/Button.js +74 -0
  6. package/dist/components/Button/Button.js.map +1 -0
  7. package/dist/components/Card/Card.d.ts +18 -0
  8. package/dist/components/Card/Card.d.ts.map +1 -0
  9. package/dist/components/Card/Card.js +53 -0
  10. package/dist/components/Card/Card.js.map +1 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +11 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/theme/ThemeProvider.d.ts +32 -0
  16. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  17. package/dist/theme/ThemeProvider.js +39 -0
  18. package/dist/theme/ThemeProvider.js.map +1 -0
  19. package/dist/theme/fonts.d.ts +33 -0
  20. package/dist/theme/fonts.d.ts.map +1 -0
  21. package/dist/theme/fonts.js +45 -0
  22. package/dist/theme/fonts.js.map +1 -0
  23. package/dist/theme/index.d.ts +5 -0
  24. package/dist/theme/index.d.ts.map +1 -0
  25. package/dist/theme/index.js +3 -0
  26. package/dist/theme/index.js.map +1 -0
  27. package/dist/theme/types.d.ts +150 -0
  28. package/dist/theme/types.d.ts.map +1 -0
  29. package/dist/theme/types.js +11 -0
  30. package/dist/theme/types.js.map +1 -0
  31. package/dist/tokens/generated/consumer.d.ts +3 -0
  32. package/dist/tokens/generated/consumer.d.ts.map +1 -0
  33. package/dist/tokens/generated/consumer.js +126 -0
  34. package/dist/tokens/generated/consumer.js.map +1 -0
  35. package/dist/tokens/generated/corporate.d.ts +3 -0
  36. package/dist/tokens/generated/corporate.d.ts.map +1 -0
  37. package/dist/tokens/generated/corporate.js +126 -0
  38. package/dist/tokens/generated/corporate.js.map +1 -0
  39. package/dist/tokens/generated/index.d.ts +6 -0
  40. package/dist/tokens/generated/index.d.ts.map +1 -0
  41. package/dist/tokens/generated/index.js +5 -0
  42. package/dist/tokens/generated/index.js.map +1 -0
  43. package/dist/tokens/generated/luxury.d.ts +3 -0
  44. package/dist/tokens/generated/luxury.d.ts.map +1 -0
  45. package/dist/tokens/generated/luxury.js +126 -0
  46. package/dist/tokens/generated/luxury.js.map +1 -0
  47. package/dist/tokens/generated/white-label.d.ts +3 -0
  48. package/dist/tokens/generated/white-label.d.ts.map +1 -0
  49. package/dist/tokens/generated/white-label.js +126 -0
  50. package/dist/tokens/generated/white-label.js.map +1 -0
  51. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cast UI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,352 @@
1
+ # Cast UI
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.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ Figma Variables (JSON)
9
+ |
10
+ Token Build Script src/tokens/build.ts
11
+ |
12
+ TypeScript Theme Objects src/tokens/generated/*.ts
13
+ |
14
+ ThemeProvider React Context (src/theme/)
15
+ |
16
+ RN Components Pressable, View, Text (src/components/)
17
+ |
18
+ +-----------+-----------+
19
+ | | |
20
+ iOS Android Web (via React Native Web)
21
+ ```
22
+
23
+ **Token tiers** follow a three-layer alias chain. Changing a value at any tier cascades automatically:
24
+
25
+ ```
26
+ Primitive --> Semantic --> Component
27
+
28
+ Example:
29
+ Primitive.Colour.Blue-600
30
+ --> Semantic.Colour.Primary
31
+ --> Component.Button.Filled.Background
32
+ ```
33
+
34
+ See [`design-tokens/DESIGN-TOKENS-SUMMARY.md`](design-tokens/DESIGN-TOKENS-SUMMARY.md) for the full token reference.
35
+
36
+ ## Project Structure
37
+
38
+ ```
39
+ cast-ui/
40
+ src/
41
+ components/
42
+ Button/
43
+ Button.tsx RN Pressable + Text, theme-aware
44
+ Button.stories.tsx Storybook stories
45
+ theme/
46
+ types.ts CastTheme TypeScript interface
47
+ ThemeProvider.tsx React Context provider + useTheme hook
48
+ fonts.ts Per-theme font family helpers
49
+ index.ts Barrel export
50
+ tokens/
51
+ build.ts Reads Figma JSON, generates TS theme objects
52
+ generated/ Auto-generated (gitignored)
53
+ white-label.ts
54
+ consumer.ts
55
+ corporate.ts
56
+ luxury.ts
57
+ index.ts
58
+ index.ts Public API
59
+ design-tokens/ Source of truth (Figma export)
60
+ White label.tokens.json Default theme (system-ui, slate neutrals)
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
64
+ DESIGN-TOKENS-SUMMARY.md Complete token reference
65
+ .storybook/
66
+ main.ts Webpack config with react-native-web alias
67
+ preview.ts Theme switcher toolbar + decorator
68
+ preview-head.html Google Fonts <link> tags
69
+ .github/workflows/
70
+ chromatic.yml Visual regression testing on push
71
+ dist/ Build output (gitignored)
72
+ tsconfig.json Development TypeScript config
73
+ tsconfig.build.json Library build config (excludes stories)
74
+ ```
75
+
76
+ ## Getting Started
77
+
78
+ ### Prerequisites
79
+
80
+ - Node.js >= 18
81
+ - npm
82
+
83
+ ### Install Dependencies
84
+
85
+ ```bash
86
+ npm install
87
+ ```
88
+
89
+ ### Build Tokens
90
+
91
+ Generates TypeScript theme objects from the Figma JSON files in `design-tokens/`:
92
+
93
+ ```bash
94
+ npm run build:tokens
95
+ ```
96
+
97
+ This writes to `src/tokens/generated/` (gitignored). Runs automatically before Storybook and library builds.
98
+
99
+ ### Start Storybook
100
+
101
+ ```bash
102
+ npm run storybook
103
+ ```
104
+
105
+ Opens at `http://localhost:6006`. Use the paintbrush icon in the toolbar to switch between all four themes.
106
+
107
+ ## Scripts
108
+
109
+ | Script | Description |
110
+ |--------|-------------|
111
+ | `npm run build:tokens` | Generate TypeScript theme files from Figma token JSON |
112
+ | `npm run storybook` | Start Storybook dev server (auto-runs `build:tokens`) |
113
+ | `npm run build-storybook` | Build static Storybook (auto-runs `build:tokens`) |
114
+ | `npm run build` | Full library build: tokens + TypeScript compilation to `dist/` |
115
+ | `npm publish` | Publish to npm (auto-runs `build` via `prepublishOnly`) |
116
+
117
+ ## Themes
118
+
119
+ Four themes share the same component API but produce completely different visual identities:
120
+
121
+ | Theme | Primary Colour | Typography | Border Radius | Character |
122
+ |-------|---------------|------------|---------------|-----------|
123
+ | **White Label** (default) | Slate-900 | system-ui | Moderate (8px buttons) | Neutral, adaptable |
124
+ | **Consumer** | Violet-600 | Poppins | Rounded (24px pill buttons) | Vibrant, friendly |
125
+ | **Corporate** | Blue-600 | Merriweather + Inter | Crisp (4px buttons) | Professional, structured |
126
+ | **Luxury** | Gold-400 on Black | Playfair Display + Cormorant Garamond | Zero (sharp edges) | Premium, elegant |
127
+
128
+ 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.
129
+
130
+ ## Theme System
131
+
132
+ ### ThemeProvider
133
+
134
+ Wrap your app in `CastThemeProvider`. Defaults to White Label:
135
+
136
+ ```tsx
137
+ import { CastThemeProvider, consumer } from '@castui/cast-ui';
138
+
139
+ export default function App() {
140
+ return (
141
+ <CastThemeProvider theme={consumer}>
142
+ {/* components here */}
143
+ </CastThemeProvider>
144
+ );
145
+ }
146
+ ```
147
+
148
+ ### useTheme
149
+
150
+ Access the current theme inside any component:
151
+
152
+ ```tsx
153
+ import { useTheme } from '@castui/cast-ui';
154
+
155
+ function MyComponent() {
156
+ const theme = useTheme();
157
+
158
+ return (
159
+ <View style={{ backgroundColor: theme.semantic.color.surface }}>
160
+ <Text style={{
161
+ color: theme.semantic.color.onSurface,
162
+ fontSize: theme.semantic.fontSize.body,
163
+ }}>
164
+ Themed text
165
+ </Text>
166
+ </View>
167
+ );
168
+ }
169
+ ```
170
+
171
+ ### Theme Object Shape
172
+
173
+ Every theme conforms to the `CastTheme` interface (see `src/theme/types.ts`):
174
+
175
+ ```
176
+ theme.name 'white-label' | 'consumer' | 'corporate' | 'luxury'
177
+ theme.semantic.color.* 30 semantic colours (surface, primary, error, etc.)
178
+ theme.semantic.fontFamily.* brand, interface, data
179
+ theme.semantic.fontSize.* display, h1, h2, h3, body, small, button
180
+ theme.semantic.fontWeight.* heading, body, button
181
+ theme.semantic.lineHeight.* heading, body, uiLabel
182
+ theme.semantic.letterSpacing.* heading, body, label
183
+ theme.semantic.paragraphSpacing.* body, editorial
184
+ theme.semantic.paragraphIndent.* editorial
185
+ theme.semantic.borderRadius.* small, medium, large
186
+ theme.component.button.* All button tokens (padding, colours, variants, states)
187
+ ```
188
+
189
+ ## Components
190
+
191
+ ### Button
192
+
193
+ React Native `Pressable` + `Text`. Consumes all tokens from `theme.component.button`.
194
+
195
+ ```tsx
196
+ import { Button } from '@castui/cast-ui';
197
+
198
+ <Button label="Get started" variant="filled" />
199
+ <Button label="Learn more" variant="outline" />
200
+ <Button label="Cancel" variant="text" disabled />
201
+ ```
202
+
203
+ | Prop | Type | Default | Description |
204
+ |------|------|---------|-------------|
205
+ | `label` | `string` | required | Button text |
206
+ | `variant` | `'filled' \| 'outline' \| 'text'` | `'filled'` | Visual variant |
207
+ | `disabled` | `boolean` | `false` | Disabled state |
208
+ | `backgroundColor` | `string` | - | Override background colour |
209
+
210
+ ## Font Handling
211
+
212
+ Components reference font families from the theme tokens. Font **loading** is the consumer's responsibility.
213
+
214
+ ### Web
215
+
216
+ Load fonts via a `<link>` tag or use the helper:
217
+
218
+ ```ts
219
+ import { googleFontsUrl } from '@castui/cast-ui';
220
+
221
+ const url = googleFontsUrl('luxury');
222
+ // "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;700&family=Cormorant+Garamond:wght@400;500;700&display=swap"
223
+ ```
224
+
225
+ ### React Native / Expo
226
+
227
+ Load fonts with `expo-font` before rendering:
228
+
229
+ ```ts
230
+ import { useFonts } from 'expo-font';
231
+ import { THEME_FONT_FAMILIES } from '@castui/cast-ui';
232
+ // THEME_FONT_FAMILIES.luxury = ['Playfair Display', 'Cormorant Garamond']
233
+ ```
234
+
235
+ The **White Label** theme uses `system-ui` (platform default) and requires no font loading.
236
+
237
+ | Theme | Fonts to Load |
238
+ |-------|---------------|
239
+ | White Label | None (system default) |
240
+ | Consumer | Poppins |
241
+ | Corporate | Inter, Merriweather |
242
+ | Luxury | Playfair Display, Cormorant Garamond |
243
+
244
+ ## Consumer Installation
245
+
246
+ ```bash
247
+ npm install @castui/cast-ui
248
+ ```
249
+
250
+ Peer dependencies: `react` (>=18), `react-native` (>=0.72).
251
+
252
+ ```tsx
253
+ import {
254
+ CastThemeProvider,
255
+ useTheme,
256
+ Button,
257
+ whiteLabel,
258
+ consumer,
259
+ corporate,
260
+ luxury,
261
+ } from '@castui/cast-ui';
262
+ ```
263
+
264
+ ## Storybook
265
+
266
+ 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`.
267
+
268
+ ### Theme Switcher
269
+
270
+ 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`.
271
+
272
+ ### Chromatic
273
+
274
+ Visual regression testing runs on every push via the GitHub Actions workflow at `.github/workflows/chromatic.yml`. Requires a `CHROMATIC_PROJECT_TOKEN` repository secret.
275
+
276
+ ## Token Build Pipeline
277
+
278
+ The build script (`src/tokens/build.ts`) reads Figma-exported JSON from `design-tokens/` and generates fully-resolved TypeScript theme objects.
279
+
280
+ **What it does:**
281
+
282
+ 1. Reads each `*.tokens.json` file
283
+ 2. Recursively resolves all `{Primitive.Colour.Slate-900}` style alias references through the three-tier chain
284
+ 3. Extracts hex values from Figma's colour object format (`{ colorSpace, components, hex }`)
285
+ 4. Outputs typed TypeScript files to `src/tokens/generated/`
286
+
287
+ **When to re-run:** After updating any `design-tokens/*.tokens.json` file. The script runs automatically before Storybook and library builds.
288
+
289
+ **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`.
290
+
291
+ ## Adding a New Component
292
+
293
+ 1. Create `src/components/ComponentName/ComponentName.tsx`
294
+ 2. Import `useTheme` and consume tokens from the theme object
295
+ 3. Use only React Native primitives (`View`, `Text`, `Pressable`, `ScrollView`, etc.)
296
+ 4. Create `ComponentName.stories.tsx` alongside the component
297
+ 5. Export the component and its types from `src/index.ts`
298
+ 6. If the component needs new design tokens, add them to all four `*.tokens.json` files and update `src/theme/types.ts`
299
+
300
+ ## npm Publishing
301
+
302
+ The package is configured for public npm publishing:
303
+
304
+ - **Entry point:** `dist/index.js` (CJS) with `dist/index.d.ts` type declarations
305
+ - **Included files:** `dist/`, `README.md`, `LICENSE`
306
+ - **Peer dependencies:** `react` (>=18), `react-native` (>=0.72)
307
+ - **License:** MIT
308
+
309
+ ```bash
310
+ npm login
311
+ npm publish
312
+ ```
313
+
314
+ The `prepublishOnly` hook runs the full build automatically.
315
+
316
+ ## Security
317
+
318
+ This repository uses a **whitelist-based `.gitignore`**. Everything is ignored by default (`*`), and only explicitly allowed paths are tracked. This prevents accidental exposure of secrets, logs, or environment files.
319
+
320
+ **Never tracked:** `.env`, `.env.*`, `*.log`, `*.local`, `.DS_Store`, `dist/`, `src/tokens/generated/`, `storybook-static/`.
321
+
322
+ When adding new top-level files or directories, you must add a `!path` entry to `.gitignore` for them to be tracked by git.
323
+
324
+ ## CI/CD
325
+
326
+ | Workflow | Trigger | Purpose |
327
+ |----------|---------|---------|
328
+ | Chromatic (`.github/workflows/chromatic.yml`) | Every push | Visual regression testing via Storybook snapshots |
329
+
330
+ **Required secrets:** `CHROMATIC_PROJECT_TOKEN` (repository secret).
331
+
332
+ ## Dependencies
333
+
334
+ ### Runtime (peer)
335
+
336
+ | Package | Version | Purpose |
337
+ |---------|---------|---------|
338
+ | `react` | >=18 | React core |
339
+ | `react-native` | >=0.72 | Cross-platform UI primitives |
340
+
341
+ ### Development only
342
+
343
+ | Package | Purpose |
344
+ |---------|---------|
345
+ | `react-native-web` | Renders RN components in browser for Storybook |
346
+ | `@storybook/react-webpack5` | Storybook framework |
347
+ | `chromatic` | Visual regression testing |
348
+ | `style-dictionary` | Installed for future token transforms (current build uses custom script) |
349
+ | `ts-node` | Runs the TypeScript token build script |
350
+ | `typescript` | Type checking and compilation |
351
+
352
+ None of the dev dependencies ship to consumers.
@@ -0,0 +1,18 @@
1
+ import { type PressableProps } from 'react-native';
2
+ export type ButtonVariant = 'filled' | 'outline' | 'text';
3
+ export interface ButtonProps extends Omit<PressableProps, 'style'> {
4
+ /** Button label text. */
5
+ label: string;
6
+ /** Visual variant. @default 'filled' */
7
+ variant?: ButtonVariant;
8
+ /** Override background color. */
9
+ backgroundColor?: string;
10
+ }
11
+ /**
12
+ * Primary UI component for user interaction.
13
+ *
14
+ * Renders as a React Native `Pressable` with `Text` – works identically
15
+ * on iOS, Android, and Web (via React Native Web).
16
+ */
17
+ export declare function Button({ label, variant, backgroundColor, disabled, ...pressableProps }: ButtonProps): import("react/jsx-runtime").JSX.Element;
18
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AACA,OAAO,EAML,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,2CA0Eb"}
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Pressable, Text, } from 'react-native';
4
+ import { useTheme } from '../../theme';
5
+ // ---------------------------------------------------------------------------
6
+ // Component
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * Primary UI component for user interaction.
10
+ *
11
+ * Renders as a React Native `Pressable` with `Text` – works identically
12
+ * on iOS, Android, and Web (via React Native Web).
13
+ */
14
+ export function Button({ label, variant = 'filled', backgroundColor, disabled = false, ...pressableProps }) {
15
+ const theme = useTheme();
16
+ const bt = theme.component.button;
17
+ const [hovered, setHovered] = useState(false);
18
+ // --- resolve colours per variant + state -----------------------------------
19
+ const resolveBackground = () => {
20
+ if (disabled)
21
+ return bt.state.disabledBackground;
22
+ if (backgroundColor)
23
+ return backgroundColor;
24
+ const variantTokens = bt[variant];
25
+ const base = variantTokens.background;
26
+ if (hovered)
27
+ return bt.state.hoverBackground;
28
+ return base;
29
+ };
30
+ const resolveContent = () => {
31
+ if (disabled)
32
+ return bt.state.disabledContent;
33
+ return bt[variant].content;
34
+ };
35
+ const resolveBorder = () => {
36
+ if (variant !== 'outline')
37
+ return undefined;
38
+ if (disabled)
39
+ return bt.state.disabledContent;
40
+ return bt.outline.border;
41
+ };
42
+ // --- build styles ----------------------------------------------------------
43
+ const containerStyle = {
44
+ flexDirection: 'row',
45
+ alignItems: 'center',
46
+ justifyContent: 'center',
47
+ gap: bt.gap,
48
+ paddingHorizontal: bt.paddingHorizontal,
49
+ paddingVertical: bt.paddingVertical,
50
+ borderRadius: bt.cornerRadius,
51
+ backgroundColor: resolveBackground(),
52
+ ...(variant === 'outline' && {
53
+ borderWidth: bt.borderWidth,
54
+ borderColor: resolveBorder(),
55
+ }),
56
+ ...(variant === 'text' && {
57
+ backgroundColor: 'transparent',
58
+ }),
59
+ opacity: disabled ? 0.6 : 1,
60
+ };
61
+ const fontFamily = bt.fontFamily === 'system-ui' ? undefined : bt.fontFamily;
62
+ const textStyle = {
63
+ color: resolveContent(),
64
+ fontSize: bt.textSize,
65
+ fontWeight: String(bt.fontWeight),
66
+ lineHeight: bt.textSize * bt.lineHeight,
67
+ ...(fontFamily ? { fontFamily } : {}),
68
+ };
69
+ return (_jsx(Pressable, { ...pressableProps, disabled: disabled, style: containerStyle, ...{
70
+ onHoverIn: () => setHovered(true),
71
+ onHoverOut: () => setHovered(false),
72
+ }, accessibilityRole: "button", children: _jsx(Text, { style: textStyle, children: label }) }));
73
+ }
74
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { type ViewProps } from 'react-native';
3
+ export interface CardProps extends Omit<ViewProps, 'style'> {
4
+ /** Card title text. */
5
+ heading?: string;
6
+ /** Card body text. */
7
+ body?: string;
8
+ /** Override card content with arbitrary children. */
9
+ children?: React.ReactNode;
10
+ }
11
+ /**
12
+ * Themed container for grouping related content.
13
+ *
14
+ * Renders as a React Native `View` – works identically on iOS, Android,
15
+ * and Web (via React Native Web).
16
+ */
17
+ export declare function Card({ heading, body, children, ...viewProps }: CardProps): import("react/jsx-runtime").JSX.Element;
18
+ //# sourceMappingURL=Card.d.ts.map
@@ -0,0 +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,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAMD;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAE,EAAE,SAAS,2CAqDxE"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { View, Text, } from 'react-native';
3
+ import { useTheme } from '../../theme';
4
+ // ---------------------------------------------------------------------------
5
+ // Component
6
+ // ---------------------------------------------------------------------------
7
+ /**
8
+ * Themed container for grouping related content.
9
+ *
10
+ * Renders as a React Native `View` – works identically on iOS, Android,
11
+ * and Web (via React Native Web).
12
+ */
13
+ export function Card({ heading, body, children, ...viewProps }) {
14
+ const theme = useTheme();
15
+ const ct = theme.component.card;
16
+ // --- container styles ------------------------------------------------------
17
+ const containerStyle = {
18
+ padding: ct.padding,
19
+ gap: ct.gap,
20
+ backgroundColor: ct.background,
21
+ borderRadius: ct.cornerRadius,
22
+ borderWidth: ct.strokeWidth,
23
+ borderColor: ct.stroke,
24
+ // Elevation / shadow
25
+ ...(ct.elevation > 0 && {
26
+ // iOS shadows
27
+ shadowColor: '#000',
28
+ shadowOffset: { width: 0, height: ct.elevation },
29
+ shadowOpacity: 0.08 * ct.elevation,
30
+ shadowRadius: ct.elevation * 2,
31
+ // Android elevation
32
+ elevation: ct.elevation,
33
+ }),
34
+ };
35
+ // --- typography styles -----------------------------------------------------
36
+ const headingFontFamily = ct.headingFontFamily === 'system-ui' ? undefined : ct.headingFontFamily;
37
+ const bodyFontFamily = ct.bodyFontFamily === 'system-ui' ? undefined : ct.bodyFontFamily;
38
+ const headingStyle = {
39
+ fontSize: ct.headingSize,
40
+ fontWeight: String(ct.headingWeight),
41
+ color: theme.semantic.color.onSurface,
42
+ ...(headingFontFamily ? { fontFamily: headingFontFamily } : {}),
43
+ };
44
+ const bodyStyle = {
45
+ fontSize: ct.bodySize,
46
+ fontWeight: String(ct.bodyWeight),
47
+ color: theme.semantic.color.onSurfaceMuted,
48
+ lineHeight: ct.bodySize * theme.semantic.lineHeight.body,
49
+ ...(bodyFontFamily ? { fontFamily: bodyFontFamily } : {}),
50
+ };
51
+ return (_jsxs(View, { ...viewProps, style: containerStyle, children: [heading != null && _jsx(Text, { style: headingStyle, children: heading }), body != null && _jsx(Text, { style: bodyStyle, children: body }), children] }));
52
+ }
53
+ //# sourceMappingURL=Card.js.map
@@ -0,0 +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;AAevC,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAa;IACvE,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC;IAEhC,8EAA8E;IAC9E,MAAM,cAAc,GAAc;QAChC,OAAO,EAAE,EAAE,CAAC,OAAO;QACnB,GAAG,EAAE,EAAE,CAAC,GAAG;QACX,eAAe,EAAE,EAAE,CAAC,UAAU;QAC9B,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,WAAW,EAAE,EAAE,CAAC,MAAM;QACtB,qBAAqB;QACrB,GAAG,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,IAAI;YACtB,cAAc;YACd,WAAW,EAAE,MAAM;YACnB,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,SAAS,EAAE;YAChD,aAAa,EAAE,IAAI,GAAG,EAAE,CAAC,SAAS;YAClC,YAAY,EAAE,EAAE,CAAC,SAAS,GAAG,CAAC;YAC9B,oBAAoB;YACpB,SAAS,EAAE,EAAE,CAAC,SAAS;SACxB,CAAC;KACH,CAAC;IAEF,8EAA8E;IAC9E,MAAM,iBAAiB,GACrB,EAAE,CAAC,iBAAiB,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC;IAE1E,MAAM,cAAc,GAClB,EAAE,CAAC,cAAc,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC;IAEpE,MAAM,YAAY,GAAc;QAC9B,QAAQ,EAAE,EAAE,CAAC,WAAW;QACxB,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,aAAa,CAA4B;QAC/D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS;QACrC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChE,CAAC;IAEF,MAAM,SAAS,GAAc;QAC3B,QAAQ,EAAE,EAAE,CAAC,QAAQ;QACrB,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,UAAU,CAA4B;QAC5D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc;QAC1C,UAAU,EAAE,EAAE,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;QACxD,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1D,CAAC;IAEF,OAAO,CACL,MAAC,IAAI,OAAK,SAAS,EAAE,KAAK,EAAE,cAAc,aACvC,OAAO,IAAI,IAAI,IAAI,KAAC,IAAI,IAAC,KAAK,EAAE,YAAY,YAAG,OAAO,GAAQ,EAC9D,IAAI,IAAI,IAAI,IAAI,KAAC,IAAI,IAAC,KAAK,EAAE,SAAS,YAAG,IAAI,GAAQ,EACrD,QAAQ,IACJ,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { CastThemeProvider, useTheme } from './theme';
2
+ export type { CastThemeProviderProps } from './theme';
3
+ export type { CastTheme, ThemeName, SemanticTokens, ComponentTokens, ButtonTokens, } from './theme';
4
+ export { THEME_FONT_FAMILIES, googleFontsUrl } from './theme';
5
+ export { whiteLabel, consumer, corporate, luxury, } from './tokens/generated';
6
+ export { Button } from './components/Button/Button';
7
+ export type { ButtonProps, ButtonVariant } from './components/Button/Button';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9D,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"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Cast Design System – Public API
3
+ // ---------------------------------------------------------------------------
4
+ // Theme system
5
+ export { CastThemeProvider, useTheme } from './theme';
6
+ export { THEME_FONT_FAMILIES, googleFontsUrl } from './theme';
7
+ // Theme objects
8
+ export { whiteLabel, consumer, corporate, luxury, } from './tokens/generated';
9
+ // Components
10
+ export { Button } from './components/Button/Button';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;AAStD,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9D,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"}
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import type { CastTheme } from './types';
3
+ export interface CastThemeProviderProps {
4
+ /** The theme object to provide. Defaults to White Label. */
5
+ theme?: CastTheme;
6
+ children: React.ReactNode;
7
+ }
8
+ /**
9
+ * Wraps the component tree with the selected Cast theme.
10
+ *
11
+ * ```tsx
12
+ * import { CastThemeProvider } from '@castui/cast-ui';
13
+ * import { consumer } from '@castui/cast-ui/tokens/generated';
14
+ *
15
+ * <CastThemeProvider theme={consumer}>
16
+ * <App />
17
+ * </CastThemeProvider>
18
+ * ```
19
+ */
20
+ export declare function CastThemeProvider({ theme, children, }: CastThemeProviderProps): import("react/jsx-runtime").JSX.Element;
21
+ /**
22
+ * Returns the current Cast theme object.
23
+ *
24
+ * Must be called inside an `<CastThemeProvider>`.
25
+ *
26
+ * ```tsx
27
+ * const theme = useTheme();
28
+ * <View style={{ backgroundColor: theme.semantic.color.surface }} />
29
+ * ```
30
+ */
31
+ export declare function useTheme(): CastTheme;
32
+ //# sourceMappingURL=ThemeProvider.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from 'react';
3
+ import { whiteLabel } from '../tokens/generated';
4
+ // ---------------------------------------------------------------------------
5
+ // Context
6
+ // ---------------------------------------------------------------------------
7
+ const ThemeContext = createContext(whiteLabel);
8
+ /**
9
+ * Wraps the component tree with the selected Cast theme.
10
+ *
11
+ * ```tsx
12
+ * import { CastThemeProvider } from '@castui/cast-ui';
13
+ * import { consumer } from '@castui/cast-ui/tokens/generated';
14
+ *
15
+ * <CastThemeProvider theme={consumer}>
16
+ * <App />
17
+ * </CastThemeProvider>
18
+ * ```
19
+ */
20
+ export function CastThemeProvider({ theme = whiteLabel, children, }) {
21
+ return (_jsx(ThemeContext.Provider, { value: theme, children: children }));
22
+ }
23
+ // ---------------------------------------------------------------------------
24
+ // Hook
25
+ // ---------------------------------------------------------------------------
26
+ /**
27
+ * Returns the current Cast theme object.
28
+ *
29
+ * Must be called inside an `<CastThemeProvider>`.
30
+ *
31
+ * ```tsx
32
+ * const theme = useTheme();
33
+ * <View style={{ backgroundColor: theme.semantic.color.surface }} />
34
+ * ```
35
+ */
36
+ export function useTheme() {
37
+ return useContext(ThemeContext);
38
+ }
39
+ //# sourceMappingURL=ThemeProvider.js.map
@@ -0,0 +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"}