@metacells/mcellui-core 0.1.0 → 0.1.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metacells/mcellui-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Core theme system and utilities for mcellui - React Native UI components",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -2,7 +2,7 @@
2
2
  * ErrorBoundary
3
3
  *
4
4
  * A React error boundary component for catching and handling
5
- * runtime errors in nativeui components.
5
+ * runtime errors in mcellui components.
6
6
  *
7
7
  * @example
8
8
  * ```tsx
@@ -1,14 +1,25 @@
1
1
  /**
2
2
  * ConfigProvider
3
3
  *
4
- * Wraps ThemeProvider and automatically applies configuration from nativeui.config.ts.
4
+ * Wraps ThemeProvider and automatically applies configuration from mcellui.config.ts.
5
5
  * This is the recommended way to set up NativeUI in your app.
6
6
  *
7
7
  * @example
8
8
  * ```tsx
9
- * // App.tsx
10
- * import { ConfigProvider } from '@nativeui/core';
11
- * import config from './nativeui.config';
9
+ * // App.tsx - with auto-config (requires metro-plugin)
10
+ * import { ConfigProvider } from '@metacells/mcellui-core';
11
+ *
12
+ * export default function App() {
13
+ * return (
14
+ * <ConfigProvider>
15
+ * <YourApp />
16
+ * </ConfigProvider>
17
+ * );
18
+ * }
19
+ *
20
+ * // App.tsx - with explicit config
21
+ * import { ConfigProvider } from '@metacells/mcellui-core';
22
+ * import config from './mcellui.config';
12
23
  *
13
24
  * export default function App() {
14
25
  * return (
@@ -25,13 +36,24 @@ import { ThemeProvider, ThemeProviderProps } from '../theme/ThemeProvider';
25
36
  import { NativeUIConfig, ResolvedNativeUIConfig } from './types';
26
37
  import { resolveConfig } from './defineConfig';
27
38
 
39
+ // Try to load auto-config from metro-plugin (if configured)
40
+ let autoConfig: NativeUIConfig = {};
41
+ try {
42
+ // This module is resolved by @metacells/mcellui-metro-plugin
43
+ // to either the user's config file or an empty default
44
+ autoConfig = require('@mcellui/auto-config').default ?? {};
45
+ } catch {
46
+ // Metro plugin not configured, use empty default
47
+ autoConfig = {};
48
+ }
49
+
28
50
  // Config context for accessing raw config values
29
51
  const ConfigContext = createContext<ResolvedNativeUIConfig | null>(null);
30
52
 
31
53
  export interface ConfigProviderProps {
32
54
  /**
33
55
  * NativeUI configuration object.
34
- * Import from your nativeui.config.ts file.
56
+ * Import from your mcellui.config.ts file.
35
57
  */
36
58
  config?: NativeUIConfig;
37
59
 
@@ -60,8 +82,11 @@ export interface ConfigProviderProps {
60
82
  }
61
83
 
62
84
  /**
63
- * ConfigProvider combines your nativeui.config.ts with ThemeProvider.
85
+ * ConfigProvider combines your mcellui.config.ts with ThemeProvider.
64
86
  * Use this as the root of your app for the easiest setup.
87
+ *
88
+ * If no config is provided and @metacells/mcellui-metro-plugin is set up,
89
+ * it will automatically load your mcellui.config.ts file.
65
90
  */
66
91
  export function ConfigProvider({
67
92
  config,
@@ -70,8 +95,11 @@ export function ConfigProvider({
70
95
  radius,
71
96
  children,
72
97
  }: ConfigProviderProps) {
98
+ // Use provided config, or fall back to auto-discovered config
99
+ const effectiveConfig = config ?? autoConfig;
100
+
73
101
  // Resolve config with defaults
74
- const resolvedConfig = useMemo(() => resolveConfig(config), [config]);
102
+ const resolvedConfig = useMemo(() => resolveConfig(effectiveConfig), [effectiveConfig]);
75
103
 
76
104
  // Props can override config values
77
105
  const finalTheme = theme ?? resolvedConfig.theme;
@@ -2,12 +2,12 @@
2
2
  * defineConfig
3
3
  *
4
4
  * Helper function to define NativeUI configuration with type safety.
5
- * Use this in your `nativeui.config.ts` file.
5
+ * Use this in your `mcellui.config.ts` file.
6
6
  *
7
7
  * @example
8
8
  * ```ts
9
- * // nativeui.config.ts
10
- * import { defineConfig } from '@nativeui/core';
9
+ * // mcellui.config.ts
10
+ * import { defineConfig } from '@metacells/mcellui-core';
11
11
  *
12
12
  * export default defineConfig({
13
13
  * theme: 'blue',
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * @example
7
7
  * ```ts
8
- * // nativeui.config.ts
9
- * import { defineConfig } from '@nativeui/core';
8
+ * // mcellui.config.ts
9
+ * import { defineConfig } from '@metacells/mcellui-core';
10
10
  *
11
11
  * export default defineConfig({
12
12
  * theme: 'blue',
@@ -20,8 +20,8 @@
20
20
  * @example
21
21
  * ```tsx
22
22
  * // App.tsx
23
- * import { ConfigProvider } from '@nativeui/core';
24
- * import config from './nativeui.config';
23
+ * import { ConfigProvider } from '@metacells/mcellui-core';
24
+ * import config from './mcellui.config';
25
25
  *
26
26
  * export default function App() {
27
27
  * return (
@@ -6,8 +6,8 @@
6
6
  *
7
7
  * @example
8
8
  * ```ts
9
- * // nativeui.config.ts
10
- * import { defineConfig } from '@nativeui/core';
9
+ * // mcellui.config.ts
10
+ * import { defineConfig } from '@metacells/mcellui-core';
11
11
  *
12
12
  * export default defineConfig({
13
13
  * theme: 'blue',
@@ -27,7 +27,7 @@ import type { AnimationPreset } from '../theme/animations';
27
27
 
28
28
  /**
29
29
  * NativeUI configuration object.
30
- * Place in `nativeui.config.ts` at your project root.
30
+ * Place in `mcellui.config.ts` at your project root.
31
31
  */
32
32
  export interface NativeUIConfig {
33
33
  // ============================================
@@ -113,7 +113,7 @@ export interface NativeUIConfig {
113
113
  };
114
114
 
115
115
  // ============================================
116
- // CLI Configuration (used by `npx nativeui add`)
116
+ // CLI Configuration (used by `npx mcellui add`)
117
117
  // ============================================
118
118
 
119
119
  /**
package/src/constants.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @example
9
9
  * ```tsx
10
- * import { SHEET_CONSTANTS } from '@nativeui/core';
10
+ * import { SHEET_CONSTANTS } from '@metacells/mcellui-core';
11
11
  *
12
12
  * // In SheetContent:
13
13
  * if (translationY > height * SHEET_CONSTANTS.closeThreshold) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ThemeProvider
3
3
  *
4
- * Provides theme context to all nativeui components.
4
+ * Provides theme context to all mcellui components.
5
5
  * Automatically detects system color scheme and provides all design tokens.
6
6
  *
7
7
  * Like shadcn/ui - change tokens here to transform the entire UI.
@@ -24,6 +24,7 @@ import React, { createContext, useContext, useMemo, useState, useCallback, useEf
24
24
  import { useColorScheme, ViewStyle } from 'react-native';
25
25
  import { lightColors, darkColors, ThemeColors } from './colors';
26
26
  import { setHapticsEnabled } from '../utils/haptics';
27
+ import { setAnimationsDisabled, isExpoGo } from '../utils/expoGo';
27
28
  import { spacing } from './spacing';
28
29
  import {
29
30
  createRadius,
@@ -251,6 +252,24 @@ export interface ThemeProviderProps {
251
252
  */
252
253
  animationPreset?: AnimationPreset;
253
254
 
255
+ /**
256
+ * Enable or disable animations globally.
257
+ * - `true`: Force enable animations
258
+ * - `false`: Force disable animations (components will use static styles)
259
+ * - `'auto'`: Automatically detect - disable in Expo Go, enable in dev/prod builds
260
+ * @default 'auto'
261
+ *
262
+ * @example
263
+ * ```tsx
264
+ * // Auto-detect (disabled in Expo Go)
265
+ * <ThemeProvider animations="auto">
266
+ *
267
+ * // Force disable for testing or accessibility
268
+ * <ThemeProvider animations={false}>
269
+ * ```
270
+ */
271
+ animations?: boolean | 'auto';
272
+
254
273
  /** Children components */
255
274
  children: ReactNode;
256
275
  }
@@ -265,6 +284,7 @@ export function ThemeProvider({
265
284
  darkColors: darkColorOverrides,
266
285
  haptics = true,
267
286
  animationPreset = defaultAnimationPreset,
287
+ animations = 'auto',
268
288
  children,
269
289
  }: ThemeProviderProps) {
270
290
  const systemColorScheme = useColorScheme();
@@ -275,6 +295,17 @@ export function ThemeProvider({
275
295
  setHapticsEnabled(haptics);
276
296
  }, [haptics]);
277
297
 
298
+ // Set global animations enabled state
299
+ useEffect(() => {
300
+ if (animations === 'auto') {
301
+ // Use automatic detection (Expo Go = disabled)
302
+ setAnimationsDisabled(null);
303
+ } else {
304
+ // Use explicit override
305
+ setAnimationsDisabled(!animations);
306
+ }
307
+ }, [animations]);
308
+
278
309
  const setColorScheme = useCallback((newPreference: ColorSchemePreference) => {
279
310
  setPreference(newPreference);
280
311
  }, []);
@@ -7,8 +7,6 @@
7
7
  * Inspired by iOS 17+ animations and Linear App micro-interactions.
8
8
  */
9
9
 
10
- import { Easing, EasingFunction } from 'react-native-reanimated';
11
-
12
10
  // Type definitions for Reanimated-compatible configs
13
11
  export interface SpringConfig {
14
12
  damping?: number;
@@ -20,15 +18,19 @@ export interface SpringConfig {
20
18
  velocity?: number;
21
19
  }
22
20
 
21
+ // Generic easing function type that works with or without Reanimated
22
+ type EasingFn = (t: number) => number;
23
+
23
24
  export interface TimingConfig {
24
25
  duration?: number;
25
- easing?: EasingFunction;
26
+ easing?: EasingFn;
26
27
  }
27
28
 
28
- // Common easing functions using Reanimated's Easing module (worklet-compatible)
29
- const easeOutQuad = Easing.out(Easing.quad);
30
- const easeOutCubic = Easing.out(Easing.cubic);
31
- const easeInQuad = Easing.in(Easing.quad);
29
+ // Simple easing functions that don't require Reanimated
30
+ // These are compatible with both Reanimated and standard Animated API
31
+ const easeOutQuad: EasingFn = (t) => t * (2 - t);
32
+ const easeOutCubic: EasingFn = (t) => 1 - Math.pow(1 - t, 3);
33
+ const easeInQuad: EasingFn = (t) => t * t;
32
34
 
33
35
  /**
34
36
  * Spring configurations for different animation contexts
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Theme System
3
3
  *
4
- * Complete design token system for nativeui components.
4
+ * Complete design token system for mcellui components.
5
5
  * Inspired by shadcn/ui - change a few tokens to transform the entire UI.
6
6
  */
7
7
 
package/src/utils/cn.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * cn() - Class Name / Style Merger
3
3
  *
4
- * The core utility for merging styles in nativeui.
4
+ * The core utility for merging styles in mcellui.
5
5
  * Inspired by shadcn/ui's cn() but adapted for React Native StyleSheet.
6
6
  */
7
7
 
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Expo Go Detection Utility
3
+ *
4
+ * Provides detection for Expo Go environment to gracefully disable
5
+ * Reanimated animations when running in Expo Go client.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { isExpoGo, areAnimationsDisabled } from '@metacells/mcellui-core';
10
+ *
11
+ * // Check environment
12
+ * if (isExpoGo()) {
13
+ * console.log('Running in Expo Go');
14
+ * }
15
+ *
16
+ * // Check if animations should be disabled
17
+ * if (areAnimationsDisabled()) {
18
+ * // Skip animation, use static styles
19
+ * }
20
+ * ```
21
+ */
22
+
23
+ let executionEnvironment: string | undefined;
24
+
25
+ // Try to load expo-constants at module load time
26
+ try {
27
+ // Dynamic require to avoid bundler issues when expo-constants is not available
28
+ const Constants = require('expo-constants').default;
29
+ executionEnvironment = Constants?.executionEnvironment;
30
+ } catch {
31
+ // expo-constants not available - not in Expo environment
32
+ executionEnvironment = undefined;
33
+ }
34
+
35
+ /**
36
+ * Check if the app is running in Expo Go client.
37
+ * Returns false in development builds, production builds, or non-Expo environments.
38
+ */
39
+ export function isExpoGo(): boolean {
40
+ return executionEnvironment === 'storeClient';
41
+ }
42
+
43
+ // Internal state for animation override
44
+ let animationsDisabledOverride: boolean | null = null;
45
+
46
+ /**
47
+ * Manually override the animation disabled state.
48
+ * Set to `true` to force disable animations, `false` to force enable,
49
+ * or `null` to use automatic detection (Expo Go = disabled).
50
+ *
51
+ * @param disabled - Override value or null for automatic
52
+ */
53
+ export function setAnimationsDisabled(disabled: boolean | null): void {
54
+ animationsDisabledOverride = disabled;
55
+ }
56
+
57
+ /**
58
+ * Check if animations should be disabled.
59
+ * Returns true if:
60
+ * - Manually overridden to true via setAnimationsDisabled(true)
61
+ * - Running in Expo Go (automatic detection)
62
+ *
63
+ * Returns false if:
64
+ * - Manually overridden to false via setAnimationsDisabled(false)
65
+ * - Running in development/production build
66
+ */
67
+ export function areAnimationsDisabled(): boolean {
68
+ if (animationsDisabledOverride !== null) {
69
+ return animationsDisabledOverride;
70
+ }
71
+ return isExpoGo();
72
+ }
@@ -75,7 +75,7 @@ export function isHapticsEnabled(): boolean {
75
75
  * Respects the global haptics enabled state. Disabled via:
76
76
  * - `setHapticsEnabled(false)`
77
77
  * - `<ThemeProvider haptics={false}>`
78
- * - `nativeui.config.ts` with `haptics: false`
78
+ * - `mcellui.config.ts` with `haptics: false`
79
79
  *
80
80
  * @example
81
81
  * ```tsx
@@ -26,3 +26,8 @@ export {
26
26
  hapticPresets,
27
27
  type HapticStyle,
28
28
  } from './haptics';
29
+ export {
30
+ isExpoGo,
31
+ setAnimationsDisabled,
32
+ areAnimationsDisabled,
33
+ } from './expoGo';