create-proto 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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +104 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/copy-template.d.ts +8 -0
  8. package/dist/copy-template.d.ts.map +1 -0
  9. package/dist/copy-template.js +46 -0
  10. package/dist/copy-template.js.map +1 -0
  11. package/dist/detect-pm.d.ts +3 -0
  12. package/dist/detect-pm.d.ts.map +1 -0
  13. package/dist/detect-pm.js +12 -0
  14. package/dist/detect-pm.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +7 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/install-deps.d.ts +16 -0
  20. package/dist/install-deps.d.ts.map +1 -0
  21. package/dist/install-deps.js +37 -0
  22. package/dist/install-deps.js.map +1 -0
  23. package/dist/messages.d.ts +17 -0
  24. package/dist/messages.d.ts.map +1 -0
  25. package/dist/messages.js +16 -0
  26. package/dist/messages.js.map +1 -0
  27. package/dist/render-qr.d.ts +2 -0
  28. package/dist/render-qr.d.ts.map +1 -0
  29. package/dist/render-qr.js +9 -0
  30. package/dist/render-qr.js.map +1 -0
  31. package/dist/validate-name.d.ts +9 -0
  32. package/dist/validate-name.d.ts.map +1 -0
  33. package/dist/validate-name.js +33 -0
  34. package/dist/validate-name.js.map +1 -0
  35. package/package.json +64 -0
  36. package/template/.proto/app/(proto)/[...screen].tsx +24 -0
  37. package/template/.proto/app/_layout.tsx +5 -0
  38. package/template/.proto/expo-config/app.json +17 -0
  39. package/template/CLAUDE.md +71 -0
  40. package/template/DESIGN.md +53 -0
  41. package/template/README.md +6 -0
  42. package/template/app/index.tsx +5 -0
  43. package/template/app.config.js +1 -0
  44. package/template/assets/.gitkeep +0 -0
  45. package/template/assets/icon.png +0 -0
  46. package/template/assets/splash.png +0 -0
  47. package/template/babel.config.js +7 -0
  48. package/template/components/proto/.gitkeep +0 -0
  49. package/template/components/proto/Button.tsx +61 -0
  50. package/template/components/proto/Card.tsx +63 -0
  51. package/template/components/proto/Divider.tsx +15 -0
  52. package/template/components/proto/Modal.tsx +43 -0
  53. package/template/components/proto/Row.tsx +28 -0
  54. package/template/components/proto/Screen.tsx +38 -0
  55. package/template/components/proto/Stack.tsx +17 -0
  56. package/template/components/proto/Text.tsx +37 -0
  57. package/template/components/proto/Toggle.tsx +40 -0
  58. package/template/components/proto/index.ts +11 -0
  59. package/template/components/proto/tokens/liquidGlass.ts +38 -0
  60. package/template/components/proto/tokens/materialYou.ts +38 -0
  61. package/template/components/proto/types.ts +55 -0
  62. package/template/components/proto/useTheme.ts +35 -0
  63. package/template/components/shared/.gitkeep +0 -0
  64. package/template/metro.config.js +5 -0
  65. package/template/package.json +35 -0
  66. package/template/pnpm-workspace.yaml +1 -0
  67. package/template/proto.config.js +6 -0
  68. package/template/screens/.gitkeep +0 -0
  69. package/template/screens/Home.tsx +60 -0
@@ -0,0 +1,71 @@
1
+ # Proto Project — Claude Code Instructions
2
+
3
+ You are the design tool inside a Proto project. The iOS Simulator is the canvas. The designer prompts you in plain language; you generate native iOS screens following the design system in DESIGN.md. Designers never touch files.
4
+
5
+ ## Three rules
6
+
7
+ **1. Native iOS first.** Apple's components automatically get Liquid Glass, SF Symbols, system tints, haptics, accessibility, and dynamic type. Always prefer them when they exist:
8
+
9
+ | Need | Use |
10
+ |---|---|
11
+ | Tab bar | `expo-router/unstable-native-tabs` (`NativeTabs` + `Icon sf={{default, selected}}` in `app/_layout.tsx`) |
12
+ | SF Symbol icon | `expo-symbols` `SymbolView` |
13
+ | System button | `@expo/ui/swift-ui` `Button` |
14
+ | System toggle | `@expo/ui/swift-ui` `Toggle` |
15
+ | Form / settings list | `@expo/ui/swift-ui` `Form` + `Section` |
16
+ | Liquid Glass surface | `expo-glass-effect` `GlassView` directly |
17
+
18
+ Never wrap a native component just to add Proto branding. Native > custom.
19
+
20
+ **2. Proto primitives are fallbacks for what native doesn't ship.** Use `/components/proto` for layout helpers, generic surfaces, themed text — never to rebuild Apple-native UI.
21
+
22
+ **3. DESIGN.md is the only source of design tokens.** Read it before every change. Never hardcode colour, spacing, radius, or typography. If the designer asks to change tokens, update DESIGN.md.
23
+
24
+ If DESIGN.md's "Component Library" section names a third-party library (Tamagui, Gluestack, etc.), use that library's components first, Proto primitives as fallback. Otherwise use Proto primitives only.
25
+
26
+ ## File layout
27
+
28
+ ```
29
+ /app/<route>.tsx thin re-export of a screen (one-line wrapper)
30
+ /app/_layout.tsx NativeTabs root layout (when app has tabs)
31
+ /screens/<Name>.tsx actual screen component (PascalCase, default export)
32
+ /components/shared/ designer-created shared components
33
+ /components/proto/ Proto primitives — read-only, do not edit
34
+ ```
35
+
36
+ For a new screen `screens/Settings.tsx`, add a matching `app/settings.tsx`:
37
+
38
+ ```tsx
39
+ import Settings from '../screens/Settings';
40
+ export default function SettingsRoute() { return <Settings />; }
41
+ ```
42
+
43
+ Route filenames are lowercase kebab-case. Then add a one-line description to the Screens section of DESIGN.md.
44
+
45
+ ## Proto primitives (`/components/proto`)
46
+
47
+ ```
48
+ Screen title?, scrollable? SafeAreaView + ScrollView wrapper
49
+ Stack gap?, padding? vertical flex
50
+ Row gap?, align? horizontal flex
51
+ Text size, color, style? themed RN Text (sizes: title/headline/body/caption/label)
52
+ Card glass?, padding? surface; glass={true} = real Liquid Glass on iOS 26+
53
+ Button label, variant?, onPress custom animated button — for iOS system style use @expo/ui Button
54
+ Toggle label, value, onChange themed RN Switch — for iOS system look use @expo/ui Toggle
55
+ Divider — 1px separator
56
+ Modal title?, visible, ... RN Modal wrapper
57
+ ```
58
+
59
+ ## When modifying a screen
60
+
61
+ Read the file first, then rewrite the full file. Never partial edits or diffs.
62
+
63
+ ## Never
64
+
65
+ - Never import from `react-native` directly — use a library, native iOS, or Proto fallback
66
+ - Never build a custom tab bar — always `expo-router/unstable-native-tabs`
67
+ - Never put logic in `/app/` files — they re-export a screen, nothing else
68
+ - Never use SF Symbol private-use Unicode codepoints (like `''`) as text — they don't render in plain Text. Use `expo-symbols` `SymbolView` or native components that take SF symbol names
69
+ - Never edit `/components/proto/`, `.proto/`, `app.config.js`, `babel.config.js`, `metro.config.js`
70
+ - Never add a build step, dependency, or visual editor
71
+ - Never tell the designer to open or edit a file manually
@@ -0,0 +1,53 @@
1
+ # DESIGN.md
2
+ > Source of truth for {{APP_NAME}}'s design system.
3
+ > Update by prompting Claude Code: "update DESIGN.md, [what to change]"
4
+ > Last updated: {{DATE}}
5
+
6
+ ## App
7
+ - Name: {{APP_NAME}}
8
+ - Theme: liquidGlass
9
+ - Platform: iOS
10
+
11
+ ## Component Library
12
+ - Package: proto (built-in)
13
+ - Import from: ../components/proto
14
+ - Fallback: proto
15
+
16
+ ## Colour
17
+ - Accent: #007AFF
18
+ - Surface primary: rgba(255,255,255,0.72)
19
+ - Surface secondary: rgba(255,255,255,0.48)
20
+ - Surface card: rgba(255,255,255,0.60)
21
+ - Surface nav: rgba(255,255,255,0.82)
22
+ - Text primary: #000000
23
+ - Text secondary: rgba(0,0,0,0.5)
24
+ - Text tertiary: rgba(0,0,0,0.3)
25
+ - Destructive: #FF3B30
26
+
27
+ ## Typography
28
+ - Title: 34px / bold / tracking -0.4
29
+ - Headline: 22px / semibold / tracking -0.4
30
+ - Body: 17px / regular
31
+ - Caption: 12px / regular / text-secondary
32
+ - Label: 13px / medium
33
+
34
+ ## Spacing
35
+ - xs: 4 / sm: 8 / md: 16 / lg: 24 / xl: 32
36
+
37
+ ## Shape
38
+ - Card radius: 22
39
+ - Button radius: 14
40
+ - Modal radius: 44
41
+ - Input radius: 12
42
+
43
+ ## Effects
44
+ - Card blur: 20
45
+ - Nav blur: 40
46
+ - Modal blur: 60
47
+ - Border: rgba(255,255,255,0.4)
48
+
49
+ ## Components in use
50
+ - Screen, Stack, Row, Text, Card, Button, Toggle, Nav, Modal, Divider
51
+
52
+ ## Screens
53
+ - Home (initial) — starter screen
@@ -0,0 +1,6 @@
1
+ # {{name}}
2
+
3
+ Built with Proto.
4
+
5
+ Run `proto start` to preview on your phone.
6
+ Run `proto add "describe a screen"` to generate a new screen.
@@ -0,0 +1,5 @@
1
+ import Home from '../screens/Home';
2
+
3
+ export default function Index() {
4
+ return <Home />;
5
+ }
@@ -0,0 +1 @@
1
+ module.exports = require('./.proto/expo-config/app.json');
File without changes
Binary file
Binary file
@@ -0,0 +1,7 @@
1
+ module.exports = function (api) {
2
+ api.cache(true);
3
+ return {
4
+ presets: ['babel-preset-expo'],
5
+ plugins: [require.resolve('react-native-worklets/plugin')],
6
+ };
7
+ };
File without changes
@@ -0,0 +1,61 @@
1
+ import { Pressable, type ViewStyle } from 'react-native';
2
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
3
+ import * as Haptics from 'expo-haptics';
4
+ import { useTheme, useAccent } from './useTheme';
5
+ import { Text } from './Text';
6
+
7
+ export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'destructive';
8
+
9
+ export type ButtonProps = {
10
+ label: string;
11
+ variant?: ButtonVariant;
12
+ onPress?: () => void;
13
+ };
14
+
15
+ export function Button({ label, variant = 'primary', onPress }: ButtonProps) {
16
+ const theme = useTheme();
17
+ const accent = useAccent();
18
+ const scale = useSharedValue(1);
19
+
20
+ const animated = useAnimatedStyle(() => ({
21
+ transform: [{ scale: scale.value }],
22
+ }));
23
+
24
+ const handlePressIn = () => {
25
+ scale.value = withTiming(0.96, { duration: 80 });
26
+ };
27
+ const handlePressOut = () => {
28
+ scale.value = withTiming(1, { duration: 120 });
29
+ };
30
+ const handlePress = () => {
31
+ Haptics.selectionAsync().catch(() => {});
32
+ onPress?.();
33
+ };
34
+
35
+ const palette: Record<ButtonVariant, { bg: string; fg: string }> = {
36
+ primary: { bg: accent, fg: '#FFFFFF' },
37
+ secondary: { bg: theme.surface.secondary, fg: theme.text.primary },
38
+ ghost: { bg: 'transparent', fg: accent },
39
+ destructive: { bg: theme.text.destructive, fg: '#FFFFFF' },
40
+ };
41
+ const { bg, fg } = palette[variant];
42
+
43
+ const baseStyle: ViewStyle = {
44
+ backgroundColor: bg,
45
+ borderRadius: theme.radius.button,
46
+ paddingVertical: theme.space.sm + 4,
47
+ paddingHorizontal: theme.space.md,
48
+ alignItems: 'center',
49
+ justifyContent: 'center',
50
+ };
51
+
52
+ return (
53
+ <Pressable onPressIn={handlePressIn} onPressOut={handlePressOut} onPress={handlePress}>
54
+ <Animated.View style={[baseStyle, animated]}>
55
+ <Text size="label" style={{ color: fg }}>
56
+ {label}
57
+ </Text>
58
+ </Animated.View>
59
+ </Pressable>
60
+ );
61
+ }
@@ -0,0 +1,63 @@
1
+ import { View } from 'react-native';
2
+ import { BlurView } from 'expo-blur';
3
+ import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
4
+ import type { ReactNode } from 'react';
5
+ import { useTheme } from './useTheme';
6
+
7
+ export type CardProps = {
8
+ glass?: boolean;
9
+ padding?: number;
10
+ children?: ReactNode;
11
+ };
12
+
13
+ export function Card({ glass = false, padding, children }: CardProps) {
14
+ const theme = useTheme();
15
+ const pad = padding ?? theme.space.md;
16
+
17
+ if (glass) {
18
+ if (isLiquidGlassAvailable()) {
19
+ return (
20
+ <GlassView
21
+ style={{
22
+ borderRadius: theme.radius.card,
23
+ borderWidth: 1,
24
+ borderColor: theme.border.default,
25
+ padding: pad,
26
+ overflow: 'hidden',
27
+ }}
28
+ >
29
+ {children}
30
+ </GlassView>
31
+ );
32
+ }
33
+ return (
34
+ <View
35
+ style={{
36
+ borderRadius: theme.radius.card,
37
+ overflow: 'hidden',
38
+ borderWidth: 1,
39
+ borderColor: theme.border.default,
40
+ backgroundColor: theme.surface.card,
41
+ }}
42
+ >
43
+ <BlurView intensity={theme.blur.card} tint="light" style={{ padding: pad }}>
44
+ {children}
45
+ </BlurView>
46
+ </View>
47
+ );
48
+ }
49
+
50
+ return (
51
+ <View
52
+ style={{
53
+ backgroundColor: theme.surface.card,
54
+ borderRadius: theme.radius.card,
55
+ borderWidth: 1,
56
+ borderColor: theme.border.default,
57
+ padding: pad,
58
+ }}
59
+ >
60
+ {children}
61
+ </View>
62
+ );
63
+ }
@@ -0,0 +1,15 @@
1
+ import { View } from 'react-native';
2
+ import { useTheme } from './useTheme';
3
+
4
+ export function Divider() {
5
+ const theme = useTheme();
6
+ return (
7
+ <View
8
+ style={{
9
+ height: 1,
10
+ width: '100%',
11
+ backgroundColor: theme.border.default,
12
+ }}
13
+ />
14
+ );
15
+ }
@@ -0,0 +1,43 @@
1
+ import { Modal as RNModal, Pressable, View } from 'react-native';
2
+ import type { ReactNode } from 'react';
3
+ import { useTheme } from './useTheme';
4
+ import { Text } from './Text';
5
+
6
+ export type ModalProps = {
7
+ title: string;
8
+ visible: boolean;
9
+ onClose?: () => void;
10
+ children?: ReactNode;
11
+ };
12
+
13
+ export function Modal({ title, visible, onClose, children }: ModalProps) {
14
+ const theme = useTheme();
15
+ return (
16
+ <RNModal
17
+ visible={visible}
18
+ transparent
19
+ animationType="slide"
20
+ onRequestClose={onClose}
21
+ >
22
+ <Pressable
23
+ onPress={onClose}
24
+ style={{ flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.4)' }}
25
+ >
26
+ <Pressable
27
+ onPress={() => {}}
28
+ style={{
29
+ marginTop: 'auto',
30
+ backgroundColor: theme.surface.primary,
31
+ borderTopLeftRadius: theme.radius.modal,
32
+ borderTopRightRadius: theme.radius.modal,
33
+ padding: theme.space.lg,
34
+ gap: theme.space.md,
35
+ }}
36
+ >
37
+ <Text size="headline">{title}</Text>
38
+ {children}
39
+ </Pressable>
40
+ </Pressable>
41
+ </RNModal>
42
+ );
43
+ }
@@ -0,0 +1,28 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+ import type { ReactNode } from 'react';
3
+
4
+ export type RowProps = {
5
+ gap?: number;
6
+ align?: 'start' | 'center' | 'end';
7
+ children?: ReactNode;
8
+ style?: ViewProps['style'];
9
+ };
10
+
11
+ const alignMap = {
12
+ start: 'flex-start',
13
+ center: 'center',
14
+ end: 'flex-end',
15
+ } as const;
16
+
17
+ export function Row({ gap = 0, align = 'start', style, children }: RowProps) {
18
+ return (
19
+ <View
20
+ style={[
21
+ { flexDirection: 'row', alignItems: alignMap[align], gap },
22
+ style,
23
+ ]}
24
+ >
25
+ {children}
26
+ </View>
27
+ );
28
+ }
@@ -0,0 +1,38 @@
1
+ import { ScrollView, View } from 'react-native';
2
+ import { SafeAreaView } from 'react-native-safe-area-context';
3
+ import type { ReactNode } from 'react';
4
+ import { useTheme } from './useTheme';
5
+ import { Text } from './Text';
6
+
7
+ export type ScreenProps = {
8
+ title?: string;
9
+ scrollable?: boolean;
10
+ children?: ReactNode;
11
+ };
12
+
13
+ export function Screen({ title, scrollable = true, children }: ScreenProps) {
14
+ const theme = useTheme();
15
+ const Body = scrollable ? ScrollView : View;
16
+ return (
17
+ <SafeAreaView
18
+ style={{ flex: 1, backgroundColor: theme.surface.primary }}
19
+ edges={['top', 'left', 'right']}
20
+ >
21
+ {title ? (
22
+ <View style={{ paddingHorizontal: theme.space.md, paddingTop: theme.space.md, paddingBottom: theme.space.sm }}>
23
+ <Text size="title">{title}</Text>
24
+ </View>
25
+ ) : null}
26
+ <Body
27
+ style={{ flex: 1 }}
28
+ contentContainerStyle={
29
+ scrollable
30
+ ? { padding: theme.space.md, gap: theme.space.md }
31
+ : undefined
32
+ }
33
+ >
34
+ {scrollable ? children : <View style={{ flex: 1, padding: theme.space.md, gap: theme.space.md }}>{children}</View>}
35
+ </Body>
36
+ </SafeAreaView>
37
+ );
38
+ }
@@ -0,0 +1,17 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+ import type { ReactNode } from 'react';
3
+
4
+ export type StackProps = {
5
+ gap?: number;
6
+ padding?: number;
7
+ children?: ReactNode;
8
+ style?: ViewProps['style'];
9
+ };
10
+
11
+ export function Stack({ gap = 0, padding = 0, style, children }: StackProps) {
12
+ return (
13
+ <View style={[{ flexDirection: 'column', gap, padding }, style]}>
14
+ {children}
15
+ </View>
16
+ );
17
+ }
@@ -0,0 +1,37 @@
1
+ import { Text as RNText, type TextProps as RNTextProps, type TextStyle } from 'react-native';
2
+ import type { ReactNode } from 'react';
3
+ import { useTheme, useAccent } from './useTheme';
4
+
5
+ export type TextSize = 'title' | 'headline' | 'body' | 'caption' | 'label';
6
+ export type TextColor = 'primary' | 'secondary' | 'accent' | 'destructive';
7
+
8
+ export type TextProps = {
9
+ size?: TextSize;
10
+ color?: TextColor;
11
+ children?: ReactNode;
12
+ style?: RNTextProps['style'];
13
+ };
14
+
15
+ const sizeMap: Record<TextSize, { fontSize: number; fontWeight: TextStyle['fontWeight'] }> = {
16
+ title: { fontSize: 34, fontWeight: '700' },
17
+ headline: { fontSize: 22, fontWeight: '600' },
18
+ body: { fontSize: 17, fontWeight: '400' },
19
+ caption: { fontSize: 13, fontWeight: '400' },
20
+ label: { fontSize: 13, fontWeight: '600' },
21
+ };
22
+
23
+ export function Text({ size = 'body', color = 'primary', style, children }: TextProps) {
24
+ const theme = useTheme();
25
+ const accent = useAccent();
26
+ const palette: Record<TextColor, string> = {
27
+ primary: theme.text.primary,
28
+ secondary: theme.text.secondary,
29
+ accent,
30
+ destructive: theme.text.destructive,
31
+ };
32
+ return (
33
+ <RNText style={[sizeMap[size], { color: palette[color] }, style]}>
34
+ {children}
35
+ </RNText>
36
+ );
37
+ }
@@ -0,0 +1,40 @@
1
+ import { Platform, Switch as RNSwitch, View } from 'react-native';
2
+ import { Host, Toggle as SwiftUIToggle } from '@expo/ui/swift-ui';
3
+ import { useAccent, useTheme } from './useTheme';
4
+ import { Text } from './Text';
5
+
6
+ export type ToggleProps = {
7
+ label: string;
8
+ value: boolean;
9
+ onChange?: (value: boolean) => void;
10
+ };
11
+
12
+ export function Toggle({ label, value, onChange }: ToggleProps) {
13
+ const theme = useTheme();
14
+ const accent = useAccent();
15
+
16
+ return (
17
+ <View
18
+ style={{
19
+ flexDirection: 'row',
20
+ alignItems: 'center',
21
+ justifyContent: 'space-between',
22
+ paddingVertical: theme.space.sm,
23
+ }}
24
+ >
25
+ <Text size="body">{label}</Text>
26
+ {Platform.OS === 'ios' ? (
27
+ <Host matchContents>
28
+ <SwiftUIToggle isOn={value} onIsOnChange={(next) => onChange?.(next)} />
29
+ </Host>
30
+ ) : (
31
+ <RNSwitch
32
+ value={value}
33
+ onValueChange={onChange}
34
+ trackColor={{ false: theme.border.default, true: accent }}
35
+ thumbColor="#FFFFFF"
36
+ />
37
+ )}
38
+ </View>
39
+ );
40
+ }
@@ -0,0 +1,11 @@
1
+ export { Screen, type ScreenProps } from './Screen';
2
+ export { Stack, type StackProps } from './Stack';
3
+ export { Row, type RowProps } from './Row';
4
+ export { Text, type TextProps, type TextSize, type TextColor } from './Text';
5
+ export { Card, type CardProps } from './Card';
6
+ export { Button, type ButtonProps, type ButtonVariant } from './Button';
7
+ export { Toggle, type ToggleProps } from './Toggle';
8
+ export { Divider } from './Divider';
9
+ export { Modal, type ModalProps } from './Modal';
10
+ export { useTheme, useAccent } from './useTheme';
11
+ export type { Theme, ThemeName, ThemeOverrides, ProtoConfig } from './types';
@@ -0,0 +1,38 @@
1
+ import type { Theme } from '../types';
2
+
3
+ export const liquidGlass: Theme = {
4
+ surface: {
5
+ primary: 'rgba(255, 255, 255, 0.72)',
6
+ secondary: 'rgba(255, 255, 255, 0.48)',
7
+ card: 'rgba(255, 255, 255, 0.6)',
8
+ nav: 'rgba(255, 255, 255, 0.82)',
9
+ },
10
+ text: {
11
+ primary: '#000000',
12
+ secondary: 'rgba(0, 0, 0, 0.5)',
13
+ tertiary: 'rgba(0, 0, 0, 0.3)',
14
+ destructive: '#FF3B30',
15
+ },
16
+ blur: {
17
+ nav: 40,
18
+ card: 20,
19
+ modal: 60,
20
+ },
21
+ border: {
22
+ default: 'rgba(255, 255, 255, 0.4)',
23
+ strong: 'rgba(255, 255, 255, 0.7)',
24
+ },
25
+ radius: {
26
+ card: 22,
27
+ button: 14,
28
+ nav: 0,
29
+ modal: 44,
30
+ },
31
+ space: {
32
+ xs: 4,
33
+ sm: 8,
34
+ md: 16,
35
+ lg: 24,
36
+ xl: 32,
37
+ },
38
+ };
@@ -0,0 +1,38 @@
1
+ import type { Theme } from '../types';
2
+
3
+ export const materialYou: Theme = {
4
+ surface: {
5
+ primary: '#FFFBFE',
6
+ secondary: '#E6E1E5',
7
+ card: '#F4EFF4',
8
+ nav: '#FFFBFE',
9
+ },
10
+ text: {
11
+ primary: '#1C1B1F',
12
+ secondary: '#49454F',
13
+ tertiary: '#79747E',
14
+ destructive: '#B3261E',
15
+ },
16
+ blur: {
17
+ nav: 0,
18
+ card: 0,
19
+ modal: 0,
20
+ },
21
+ border: {
22
+ default: '#CAC4D0',
23
+ strong: '#79747E',
24
+ },
25
+ radius: {
26
+ card: 12,
27
+ button: 20,
28
+ nav: 0,
29
+ modal: 28,
30
+ },
31
+ space: {
32
+ xs: 4,
33
+ sm: 8,
34
+ md: 16,
35
+ lg: 24,
36
+ xl: 32,
37
+ },
38
+ };
@@ -0,0 +1,55 @@
1
+ export type ThemeName = 'liquidGlass' | 'materialYou';
2
+
3
+ export type Theme = {
4
+ surface: {
5
+ primary: string;
6
+ secondary: string;
7
+ card: string;
8
+ nav: string;
9
+ };
10
+ text: {
11
+ primary: string;
12
+ secondary: string;
13
+ tertiary: string;
14
+ destructive: string;
15
+ };
16
+ blur: {
17
+ nav: number;
18
+ card: number;
19
+ modal: number;
20
+ };
21
+ border: {
22
+ default: string;
23
+ strong: string;
24
+ };
25
+ radius: {
26
+ card: number;
27
+ button: number;
28
+ nav: number;
29
+ modal: number;
30
+ };
31
+ space: {
32
+ xs: number;
33
+ sm: number;
34
+ md: number;
35
+ lg: number;
36
+ xl: number;
37
+ };
38
+ };
39
+
40
+ export type ThemeOverrides = Partial<{
41
+ surface: Partial<Theme['surface']>;
42
+ text: Partial<Theme['text']>;
43
+ blur: Partial<Theme['blur']>;
44
+ border: Partial<Theme['border']>;
45
+ radius: Partial<Theme['radius']>;
46
+ space: Partial<Theme['space']>;
47
+ }>;
48
+
49
+ export type ProtoConfig = {
50
+ name?: string;
51
+ theme?: ThemeName;
52
+ accentColor?: string;
53
+ tokens?: ThemeOverrides;
54
+ screens?: { initial?: string };
55
+ };