@metacells/mcellui-core 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.
- package/package.json +50 -0
- package/src/components/ErrorBoundary.tsx +188 -0
- package/src/components/index.ts +6 -0
- package/src/config/ConfigProvider.tsx +117 -0
- package/src/config/defineConfig.ts +75 -0
- package/src/config/index.ts +42 -0
- package/src/config/types.ts +185 -0
- package/src/constants.ts +203 -0
- package/src/index.ts +144 -0
- package/src/primitives/Portal.tsx +185 -0
- package/src/primitives/Pressable.tsx +114 -0
- package/src/primitives/Slot.tsx +177 -0
- package/src/primitives/index.ts +19 -0
- package/src/theme/ThemeProvider.tsx +475 -0
- package/src/theme/animations.ts +379 -0
- package/src/theme/colors.ts +266 -0
- package/src/theme/components.ts +267 -0
- package/src/theme/index.ts +130 -0
- package/src/theme/presets.ts +341 -0
- package/src/theme/radius.ts +175 -0
- package/src/theme/shadows.ts +166 -0
- package/src/theme/spacing.ts +41 -0
- package/src/theme/typography.ts +389 -0
- package/src/tokens/colors.ts +67 -0
- package/src/tokens/index.ts +29 -0
- package/src/tokens/radius.ts +18 -0
- package/src/tokens/shadows.ts +38 -0
- package/src/tokens/spacing.ts +45 -0
- package/src/tokens/typography.ts +70 -0
- package/src/utils/accessibility.ts +112 -0
- package/src/utils/cn.ts +58 -0
- package/src/utils/haptics.ts +125 -0
- package/src/utils/index.ts +28 -0
- package/src/utils/platform.ts +66 -0
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metacells/mcellui-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core theme system and utilities for mcellui - React Native UI components",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./src/index.ts",
|
|
10
|
+
"default": "./src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
"./tokens": {
|
|
13
|
+
"types": "./src/tokens/index.ts",
|
|
14
|
+
"default": "./src/tokens/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"./utils": {
|
|
17
|
+
"types": "./src/utils/index.ts",
|
|
18
|
+
"default": "./src/utils/index.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"src"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"react-native",
|
|
26
|
+
"expo",
|
|
27
|
+
"ui-components",
|
|
28
|
+
"theme",
|
|
29
|
+
"design-system",
|
|
30
|
+
"mcellui"
|
|
31
|
+
],
|
|
32
|
+
"author": "christlerjohannes",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/metacells/mcellui"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"type-check": "tsc --noEmit",
|
|
40
|
+
"lint": "eslint src/"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": ">=18.0.0",
|
|
44
|
+
"react-native": ">=0.73.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/react": "~19.1.10",
|
|
48
|
+
"typescript": "^5.4.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorBoundary
|
|
3
|
+
*
|
|
4
|
+
* A React error boundary component for catching and handling
|
|
5
|
+
* runtime errors in nativeui components.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* // Wrap individual components
|
|
10
|
+
* <ErrorBoundary fallback={<Text>Something went wrong</Text>}>
|
|
11
|
+
* <MyComponent />
|
|
12
|
+
* </ErrorBoundary>
|
|
13
|
+
*
|
|
14
|
+
* // With custom error handler
|
|
15
|
+
* <ErrorBoundary
|
|
16
|
+
* onError={(error, errorInfo) => {
|
|
17
|
+
* logErrorToService(error, errorInfo);
|
|
18
|
+
* }}
|
|
19
|
+
* fallback={({ error, reset }) => (
|
|
20
|
+
* <View>
|
|
21
|
+
* <Text>Error: {error.message}</Text>
|
|
22
|
+
* <Button onPress={reset}>Try Again</Button>
|
|
23
|
+
* </View>
|
|
24
|
+
* )}
|
|
25
|
+
* >
|
|
26
|
+
* <MyComponent />
|
|
27
|
+
* </ErrorBoundary>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import React, { Component, ReactNode, ErrorInfo } from 'react';
|
|
32
|
+
import { View, Text, StyleSheet, Pressable } from 'react-native';
|
|
33
|
+
|
|
34
|
+
export interface ErrorBoundaryFallbackProps {
|
|
35
|
+
/** The error that was caught */
|
|
36
|
+
error: Error;
|
|
37
|
+
/** Function to reset the error boundary and retry */
|
|
38
|
+
reset: () => void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ErrorBoundaryProps {
|
|
42
|
+
/** Children to render when no error */
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Fallback UI to show when an error occurs.
|
|
47
|
+
* Can be a ReactNode or a render function receiving error details.
|
|
48
|
+
*/
|
|
49
|
+
fallback?: ReactNode | ((props: ErrorBoundaryFallbackProps) => ReactNode);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Callback when an error is caught.
|
|
53
|
+
* Use for logging errors to external services.
|
|
54
|
+
*/
|
|
55
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Callback when the error boundary resets.
|
|
59
|
+
*/
|
|
60
|
+
onReset?: () => void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ErrorBoundaryState {
|
|
64
|
+
hasError: boolean;
|
|
65
|
+
error: Error | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
69
|
+
constructor(props: ErrorBoundaryProps) {
|
|
70
|
+
super(props);
|
|
71
|
+
this.state = { hasError: false, error: null };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
75
|
+
return { hasError: true, error };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
|
|
79
|
+
this.props.onError?.(error, errorInfo);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
reset = (): void => {
|
|
83
|
+
this.props.onReset?.();
|
|
84
|
+
this.setState({ hasError: false, error: null });
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
render(): ReactNode {
|
|
88
|
+
const { hasError, error } = this.state;
|
|
89
|
+
const { children, fallback } = this.props;
|
|
90
|
+
|
|
91
|
+
if (hasError && error) {
|
|
92
|
+
// No fallback provided - render default
|
|
93
|
+
if (!fallback) {
|
|
94
|
+
return (
|
|
95
|
+
<DefaultErrorFallback
|
|
96
|
+
error={error}
|
|
97
|
+
reset={this.reset}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Render function fallback
|
|
103
|
+
if (typeof fallback === 'function') {
|
|
104
|
+
return fallback({ error, reset: this.reset });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ReactNode fallback
|
|
108
|
+
return fallback;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return children;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Default error fallback UI
|
|
117
|
+
*/
|
|
118
|
+
function DefaultErrorFallback({ error, reset }: ErrorBoundaryFallbackProps) {
|
|
119
|
+
return (
|
|
120
|
+
<View style={styles.container}>
|
|
121
|
+
<Text style={styles.title}>Something went wrong</Text>
|
|
122
|
+
<Text style={styles.message}>{error.message}</Text>
|
|
123
|
+
<Pressable style={styles.button} onPress={reset}>
|
|
124
|
+
<Text style={styles.buttonText}>Try Again</Text>
|
|
125
|
+
</Pressable>
|
|
126
|
+
</View>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const styles = StyleSheet.create({
|
|
131
|
+
container: {
|
|
132
|
+
flex: 1,
|
|
133
|
+
justifyContent: 'center',
|
|
134
|
+
alignItems: 'center',
|
|
135
|
+
padding: 24,
|
|
136
|
+
backgroundColor: '#f8f8f8',
|
|
137
|
+
},
|
|
138
|
+
title: {
|
|
139
|
+
fontSize: 18,
|
|
140
|
+
fontWeight: '600',
|
|
141
|
+
color: '#1a1a1a',
|
|
142
|
+
marginBottom: 8,
|
|
143
|
+
},
|
|
144
|
+
message: {
|
|
145
|
+
fontSize: 14,
|
|
146
|
+
color: '#666',
|
|
147
|
+
textAlign: 'center',
|
|
148
|
+
marginBottom: 24,
|
|
149
|
+
},
|
|
150
|
+
button: {
|
|
151
|
+
backgroundColor: '#1a1a1a',
|
|
152
|
+
paddingHorizontal: 24,
|
|
153
|
+
paddingVertical: 12,
|
|
154
|
+
borderRadius: 8,
|
|
155
|
+
},
|
|
156
|
+
buttonText: {
|
|
157
|
+
color: '#fff',
|
|
158
|
+
fontSize: 14,
|
|
159
|
+
fontWeight: '500',
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Higher-order component to wrap a component with an error boundary
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```tsx
|
|
168
|
+
* const SafeMyComponent = withErrorBoundary(MyComponent, {
|
|
169
|
+
* fallback: <Text>Error loading component</Text>,
|
|
170
|
+
* });
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export function withErrorBoundary<P extends object>(
|
|
174
|
+
WrappedComponent: React.ComponentType<P>,
|
|
175
|
+
errorBoundaryProps?: Omit<ErrorBoundaryProps, 'children'>
|
|
176
|
+
): React.FC<P> {
|
|
177
|
+
const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
|
|
178
|
+
|
|
179
|
+
const ComponentWithErrorBoundary: React.FC<P> = (props) => (
|
|
180
|
+
<ErrorBoundary {...errorBoundaryProps}>
|
|
181
|
+
<WrappedComponent {...props} />
|
|
182
|
+
</ErrorBoundary>
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
ComponentWithErrorBoundary.displayName = `withErrorBoundary(${displayName})`;
|
|
186
|
+
|
|
187
|
+
return ComponentWithErrorBoundary;
|
|
188
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigProvider
|
|
3
|
+
*
|
|
4
|
+
* Wraps ThemeProvider and automatically applies configuration from nativeui.config.ts.
|
|
5
|
+
* This is the recommended way to set up NativeUI in your app.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* // App.tsx
|
|
10
|
+
* import { ConfigProvider } from '@nativeui/core';
|
|
11
|
+
* import config from './nativeui.config';
|
|
12
|
+
*
|
|
13
|
+
* export default function App() {
|
|
14
|
+
* return (
|
|
15
|
+
* <ConfigProvider config={config}>
|
|
16
|
+
* <YourApp />
|
|
17
|
+
* </ConfigProvider>
|
|
18
|
+
* );
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import React, { createContext, useContext, ReactNode, useMemo } from 'react';
|
|
24
|
+
import { ThemeProvider, ThemeProviderProps } from '../theme/ThemeProvider';
|
|
25
|
+
import { NativeUIConfig, ResolvedNativeUIConfig } from './types';
|
|
26
|
+
import { resolveConfig } from './defineConfig';
|
|
27
|
+
|
|
28
|
+
// Config context for accessing raw config values
|
|
29
|
+
const ConfigContext = createContext<ResolvedNativeUIConfig | null>(null);
|
|
30
|
+
|
|
31
|
+
export interface ConfigProviderProps {
|
|
32
|
+
/**
|
|
33
|
+
* NativeUI configuration object.
|
|
34
|
+
* Import from your nativeui.config.ts file.
|
|
35
|
+
*/
|
|
36
|
+
config?: NativeUIConfig;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Override the color scheme preference.
|
|
40
|
+
* Takes precedence over config.colorScheme.
|
|
41
|
+
*/
|
|
42
|
+
colorScheme?: 'light' | 'dark' | 'system';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Override the theme preset.
|
|
46
|
+
* Takes precedence over config.theme.
|
|
47
|
+
*/
|
|
48
|
+
theme?: ThemeProviderProps['theme'];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Override the radius preset.
|
|
52
|
+
* Takes precedence over config.radius.
|
|
53
|
+
*/
|
|
54
|
+
radius?: ThemeProviderProps['radius'];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Children components.
|
|
58
|
+
*/
|
|
59
|
+
children: ReactNode;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* ConfigProvider combines your nativeui.config.ts with ThemeProvider.
|
|
64
|
+
* Use this as the root of your app for the easiest setup.
|
|
65
|
+
*/
|
|
66
|
+
export function ConfigProvider({
|
|
67
|
+
config,
|
|
68
|
+
colorScheme,
|
|
69
|
+
theme,
|
|
70
|
+
radius,
|
|
71
|
+
children,
|
|
72
|
+
}: ConfigProviderProps) {
|
|
73
|
+
// Resolve config with defaults
|
|
74
|
+
const resolvedConfig = useMemo(() => resolveConfig(config), [config]);
|
|
75
|
+
|
|
76
|
+
// Props can override config values
|
|
77
|
+
const finalTheme = theme ?? resolvedConfig.theme;
|
|
78
|
+
const finalRadius = radius ?? resolvedConfig.radius;
|
|
79
|
+
const finalColorScheme = colorScheme ?? resolvedConfig.colorScheme;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<ConfigContext.Provider value={resolvedConfig}>
|
|
83
|
+
<ThemeProvider
|
|
84
|
+
defaultColorScheme={finalColorScheme}
|
|
85
|
+
theme={finalTheme}
|
|
86
|
+
radius={finalRadius}
|
|
87
|
+
colors={resolvedConfig.colors}
|
|
88
|
+
lightColors={resolvedConfig.lightColors}
|
|
89
|
+
darkColors={resolvedConfig.darkColors}
|
|
90
|
+
fonts={resolvedConfig.fonts}
|
|
91
|
+
>
|
|
92
|
+
{children}
|
|
93
|
+
</ThemeProvider>
|
|
94
|
+
</ConfigContext.Provider>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Hook to access the raw NativeUI configuration.
|
|
100
|
+
* Useful for accessing component defaults and other config values.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```tsx
|
|
104
|
+
* const config = useConfig();
|
|
105
|
+
* const defaultButtonSize = config.components.button?.defaultSize ?? 'md';
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export function useConfig(): ResolvedNativeUIConfig {
|
|
109
|
+
const config = useContext(ConfigContext);
|
|
110
|
+
|
|
111
|
+
if (!config) {
|
|
112
|
+
// Return default config if no provider
|
|
113
|
+
return resolveConfig({});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return config;
|
|
117
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defineConfig
|
|
3
|
+
*
|
|
4
|
+
* Helper function to define NativeUI configuration with type safety.
|
|
5
|
+
* Use this in your `nativeui.config.ts` file.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // nativeui.config.ts
|
|
10
|
+
* import { defineConfig } from '@nativeui/core';
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* theme: 'blue',
|
|
14
|
+
* radius: 'lg',
|
|
15
|
+
* colors: {
|
|
16
|
+
* primary: '#6366F1',
|
|
17
|
+
* secondary: '#F3F4F6',
|
|
18
|
+
* },
|
|
19
|
+
* fonts: {
|
|
20
|
+
* heading: 'PlayfairDisplay_700Bold',
|
|
21
|
+
* },
|
|
22
|
+
* components: {
|
|
23
|
+
* button: {
|
|
24
|
+
* defaultVariant: 'default',
|
|
25
|
+
* defaultSize: 'md',
|
|
26
|
+
* },
|
|
27
|
+
* },
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { NativeUIConfig, ResolvedNativeUIConfig, defaultConfig } from './types';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Define your NativeUI configuration with full type safety and autocomplete.
|
|
36
|
+
*
|
|
37
|
+
* @param config - Your configuration options
|
|
38
|
+
* @returns The same config object (for type inference)
|
|
39
|
+
*/
|
|
40
|
+
export function defineConfig(config: NativeUIConfig): NativeUIConfig {
|
|
41
|
+
return config;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a partial config into a full config with defaults.
|
|
46
|
+
*
|
|
47
|
+
* @param config - Partial configuration
|
|
48
|
+
* @returns Fully resolved configuration with defaults applied
|
|
49
|
+
*/
|
|
50
|
+
export function resolveConfig(config: NativeUIConfig = {}): ResolvedNativeUIConfig {
|
|
51
|
+
return {
|
|
52
|
+
// Runtime configuration
|
|
53
|
+
theme: config.theme ?? defaultConfig.theme,
|
|
54
|
+
radius: config.radius ?? defaultConfig.radius,
|
|
55
|
+
colorScheme: config.colorScheme ?? defaultConfig.colorScheme,
|
|
56
|
+
colors: config.colors ?? defaultConfig.colors,
|
|
57
|
+
lightColors: config.lightColors ?? defaultConfig.lightColors,
|
|
58
|
+
darkColors: config.darkColors ?? defaultConfig.darkColors,
|
|
59
|
+
fonts: config.fonts ?? defaultConfig.fonts,
|
|
60
|
+
haptics: config.haptics ?? defaultConfig.haptics,
|
|
61
|
+
animationPreset: config.animationPreset ?? defaultConfig.animationPreset,
|
|
62
|
+
components: {
|
|
63
|
+
...defaultConfig.components,
|
|
64
|
+
...config.components,
|
|
65
|
+
},
|
|
66
|
+
// CLI configuration
|
|
67
|
+
componentsPath: config.componentsPath ?? defaultConfig.componentsPath,
|
|
68
|
+
utilsPath: config.utilsPath ?? defaultConfig.utilsPath,
|
|
69
|
+
style: config.style ?? defaultConfig.style,
|
|
70
|
+
aliases: {
|
|
71
|
+
...defaultConfig.aliases,
|
|
72
|
+
...config.aliases,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NativeUI Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configure your entire design system in one place.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // nativeui.config.ts
|
|
9
|
+
* import { defineConfig } from '@nativeui/core';
|
|
10
|
+
*
|
|
11
|
+
* export default defineConfig({
|
|
12
|
+
* theme: 'blue',
|
|
13
|
+
* radius: 'lg',
|
|
14
|
+
* colors: {
|
|
15
|
+
* primary: '#6366F1',
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* // App.tsx
|
|
23
|
+
* import { ConfigProvider } from '@nativeui/core';
|
|
24
|
+
* import config from './nativeui.config';
|
|
25
|
+
*
|
|
26
|
+
* export default function App() {
|
|
27
|
+
* return (
|
|
28
|
+
* <ConfigProvider config={config}>
|
|
29
|
+
* <YourApp />
|
|
30
|
+
* </ConfigProvider>
|
|
31
|
+
* );
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export { defineConfig, resolveConfig } from './defineConfig';
|
|
37
|
+
export { ConfigProvider, useConfig } from './ConfigProvider';
|
|
38
|
+
export type {
|
|
39
|
+
NativeUIConfig,
|
|
40
|
+
ResolvedNativeUIConfig,
|
|
41
|
+
} from './types';
|
|
42
|
+
export { defaultConfig } from './types';
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NativeUI Configuration Types
|
|
3
|
+
*
|
|
4
|
+
* Define your app's design system in a single config file.
|
|
5
|
+
* Similar to tailwind.config.js but for React Native.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // nativeui.config.ts
|
|
10
|
+
* import { defineConfig } from '@nativeui/core';
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* theme: 'blue',
|
|
14
|
+
* radius: 'lg',
|
|
15
|
+
* colors: {
|
|
16
|
+
* primary: '#6366F1',
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { ThemePreset } from '../theme/presets';
|
|
23
|
+
import type { RadiusPreset } from '../theme/radius';
|
|
24
|
+
import type { ThemeColors } from '../theme/colors';
|
|
25
|
+
import type { Fonts } from '../theme/typography';
|
|
26
|
+
import type { AnimationPreset } from '../theme/animations';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* NativeUI configuration object.
|
|
30
|
+
* Place in `nativeui.config.ts` at your project root.
|
|
31
|
+
*/
|
|
32
|
+
export interface NativeUIConfig {
|
|
33
|
+
// ============================================
|
|
34
|
+
// Runtime Configuration (used by ConfigProvider)
|
|
35
|
+
// ============================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Color theme preset.
|
|
39
|
+
* @default 'zinc'
|
|
40
|
+
*/
|
|
41
|
+
theme?: ThemePreset;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Border radius preset.
|
|
45
|
+
* Controls roundness of all components.
|
|
46
|
+
* @default 'md'
|
|
47
|
+
*/
|
|
48
|
+
radius?: RadiusPreset;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default color scheme preference.
|
|
52
|
+
* @default 'system'
|
|
53
|
+
*/
|
|
54
|
+
colorScheme?: 'light' | 'dark' | 'system';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Color overrides (applied to both light and dark modes).
|
|
58
|
+
*/
|
|
59
|
+
colors?: Partial<ThemeColors>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Light mode specific color overrides.
|
|
63
|
+
*/
|
|
64
|
+
lightColors?: Partial<ThemeColors>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Dark mode specific color overrides.
|
|
68
|
+
*/
|
|
69
|
+
darkColors?: Partial<ThemeColors>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Font configuration.
|
|
73
|
+
*/
|
|
74
|
+
fonts?: Partial<Fonts>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Enable or disable haptic feedback globally.
|
|
78
|
+
* @default true
|
|
79
|
+
*/
|
|
80
|
+
haptics?: boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Animation preset.
|
|
84
|
+
* Controls the overall feel of animations throughout the app.
|
|
85
|
+
* - `subtle`: Professional, smooth animations with minimal overshoot
|
|
86
|
+
* - `playful`: Bouncy, energetic animations with more personality
|
|
87
|
+
* @default 'subtle'
|
|
88
|
+
*/
|
|
89
|
+
animationPreset?: AnimationPreset;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Component-specific overrides.
|
|
93
|
+
* Override default sizes, padding, etc.
|
|
94
|
+
*/
|
|
95
|
+
components?: {
|
|
96
|
+
button?: {
|
|
97
|
+
defaultVariant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive';
|
|
98
|
+
defaultSize?: 'sm' | 'md' | 'lg';
|
|
99
|
+
};
|
|
100
|
+
input?: {
|
|
101
|
+
defaultSize?: 'sm' | 'md' | 'lg';
|
|
102
|
+
};
|
|
103
|
+
card?: {
|
|
104
|
+
defaultVariant?: 'default' | 'elevated' | 'outlined';
|
|
105
|
+
};
|
|
106
|
+
badge?: {
|
|
107
|
+
defaultVariant?: 'default' | 'secondary' | 'destructive' | 'outline';
|
|
108
|
+
defaultSize?: 'sm' | 'md' | 'lg';
|
|
109
|
+
};
|
|
110
|
+
avatar?: {
|
|
111
|
+
defaultSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// ============================================
|
|
116
|
+
// CLI Configuration (used by `npx nativeui add`)
|
|
117
|
+
// ============================================
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Path where components will be installed.
|
|
121
|
+
* @default './components/ui'
|
|
122
|
+
*/
|
|
123
|
+
componentsPath?: string;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Path where utilities (cn, etc.) will be installed.
|
|
127
|
+
* @default './lib/utils'
|
|
128
|
+
*/
|
|
129
|
+
utilsPath?: string;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Style preset for components.
|
|
133
|
+
* @default 'default'
|
|
134
|
+
*/
|
|
135
|
+
style?: 'default' | 'ios' | 'material';
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Path aliases for imports.
|
|
139
|
+
*/
|
|
140
|
+
aliases?: {
|
|
141
|
+
/** Alias for components directory */
|
|
142
|
+
components?: string;
|
|
143
|
+
/** Alias for utils directory */
|
|
144
|
+
utils?: string;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Resolved configuration with all defaults applied.
|
|
150
|
+
*/
|
|
151
|
+
export interface ResolvedNativeUIConfig extends Required<Omit<NativeUIConfig, 'colors' | 'lightColors' | 'darkColors' | 'fonts' | 'components' | 'aliases' | 'haptics' | 'animationPreset'>> {
|
|
152
|
+
colors: Partial<ThemeColors>;
|
|
153
|
+
lightColors: Partial<ThemeColors>;
|
|
154
|
+
darkColors: Partial<ThemeColors>;
|
|
155
|
+
fonts: Partial<Fonts>;
|
|
156
|
+
haptics: boolean;
|
|
157
|
+
animationPreset: AnimationPreset;
|
|
158
|
+
components: NonNullable<NativeUIConfig['components']>;
|
|
159
|
+
aliases: NonNullable<NativeUIConfig['aliases']>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Default configuration values.
|
|
164
|
+
*/
|
|
165
|
+
export const defaultConfig: ResolvedNativeUIConfig = {
|
|
166
|
+
// Runtime defaults
|
|
167
|
+
theme: 'zinc',
|
|
168
|
+
radius: 'md',
|
|
169
|
+
colorScheme: 'system',
|
|
170
|
+
colors: {},
|
|
171
|
+
lightColors: {},
|
|
172
|
+
darkColors: {},
|
|
173
|
+
fonts: {},
|
|
174
|
+
haptics: true,
|
|
175
|
+
animationPreset: 'subtle',
|
|
176
|
+
components: {},
|
|
177
|
+
// CLI defaults
|
|
178
|
+
componentsPath: './components/ui',
|
|
179
|
+
utilsPath: './lib/utils',
|
|
180
|
+
style: 'default',
|
|
181
|
+
aliases: {
|
|
182
|
+
components: '@/components',
|
|
183
|
+
utils: '@/lib/utils',
|
|
184
|
+
},
|
|
185
|
+
};
|