zelune 1.5.2 → 1.5.5
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/CHANGELOG.md +38 -0
- package/bin/cli.mjs +17 -6
- package/index.html +9 -2
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/plugins/viteReactNativeFallbackPlugin.ts +528 -0
- package/plugins/viteVirtualScreensPlugin.ts +139 -8
- package/src/canvas/CanvasApp.tsx +186 -45
- package/src/canvas/FlowArrowsLayer.tsx +7 -7
- package/src/canvas/InspectorPanel.tsx +58 -49
- package/src/canvas/ScreenArtboard.tsx +107 -32
- package/src/main.tsx +71 -1
- package/src/runtime/MockNavigationContext.tsx +1460 -40
- package/src/runtime/reactNativeShim.ts +141 -0
- package/src/screens/ProductDetailScreen.tsx +32 -59
- package/src/server/astEngine.ts +10 -1
- package/src/styles.css +182 -21
- package/vite.config.ts +136 -67
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
import React, { createContext, useContext, useMemo, useEffect } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import React, { createContext, useContext, useMemo, useEffect, useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
TouchableOpacity,
|
|
4
|
+
TouchableHighlight,
|
|
5
|
+
TouchableWithoutFeedback,
|
|
6
|
+
Pressable,
|
|
7
|
+
View,
|
|
8
|
+
Text,
|
|
9
|
+
Image as RNImage,
|
|
10
|
+
ImageBackground as RNImageBackground,
|
|
11
|
+
ScrollView as RNScrollView,
|
|
12
|
+
FlatList as RNFlatList,
|
|
13
|
+
} from 'react-native';
|
|
3
14
|
|
|
4
15
|
export interface NavigationController {
|
|
5
16
|
navigate: (targetRoute: string, params?: Record<string, unknown>) => void;
|
|
@@ -9,6 +20,9 @@ export interface NavigationController {
|
|
|
9
20
|
back: () => void;
|
|
10
21
|
setOptions: (options?: Record<string, unknown>) => void;
|
|
11
22
|
canGoBack: () => boolean;
|
|
23
|
+
dispatch: (action?: unknown) => void;
|
|
24
|
+
reset: (state?: unknown) => void;
|
|
25
|
+
addListener: (event: string, callback: () => void) => () => void;
|
|
12
26
|
}
|
|
13
27
|
|
|
14
28
|
interface MockNavigationContextValue {
|
|
@@ -21,10 +35,12 @@ function normalizeNavTarget(raw: string): string {
|
|
|
21
35
|
const cleaned = String(raw ?? '')
|
|
22
36
|
.replace(/^\/+/, '')
|
|
23
37
|
.replace(/\([^)]+\)\/?/g, '')
|
|
38
|
+
.replace(/\[\.\.\.([^\]]+)\]/g, 'CatchAll_$1')
|
|
39
|
+
.replace(/\[([^\]]+)\]/g, 'By_$1')
|
|
24
40
|
.replace(/Screen$/, '')
|
|
25
41
|
.replace(/\/index$/, '');
|
|
26
42
|
if (!cleaned || cleaned === 'index') return 'Home';
|
|
27
|
-
if (cleaned.includes('-') || cleaned.includes('/') || cleaned === cleaned.toLowerCase()) {
|
|
43
|
+
if (cleaned.includes('-') || cleaned.includes('/') || cleaned.includes('_') || cleaned === cleaned.toLowerCase()) {
|
|
28
44
|
return cleaned
|
|
29
45
|
.split(/[-_/]/)
|
|
30
46
|
.filter(Boolean)
|
|
@@ -34,18 +50,23 @@ function normalizeNavTarget(raw: string): string {
|
|
|
34
50
|
return cleaned;
|
|
35
51
|
}
|
|
36
52
|
|
|
53
|
+
const noopNavigation: NavigationController = {
|
|
54
|
+
navigate: () => undefined,
|
|
55
|
+
goBack: () => undefined,
|
|
56
|
+
push: () => undefined,
|
|
57
|
+
replace: () => undefined,
|
|
58
|
+
back: () => undefined,
|
|
59
|
+
setOptions: () => undefined,
|
|
60
|
+
canGoBack: () => true,
|
|
61
|
+
dispatch: () => undefined,
|
|
62
|
+
reset: () => undefined,
|
|
63
|
+
addListener: () => () => undefined,
|
|
64
|
+
};
|
|
65
|
+
|
|
37
66
|
const MockNavigationContext = createContext<MockNavigationContextValue>({
|
|
38
67
|
currentRoute: 'Home',
|
|
39
68
|
params: {},
|
|
40
|
-
navigation:
|
|
41
|
-
navigate: () => undefined,
|
|
42
|
-
goBack: () => undefined,
|
|
43
|
-
push: () => undefined,
|
|
44
|
-
replace: () => undefined,
|
|
45
|
-
back: () => undefined,
|
|
46
|
-
setOptions: () => undefined,
|
|
47
|
-
canGoBack: () => true,
|
|
48
|
-
},
|
|
69
|
+
navigation: noopNavigation,
|
|
49
70
|
});
|
|
50
71
|
|
|
51
72
|
export interface MockNavigationProviderProps {
|
|
@@ -76,6 +97,9 @@ export const MockNavigationProvider: React.FC<MockNavigationProviderProps> = ({
|
|
|
76
97
|
back: () => onNavigate?.(routeName, 'Home'),
|
|
77
98
|
setOptions: () => undefined,
|
|
78
99
|
canGoBack: () => true,
|
|
100
|
+
dispatch: () => undefined,
|
|
101
|
+
reset: () => undefined,
|
|
102
|
+
addListener: () => () => undefined,
|
|
79
103
|
},
|
|
80
104
|
};
|
|
81
105
|
}, [routeName, params, onNavigate]);
|
|
@@ -87,7 +111,9 @@ export const MockNavigationProvider: React.FC<MockNavigationProviderProps> = ({
|
|
|
87
111
|
);
|
|
88
112
|
};
|
|
89
113
|
|
|
90
|
-
//
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// 1. React Navigation Shims (@react-navigation/native, native-stack, bottom-tabs)
|
|
116
|
+
// ============================================================================
|
|
91
117
|
export function useNavigation(): NavigationController {
|
|
92
118
|
return useContext(MockNavigationContext).navigation;
|
|
93
119
|
}
|
|
@@ -102,40 +128,113 @@ export function useRoute(): { key: string; name: string; params: Record<string,
|
|
|
102
128
|
}
|
|
103
129
|
|
|
104
130
|
export function useFocusEffect(effect: () => void | (() => void)): void {
|
|
131
|
+
const ctx = useContext(MockNavigationContext);
|
|
132
|
+
const effectRef = useRef(effect);
|
|
133
|
+
effectRef.current = effect;
|
|
105
134
|
useEffect(() => {
|
|
106
|
-
|
|
107
|
-
|
|
135
|
+
try {
|
|
136
|
+
const cleanup = effectRef.current();
|
|
137
|
+
return typeof cleanup === 'function' ? cleanup : undefined;
|
|
138
|
+
} catch {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
}, [ctx.currentRoute]);
|
|
108
142
|
}
|
|
109
143
|
|
|
110
144
|
export function useIsFocused(): boolean {
|
|
111
145
|
return true;
|
|
112
146
|
}
|
|
113
147
|
|
|
148
|
+
export function useScrollToTop(): void {}
|
|
149
|
+
|
|
114
150
|
export const NavigationContainer: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
115
151
|
<>{children}</>
|
|
116
152
|
);
|
|
117
153
|
|
|
118
|
-
|
|
154
|
+
export const CommonActions = {
|
|
155
|
+
navigate: (payload: unknown) => ({ type: 'NAVIGATE', payload }),
|
|
156
|
+
reset: (payload: unknown) => ({ type: 'RESET', payload }),
|
|
157
|
+
goBack: () => ({ type: 'GO_BACK' }),
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const StackActions = {
|
|
161
|
+
push: (routeName: string, params?: unknown) => ({ type: 'PUSH', payload: { routeName, params } }),
|
|
162
|
+
replace: (routeName: string, params?: unknown) => ({
|
|
163
|
+
type: 'REPLACE',
|
|
164
|
+
payload: { routeName, params },
|
|
165
|
+
}),
|
|
166
|
+
pop: (count = 1) => ({ type: 'POP', payload: { count } }),
|
|
167
|
+
popToTop: () => ({ type: 'POP_TO_TOP' }),
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
function createNavigatorShim() {
|
|
171
|
+
const Navigator: React.FC<{ children?: React.ReactNode }> = ({ children }) => <>{children}</>;
|
|
172
|
+
const Screen: React.FC<{ children?: React.ReactNode }> = ({ children }) => <>{children}</>;
|
|
173
|
+
const Group: React.FC<{ children?: React.ReactNode }> = ({ children }) => <>{children}</>;
|
|
174
|
+
return { Navigator, Screen, Group };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export const createNativeStackNavigator = createNavigatorShim;
|
|
178
|
+
export const createStackNavigator = createNavigatorShim;
|
|
179
|
+
export const createBottomTabNavigator = createNavigatorShim;
|
|
180
|
+
export const createDrawerNavigator = createNavigatorShim;
|
|
181
|
+
export const createMaterialTopTabNavigator = createNavigatorShim;
|
|
182
|
+
|
|
183
|
+
export const DefaultTheme = {
|
|
184
|
+
dark: false,
|
|
185
|
+
colors: {
|
|
186
|
+
primary: '#6366F1',
|
|
187
|
+
background: '#F8FAFC',
|
|
188
|
+
card: '#FFFFFF',
|
|
189
|
+
text: '#0F172A',
|
|
190
|
+
border: '#E2E8F0',
|
|
191
|
+
notification: '#EF4444',
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const DarkTheme = {
|
|
196
|
+
dark: true,
|
|
197
|
+
colors: {
|
|
198
|
+
primary: '#6366F1',
|
|
199
|
+
background: '#09090B',
|
|
200
|
+
card: '#18181B',
|
|
201
|
+
text: '#F8FAFC',
|
|
202
|
+
border: '#27272A',
|
|
203
|
+
notification: '#EF4444',
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const ThemeProvider: React.FC<{ value?: unknown; children?: React.ReactNode }> = ({
|
|
208
|
+
children,
|
|
209
|
+
}) => <>{children}</>;
|
|
210
|
+
|
|
211
|
+
export function useTheme() {
|
|
212
|
+
return DarkTheme;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function useNavigationContainerRef() {
|
|
216
|
+
return { current: noopNavigation, isReady: () => true };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// 2. Expo Router Shims (expo-router)
|
|
221
|
+
// ============================================================================
|
|
119
222
|
export function useRouter(): NavigationController {
|
|
120
223
|
return useContext(MockNavigationContext).navigation;
|
|
121
224
|
}
|
|
122
225
|
|
|
123
|
-
export const router: NavigationController =
|
|
124
|
-
navigate: () => undefined,
|
|
125
|
-
push: () => undefined,
|
|
126
|
-
replace: () => undefined,
|
|
127
|
-
goBack: () => undefined,
|
|
128
|
-
back: () => undefined,
|
|
129
|
-
setOptions: () => undefined,
|
|
130
|
-
canGoBack: () => true,
|
|
131
|
-
};
|
|
226
|
+
export const router: NavigationController = noopNavigation;
|
|
132
227
|
|
|
133
|
-
export function useLocalSearchParams<
|
|
228
|
+
export function useLocalSearchParams<
|
|
229
|
+
T extends Record<string, unknown> = Record<string, string>
|
|
230
|
+
>(): T {
|
|
134
231
|
const ctx = useContext(MockNavigationContext);
|
|
135
232
|
return ctx.params as T;
|
|
136
233
|
}
|
|
137
234
|
|
|
138
|
-
export function useGlobalSearchParams<
|
|
235
|
+
export function useGlobalSearchParams<
|
|
236
|
+
T extends Record<string, unknown> = Record<string, string>
|
|
237
|
+
>(): T {
|
|
139
238
|
const ctx = useContext(MockNavigationContext);
|
|
140
239
|
return ctx.params as T;
|
|
141
240
|
}
|
|
@@ -147,7 +246,11 @@ export function usePathname(): string {
|
|
|
147
246
|
|
|
148
247
|
export function useSegments(): string[] {
|
|
149
248
|
const ctx = useContext(MockNavigationContext);
|
|
150
|
-
return [ctx.currentRoute.toLowerCase()];
|
|
249
|
+
return useMemo(() => [ctx.currentRoute.toLowerCase()], [ctx.currentRoute]);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function useRootNavigationState() {
|
|
253
|
+
return { key: 'root', stale: false };
|
|
151
254
|
}
|
|
152
255
|
|
|
153
256
|
export const Link: React.FC<{
|
|
@@ -157,7 +260,7 @@ export const Link: React.FC<{
|
|
|
157
260
|
style?: unknown;
|
|
158
261
|
}> = ({ href, children, style }) => {
|
|
159
262
|
const nav = useContext(MockNavigationContext).navigation;
|
|
160
|
-
const target = typeof href === 'string' ? href : href
|
|
263
|
+
const target = typeof href === 'string' ? href : href?.pathname ?? 'Home';
|
|
161
264
|
return (
|
|
162
265
|
<TouchableOpacity
|
|
163
266
|
activeOpacity={0.78}
|
|
@@ -169,31 +272,1348 @@ export const Link: React.FC<{
|
|
|
169
272
|
);
|
|
170
273
|
};
|
|
171
274
|
|
|
172
|
-
const
|
|
275
|
+
export const Redirect: React.FC<{ href: string }> = () => null;
|
|
276
|
+
|
|
277
|
+
const NoopLayoutScreen: React.FC<{ children?: React.ReactNode; screenOptions?: unknown }> & {
|
|
173
278
|
Screen: React.FC<{ name?: string; options?: unknown }>;
|
|
174
|
-
} = ({ children }
|
|
279
|
+
} = ({ children }) => <>{children}</>;
|
|
175
280
|
NoopLayoutScreen.Screen = () => null;
|
|
176
281
|
|
|
177
282
|
export const Stack = NoopLayoutScreen;
|
|
178
283
|
export const Tabs = NoopLayoutScreen;
|
|
284
|
+
export const Drawer = NoopLayoutScreen;
|
|
179
285
|
export const Slot: React.FC<{ children?: React.ReactNode }> = ({ children }) => <>{children}</>;
|
|
286
|
+
export const SplashScreen = {
|
|
287
|
+
preventAutoHideAsync: async () => true,
|
|
288
|
+
hideAsync: async () => true,
|
|
289
|
+
};
|
|
180
290
|
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
291
|
+
// ============================================================================
|
|
292
|
+
// 3. React Native Safe Area Context Shims (react-native-safe-area-context)
|
|
293
|
+
// ============================================================================
|
|
294
|
+
export const SafeAreaProvider: React.FC<{ children?: React.ReactNode; style?: unknown }> = ({
|
|
295
|
+
children,
|
|
296
|
+
style,
|
|
297
|
+
}) => <View style={[{ flex: 1 }, style as never]}>{children}</View>;
|
|
185
298
|
|
|
186
299
|
export const SafeAreaView: React.FC<{
|
|
187
300
|
children?: React.ReactNode;
|
|
188
301
|
style?: unknown;
|
|
189
302
|
edges?: string[];
|
|
190
|
-
}> = ({ children, style }) =>
|
|
191
|
-
<View style={[{ flex: 1 }, style as never]}>{children}</View>
|
|
192
|
-
);
|
|
303
|
+
}> = ({ children, style }) => <View style={[{ flex: 1 }, style as never]}>{children}</View>;
|
|
193
304
|
|
|
194
305
|
export function useSafeAreaInsets(): { top: number; right: number; bottom: number; left: number } {
|
|
195
306
|
return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
196
307
|
}
|
|
197
308
|
|
|
198
|
-
|
|
199
|
-
|
|
309
|
+
export function useSafeAreaFrame(): { x: number; y: number; width: number; height: number } {
|
|
310
|
+
return { x: 0, y: 0, width: 393, height: 852 };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export const SafeAreaInsetsContext = createContext({ top: 0, right: 0, bottom: 0, left: 0 });
|
|
314
|
+
export const SafeAreaFrameContext = createContext({ x: 0, y: 0, width: 393, height: 852 });
|
|
315
|
+
|
|
316
|
+
export function withSafeAreaInsets<P extends object>(Component: React.ComponentType<P>) {
|
|
317
|
+
return function WithSafeAreaInsetsWrapper(props: P) {
|
|
318
|
+
return <Component {...props} insets={{ top: 0, right: 0, bottom: 0, left: 0 }} />;
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export const initialWindowMetrics = {
|
|
323
|
+
frame: { x: 0, y: 0, width: 393, height: 852 },
|
|
324
|
+
insets: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// ============================================================================
|
|
328
|
+
// 4. Expo Status Bar Shim (expo-status-bar)
|
|
329
|
+
// ============================================================================
|
|
330
|
+
export const StatusBar: React.FC<{
|
|
331
|
+
style?: string;
|
|
332
|
+
hidden?: boolean;
|
|
333
|
+
backgroundColor?: string;
|
|
334
|
+
translucent?: boolean;
|
|
335
|
+
}> = () => null;
|
|
336
|
+
|
|
337
|
+
// ============================================================================
|
|
338
|
+
// 5. @expo/vector-icons Shims
|
|
339
|
+
// ============================================================================
|
|
340
|
+
export interface VectorIconProps {
|
|
341
|
+
name?: string;
|
|
342
|
+
size?: number;
|
|
343
|
+
color?: string;
|
|
344
|
+
style?: unknown;
|
|
345
|
+
onPress?: () => void;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const ICON_GLYPH_MAP: Record<string, string> = {
|
|
349
|
+
'arrow-back': '←',
|
|
350
|
+
'arrow-left': '←',
|
|
351
|
+
'chevron-back': '‹',
|
|
352
|
+
'chevron-left': '‹',
|
|
353
|
+
'arrow-forward': '→',
|
|
354
|
+
'arrow-right': '→',
|
|
355
|
+
'chevron-forward': '›',
|
|
356
|
+
'chevron-right': '›',
|
|
357
|
+
'chevron-down': '▾',
|
|
358
|
+
'chevron-up': '▴',
|
|
359
|
+
close: '✕',
|
|
360
|
+
'close-circle': '⊗',
|
|
361
|
+
x: '✕',
|
|
362
|
+
add: '+',
|
|
363
|
+
plus: '+',
|
|
364
|
+
'add-circle': '⊕',
|
|
365
|
+
remove: '−',
|
|
366
|
+
minus: '−',
|
|
367
|
+
check: '✓',
|
|
368
|
+
checkmark: '✓',
|
|
369
|
+
'checkmark-circle': '✓',
|
|
370
|
+
search: '⌕',
|
|
371
|
+
home: '⌂',
|
|
372
|
+
person: '◉',
|
|
373
|
+
user: '◉',
|
|
374
|
+
settings: '⚙',
|
|
375
|
+
cog: '⚙',
|
|
376
|
+
bell: '🔔',
|
|
377
|
+
notifications: '🔔',
|
|
378
|
+
heart: '♥',
|
|
379
|
+
'heart-outline': '♡',
|
|
380
|
+
star: '★',
|
|
381
|
+
'star-outline': '☆',
|
|
382
|
+
cart: '🛒',
|
|
383
|
+
'shopping-cart': '🛒',
|
|
384
|
+
bag: '🛍',
|
|
385
|
+
lock: '🔒',
|
|
386
|
+
'lock-closed': '🔒',
|
|
387
|
+
mail: '✉',
|
|
388
|
+
eye: '👁',
|
|
389
|
+
'eye-off': '◡',
|
|
390
|
+
trash: '🗑',
|
|
391
|
+
edit: '✎',
|
|
392
|
+
pencil: '✎',
|
|
393
|
+
share: '↗',
|
|
394
|
+
info: 'ℹ',
|
|
395
|
+
warning: '⚠',
|
|
396
|
+
alert: '⚠',
|
|
397
|
+
menu: '☰',
|
|
398
|
+
filter: '⊶',
|
|
399
|
+
calendar: '📅',
|
|
400
|
+
time: '⏱',
|
|
401
|
+
clock: '⏱',
|
|
402
|
+
location: '⌖',
|
|
403
|
+
'map-pin': '⌖',
|
|
404
|
+
camera: '📷',
|
|
405
|
+
image: '🖼',
|
|
406
|
+
send: '➤',
|
|
407
|
+
refresh: '↻',
|
|
408
|
+
sync: '↻',
|
|
409
|
+
wallet: '💳',
|
|
410
|
+
card: '💳',
|
|
411
|
+
cash: '¤',
|
|
412
|
+
'trending-up': '↗',
|
|
413
|
+
'trending-down': '↘',
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
export function createVectorIconComponent(familyName: string) {
|
|
417
|
+
const IconComp: React.FC<VectorIconProps> & {
|
|
418
|
+
glyphMap?: Record<string, number>;
|
|
419
|
+
loadFont?: () => Promise<void>;
|
|
420
|
+
} = ({ name = '', size = 18, color = '#94A3B8', style, onPress }) => {
|
|
421
|
+
const cleanName = String(name)
|
|
422
|
+
.toLowerCase()
|
|
423
|
+
.replace(/^ios-|^md-|^logo-/, '')
|
|
424
|
+
.replace(/-outline$|-sharp$/, '');
|
|
425
|
+
const symbol = ICON_GLYPH_MAP[String(name).toLowerCase()] ?? ICON_GLYPH_MAP[cleanName] ?? '◆';
|
|
426
|
+
return (
|
|
427
|
+
<Text
|
|
428
|
+
onPress={onPress}
|
|
429
|
+
accessibilityLabel={`${familyName}:${name}`}
|
|
430
|
+
style={[
|
|
431
|
+
{
|
|
432
|
+
fontSize: size * 0.85,
|
|
433
|
+
lineHeight: size,
|
|
434
|
+
width: size,
|
|
435
|
+
height: size,
|
|
436
|
+
color,
|
|
437
|
+
textAlign: 'center',
|
|
438
|
+
includeFontPadding: false,
|
|
439
|
+
} as never,
|
|
440
|
+
style as never,
|
|
441
|
+
]}
|
|
442
|
+
>
|
|
443
|
+
{symbol}
|
|
444
|
+
</Text>
|
|
445
|
+
);
|
|
446
|
+
};
|
|
447
|
+
IconComp.glyphMap = {};
|
|
448
|
+
IconComp.loadFont = async () => undefined;
|
|
449
|
+
return IconComp;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export const Ionicons = createVectorIconComponent('Ionicons');
|
|
453
|
+
export const Feather = createVectorIconComponent('Feather');
|
|
454
|
+
export const MaterialIcons = createVectorIconComponent('MaterialIcons');
|
|
455
|
+
export const MaterialCommunityIcons = createVectorIconComponent('MaterialCommunityIcons');
|
|
456
|
+
export const FontAwesome = createVectorIconComponent('FontAwesome');
|
|
457
|
+
export const FontAwesome5 = createVectorIconComponent('FontAwesome5');
|
|
458
|
+
export const FontAwesome6 = createVectorIconComponent('FontAwesome6');
|
|
459
|
+
export const AntDesign = createVectorIconComponent('AntDesign');
|
|
460
|
+
export const Entypo = createVectorIconComponent('Entypo');
|
|
461
|
+
export const EvilIcons = createVectorIconComponent('EvilIcons');
|
|
462
|
+
export const Foundation = createVectorIconComponent('Foundation');
|
|
463
|
+
export const Octicons = createVectorIconComponent('Octicons');
|
|
464
|
+
export const SimpleLineIcons = createVectorIconComponent('SimpleLineIcons');
|
|
465
|
+
export const Zocial = createVectorIconComponent('Zocial');
|
|
466
|
+
export const Fontisto = createVectorIconComponent('Fontisto');
|
|
467
|
+
export function createIconSet() {
|
|
468
|
+
return createVectorIconComponent('CustomIcon');
|
|
469
|
+
}
|
|
470
|
+
export function createIconSetFromIcoMoon() {
|
|
471
|
+
return createVectorIconComponent('IcoMoon');
|
|
472
|
+
}
|
|
473
|
+
export function createIconSetFromFontello() {
|
|
474
|
+
return createVectorIconComponent('Fontello');
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// ============================================================================
|
|
478
|
+
// 6. Expo Linear Gradient, Blur, Image & FlashList Shims
|
|
479
|
+
// ============================================================================
|
|
480
|
+
export const LinearGradient: React.FC<{
|
|
481
|
+
colors?: string[];
|
|
482
|
+
locations?: number[];
|
|
483
|
+
start?: { x: number; y: number } | [number, number];
|
|
484
|
+
end?: { x: number; y: number } | [number, number];
|
|
485
|
+
style?: unknown;
|
|
486
|
+
children?: React.ReactNode;
|
|
487
|
+
}> = ({ colors = ['#1E293B', '#0F172A'], style, children }) => {
|
|
488
|
+
const safeColors = Array.isArray(colors) && colors.length >= 2 ? colors : ['#1E293B', '#0F172A'];
|
|
489
|
+
return (
|
|
490
|
+
<View
|
|
491
|
+
style={[
|
|
492
|
+
{
|
|
493
|
+
backgroundColor: safeColors[0],
|
|
494
|
+
backgroundImage: `linear-gradient(135deg, ${safeColors.join(', ')})`,
|
|
495
|
+
} as never,
|
|
496
|
+
style as never,
|
|
497
|
+
]}
|
|
498
|
+
>
|
|
499
|
+
{children}
|
|
500
|
+
</View>
|
|
501
|
+
);
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
export const BlurView: React.FC<{
|
|
505
|
+
intensity?: number;
|
|
506
|
+
tint?: string;
|
|
507
|
+
style?: unknown;
|
|
508
|
+
children?: React.ReactNode;
|
|
509
|
+
}> = ({ intensity = 40, tint = 'dark', style, children }) => {
|
|
510
|
+
const bg = tint === 'light' ? 'rgba(255, 255, 255, 0.65)' : 'rgba(15, 23, 42, 0.65)';
|
|
511
|
+
return (
|
|
512
|
+
<View
|
|
513
|
+
style={[
|
|
514
|
+
{
|
|
515
|
+
backgroundColor: bg,
|
|
516
|
+
backdropFilter: `blur(${Math.round(intensity / 4)}px)`,
|
|
517
|
+
} as never,
|
|
518
|
+
style as never,
|
|
519
|
+
]}
|
|
520
|
+
>
|
|
521
|
+
{children}
|
|
522
|
+
</View>
|
|
523
|
+
);
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
export const Image: React.FC<Record<string, unknown>> = ({
|
|
527
|
+
contentFit,
|
|
528
|
+
resizeMode,
|
|
529
|
+
source,
|
|
530
|
+
...rest
|
|
531
|
+
}) => {
|
|
532
|
+
const resolvedSource = typeof source === 'string' ? { uri: source } : source;
|
|
533
|
+
return (
|
|
534
|
+
<RNImage
|
|
535
|
+
source={resolvedSource as never}
|
|
536
|
+
resizeMode={(contentFit ?? resizeMode ?? 'cover') as never}
|
|
537
|
+
{...(rest as Record<string, unknown>)}
|
|
538
|
+
/>
|
|
539
|
+
);
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
export const ImageBackground = RNImageBackground;
|
|
543
|
+
export const FlashList = RNFlatList;
|
|
544
|
+
|
|
545
|
+
// ============================================================================
|
|
546
|
+
// 7. React Native SVG Shims (react-native-svg)
|
|
547
|
+
// ============================================================================
|
|
548
|
+
function createSvgDomElement(tagName: string) {
|
|
549
|
+
return React.forwardRef< Element, Record<string, unknown>>(({ children, ...props }, ref) =>
|
|
550
|
+
React.createElement(tagName, { ...props, ref }, children as React.ReactNode)
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export const Svg = createSvgDomElement('svg');
|
|
555
|
+
export const Circle = createSvgDomElement('circle');
|
|
556
|
+
export const Ellipse = createSvgDomElement('ellipse');
|
|
557
|
+
export const G = createSvgDomElement('g');
|
|
558
|
+
export const SvgText = createSvgDomElement('text');
|
|
559
|
+
export const TSpan = createSvgDomElement('tspan');
|
|
560
|
+
export const TextPath = createSvgDomElement('textPath');
|
|
561
|
+
export const Path = createSvgDomElement('path');
|
|
562
|
+
export const Polygon = createSvgDomElement('polygon');
|
|
563
|
+
export const Polyline = createSvgDomElement('polyline');
|
|
564
|
+
export const Line = createSvgDomElement('line');
|
|
565
|
+
export const Rect = createSvgDomElement('rect');
|
|
566
|
+
export const Use = createSvgDomElement('use');
|
|
567
|
+
export const SvgImage = createSvgDomElement('image');
|
|
568
|
+
export const Symbol = createSvgDomElement('symbol');
|
|
569
|
+
export const Defs = createSvgDomElement('defs');
|
|
570
|
+
export const RadialGradient = createSvgDomElement('radialGradient');
|
|
571
|
+
export const Stop = createSvgDomElement('stop');
|
|
572
|
+
export const ClipPath = createSvgDomElement('clipPath');
|
|
573
|
+
export const Pattern = createSvgDomElement('pattern');
|
|
574
|
+
export const Mask = createSvgDomElement('mask');
|
|
575
|
+
export const ForeignObject = createSvgDomElement('foreignObject');
|
|
576
|
+
export const SvgXml: React.FC<{ xml?: string; width?: number | string; height?: number | string }> =
|
|
577
|
+
({ xml = '', width = 24, height = 24 }) => (
|
|
578
|
+
<span
|
|
579
|
+
style={{ display: 'inline-flex', width, height }}
|
|
580
|
+
dangerouslySetInnerHTML={{ __html: xml }}
|
|
581
|
+
/>
|
|
582
|
+
);
|
|
583
|
+
export const SvgUri: React.FC<{ uri?: string; width?: number; height?: number }> = ({
|
|
584
|
+
uri,
|
|
585
|
+
width = 24,
|
|
586
|
+
height = 24,
|
|
587
|
+
}) => <RNImage source={{ uri }} style={{ width, height }} />;
|
|
588
|
+
|
|
589
|
+
// ============================================================================
|
|
590
|
+
// 8. React Native Reanimated & Gesture Handler Shims
|
|
591
|
+
// ============================================================================
|
|
592
|
+
function createChainableAnimationStub(): Record<string, unknown> {
|
|
593
|
+
const proxy: Record<string, unknown> = new Proxy(
|
|
594
|
+
{},
|
|
595
|
+
{
|
|
596
|
+
get(_target, prop) {
|
|
597
|
+
if (prop === 'build') return () => ({});
|
|
598
|
+
return () => proxy;
|
|
599
|
+
},
|
|
600
|
+
}
|
|
601
|
+
);
|
|
602
|
+
return proxy;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export const FadeIn = createChainableAnimationStub();
|
|
606
|
+
export const FadeInDown = createChainableAnimationStub();
|
|
607
|
+
export const FadeInUp = createChainableAnimationStub();
|
|
608
|
+
export const FadeInLeft = createChainableAnimationStub();
|
|
609
|
+
export const FadeInRight = createChainableAnimationStub();
|
|
610
|
+
export const FadeOut = createChainableAnimationStub();
|
|
611
|
+
export const FadeOutDown = createChainableAnimationStub();
|
|
612
|
+
export const FadeOutUp = createChainableAnimationStub();
|
|
613
|
+
export const SlideInDown = createChainableAnimationStub();
|
|
614
|
+
export const SlideInUp = createChainableAnimationStub();
|
|
615
|
+
export const SlideInLeft = createChainableAnimationStub();
|
|
616
|
+
export const SlideInRight = createChainableAnimationStub();
|
|
617
|
+
export const SlideOutDown = createChainableAnimationStub();
|
|
618
|
+
export const SlideOutUp = createChainableAnimationStub();
|
|
619
|
+
export const SlideOutLeft = createChainableAnimationStub();
|
|
620
|
+
export const SlideOutRight = createChainableAnimationStub();
|
|
621
|
+
export const ZoomIn = createChainableAnimationStub();
|
|
622
|
+
export const ZoomOut = createChainableAnimationStub();
|
|
623
|
+
export const Layout = createChainableAnimationStub();
|
|
624
|
+
export const LinearTransition = createChainableAnimationStub();
|
|
625
|
+
export const SequencedTransition = createChainableAnimationStub();
|
|
626
|
+
export const FadingTransition = createChainableAnimationStub();
|
|
627
|
+
|
|
628
|
+
export function useSharedValue<T>(initialValue: T): { value: T } {
|
|
629
|
+
const ref = useRef<{ value: T }>({ value: initialValue });
|
|
630
|
+
return ref.current;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
export function useAnimatedStyle<T extends Record<string, unknown>>(
|
|
634
|
+
updater: () => T
|
|
635
|
+
): T {
|
|
636
|
+
try {
|
|
637
|
+
return updater();
|
|
638
|
+
} catch {
|
|
639
|
+
return {} as T;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
export function useDerivedValue<T>(updater: () => T): { value: T } {
|
|
644
|
+
try {
|
|
645
|
+
return { value: updater() };
|
|
646
|
+
} catch {
|
|
647
|
+
return { value: undefined as unknown as T };
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
export function useAnimatedProps<T extends Record<string, unknown>>(updater: () => T): T {
|
|
652
|
+
try {
|
|
653
|
+
return updater();
|
|
654
|
+
} catch {
|
|
655
|
+
return {} as T;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
export function useAnimatedScrollHandler() {
|
|
660
|
+
return () => undefined;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export function useAnimatedRef() {
|
|
664
|
+
return useRef(null);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
export function useAnimatedGestureHandler() {
|
|
668
|
+
return () => undefined;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
export function withTiming<T>(toValue: T, _config?: unknown, callback?: (finished: boolean) => void): T {
|
|
672
|
+
callback?.(true);
|
|
673
|
+
return toValue;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
export function withSpring<T>(toValue: T, _config?: unknown, callback?: (finished: boolean) => void): T {
|
|
677
|
+
callback?.(true);
|
|
678
|
+
return toValue;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
export function withDelay<T>(_delayMs: number, animationValue: T): T {
|
|
682
|
+
return animationValue;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export function withSequence<T>(...animations: T[]): T {
|
|
686
|
+
return animations[animations.length - 1];
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
export function withRepeat<T>(animationValue: T): T {
|
|
690
|
+
return animationValue;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
export function cancelAnimation(): void {}
|
|
694
|
+
|
|
695
|
+
export function runOnJS<T extends (...args: never[]) => unknown>(fn: T): T {
|
|
696
|
+
return fn;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export function runOnUI<T extends (...args: never[]) => unknown>(fn: T): T {
|
|
700
|
+
return fn;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
export function interpolate(
|
|
704
|
+
value: number,
|
|
705
|
+
inputRange: number[],
|
|
706
|
+
outputRange: number[]
|
|
707
|
+
): number {
|
|
708
|
+
if (!inputRange?.length || !outputRange?.length) return value;
|
|
709
|
+
if (value <= inputRange[0]) return outputRange[0];
|
|
710
|
+
if (value >= inputRange[inputRange.length - 1]) return outputRange[outputRange.length - 1];
|
|
711
|
+
return outputRange[0];
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
export const Extrapolation = {
|
|
715
|
+
IDENTITY: 'identity',
|
|
716
|
+
CLAMP: 'clamp',
|
|
717
|
+
EXTEND: 'extend',
|
|
718
|
+
};
|
|
719
|
+
export const Extrapolate = Extrapolation;
|
|
720
|
+
|
|
721
|
+
export const Easing = {
|
|
722
|
+
linear: (t: number) => t,
|
|
723
|
+
ease: (t: number) => t,
|
|
724
|
+
quad: (t: number) => t * t,
|
|
725
|
+
cubic: (t: number) => t * t * t,
|
|
726
|
+
bezier: () => (t: number) => t,
|
|
727
|
+
in: (fn: (t: number) => number) => fn,
|
|
728
|
+
out: (fn: (t: number) => number) => fn,
|
|
729
|
+
inOut: (fn: (t: number) => number) => fn,
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
export function createAnimatedComponent<P extends object>(Component: React.ComponentType<P>) {
|
|
733
|
+
return Component;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
export const Animated = {
|
|
737
|
+
View,
|
|
738
|
+
Text,
|
|
739
|
+
Image: RNImage,
|
|
740
|
+
ScrollView: RNScrollView,
|
|
741
|
+
FlatList: RNFlatList,
|
|
742
|
+
createAnimatedComponent,
|
|
743
|
+
Value: class {
|
|
744
|
+
private _val: number;
|
|
745
|
+
constructor(v = 0) {
|
|
746
|
+
this._val = v;
|
|
747
|
+
}
|
|
748
|
+
setValue(v: number) {
|
|
749
|
+
this._val = v;
|
|
750
|
+
}
|
|
751
|
+
interpolate() {
|
|
752
|
+
return this._val;
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
// React Native Gesture Handler Shims
|
|
758
|
+
export const GestureHandlerRootView: React.FC<{ children?: React.ReactNode; style?: unknown }> = ({
|
|
759
|
+
children,
|
|
760
|
+
style,
|
|
761
|
+
}) => <View style={[{ flex: 1 }, style as never]}>{children}</View>;
|
|
762
|
+
|
|
763
|
+
export const ScrollView = RNScrollView;
|
|
764
|
+
export const FlatList = RNFlatList;
|
|
765
|
+
export { TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback, Pressable };
|
|
766
|
+
export const Swipeable: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
767
|
+
<>{children}</>
|
|
768
|
+
);
|
|
769
|
+
export const DrawerLayout: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
770
|
+
<>{children}</>
|
|
771
|
+
);
|
|
772
|
+
export const PanGestureHandler: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
773
|
+
<>{children}</>
|
|
774
|
+
);
|
|
775
|
+
export const TapGestureHandler: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
776
|
+
<>{children}</>
|
|
777
|
+
);
|
|
778
|
+
export const LongPressGestureHandler: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
779
|
+
<>{children}</>
|
|
780
|
+
);
|
|
781
|
+
export const GestureDetector: React.FC<{ gesture?: unknown; children?: React.ReactNode }> = ({
|
|
782
|
+
children,
|
|
783
|
+
}) => <>{children}</>;
|
|
784
|
+
export const Gesture = {
|
|
785
|
+
Pan: () => createChainableAnimationStub(),
|
|
786
|
+
Tap: () => createChainableAnimationStub(),
|
|
787
|
+
LongPress: () => createChainableAnimationStub(),
|
|
788
|
+
Pinch: () => createChainableAnimationStub(),
|
|
789
|
+
Rotation: () => createChainableAnimationStub(),
|
|
790
|
+
Fling: () => createChainableAnimationStub(),
|
|
791
|
+
Simultaneous: () => createChainableAnimationStub(),
|
|
792
|
+
Exclusive: () => createChainableAnimationStub(),
|
|
793
|
+
Race: () => createChainableAnimationStub(),
|
|
794
|
+
};
|
|
795
|
+
export const State = {
|
|
796
|
+
UNDETERMINED: 0,
|
|
797
|
+
FAILED: 1,
|
|
798
|
+
BEGAN: 2,
|
|
799
|
+
CANCELLED: 3,
|
|
800
|
+
ACTIVE: 4,
|
|
801
|
+
END: 5,
|
|
802
|
+
};
|
|
803
|
+
export const Directions = {
|
|
804
|
+
RIGHT: 1,
|
|
805
|
+
LEFT: 2,
|
|
806
|
+
UP: 4,
|
|
807
|
+
DOWN: 8,
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
// ============================================================================
|
|
811
|
+
// 9. Common Expo SDK Runtime Shims (Haptics, Constants, Font, Storage, etc.)
|
|
812
|
+
// ============================================================================
|
|
813
|
+
export const ImpactFeedbackStyle = { Light: 'light', Medium: 'medium', Heavy: 'heavy' };
|
|
814
|
+
export const NotificationFeedbackType = {
|
|
815
|
+
Success: 'success',
|
|
816
|
+
Warning: 'warning',
|
|
817
|
+
Error: 'error',
|
|
818
|
+
};
|
|
819
|
+
export async function impactAsync(): Promise<void> {}
|
|
820
|
+
export async function notificationAsync(): Promise<void> {}
|
|
821
|
+
export async function selectionAsync(): Promise<void> {}
|
|
822
|
+
|
|
823
|
+
export const Constants = {
|
|
824
|
+
expoConfig: { name: 'Zelune App', slug: 'zelune-app', extra: {} },
|
|
825
|
+
manifest: { extra: {} },
|
|
826
|
+
statusBarHeight: 0,
|
|
827
|
+
systemFonts: [],
|
|
828
|
+
appOwnership: 'expo',
|
|
829
|
+
executionEnvironment: 'storeClient',
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
export function useFonts(): [boolean, null] {
|
|
833
|
+
return [true, null];
|
|
834
|
+
}
|
|
835
|
+
export async function loadAsync(): Promise<void> {}
|
|
836
|
+
export function isLoaded(): boolean {
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
export async function preventAutoHideAsync(): Promise<boolean> {
|
|
840
|
+
return true;
|
|
841
|
+
}
|
|
842
|
+
export async function hideAsync(): Promise<boolean> {
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const memoryStorage = new Map<string, string>();
|
|
847
|
+
export const AsyncStorage = {
|
|
848
|
+
getItem: async (key: string) => memoryStorage.get(key) ?? null,
|
|
849
|
+
setItem: async (key: string, value: string) => {
|
|
850
|
+
memoryStorage.set(key, value);
|
|
851
|
+
},
|
|
852
|
+
removeItem: async (key: string) => {
|
|
853
|
+
memoryStorage.delete(key);
|
|
854
|
+
},
|
|
855
|
+
clear: async () => {
|
|
856
|
+
memoryStorage.clear();
|
|
857
|
+
},
|
|
858
|
+
getAllKeys: async () => Array.from(memoryStorage.keys()),
|
|
859
|
+
multiGet: async (keys: string[]) => keys.map((k) => [k, memoryStorage.get(k) ?? null]),
|
|
860
|
+
multiSet: async (pairs: [string, string][]) => {
|
|
861
|
+
pairs.forEach(([k, v]) => memoryStorage.set(k, v));
|
|
862
|
+
},
|
|
863
|
+
multiRemove: async (keys: string[]) => {
|
|
864
|
+
keys.forEach((k) => memoryStorage.delete(k));
|
|
865
|
+
},
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
export async function getItemAsync(key: string): Promise<string | null> {
|
|
869
|
+
return memoryStorage.get(key) ?? null;
|
|
870
|
+
}
|
|
871
|
+
export async function setItemAsync(key: string, value: string): Promise<void> {
|
|
872
|
+
memoryStorage.set(key, value);
|
|
873
|
+
}
|
|
874
|
+
export async function deleteItemAsync(key: string): Promise<void> {
|
|
875
|
+
memoryStorage.delete(key);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
export async function setStringAsync(): Promise<boolean> {
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
881
|
+
export async function getStringAsync(): Promise<string> {
|
|
882
|
+
return '';
|
|
883
|
+
}
|
|
884
|
+
export async function openURL(url: string): Promise<boolean> {
|
|
885
|
+
if (typeof window !== 'undefined') {
|
|
886
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
887
|
+
}
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
export function createURL(pathStr = ''): string {
|
|
891
|
+
return `/${String(pathStr).replace(/^\/+/, '')}`;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// ============================================================================
|
|
895
|
+
// 10. State Management, Data Fetching & Backend Client Shims
|
|
896
|
+
// (Zustand, TanStack React Query, Supabase Client)
|
|
897
|
+
// ============================================================================
|
|
898
|
+
export function create(initializer?: unknown): unknown {
|
|
899
|
+
if (typeof initializer !== 'function') {
|
|
900
|
+
return (curriedInitializer: unknown) => create(curriedInitializer);
|
|
901
|
+
}
|
|
902
|
+
let state: Record<string, unknown> = {};
|
|
903
|
+
const setState = (partial: unknown) => {
|
|
904
|
+
try {
|
|
905
|
+
const next =
|
|
906
|
+
typeof partial === 'function' ? (partial as (s: unknown) => unknown)(state) : partial;
|
|
907
|
+
if (next && typeof next === 'object') {
|
|
908
|
+
state = { ...state, ...(next as Record<string, unknown>) };
|
|
909
|
+
}
|
|
910
|
+
} catch {
|
|
911
|
+
// Ignore setter errors in static canvas preview
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
const getState = () => state;
|
|
915
|
+
const api = {
|
|
916
|
+
setState,
|
|
917
|
+
getState,
|
|
918
|
+
getInitialState: () => state,
|
|
919
|
+
subscribe: () => () => undefined,
|
|
920
|
+
destroy: () => undefined,
|
|
921
|
+
};
|
|
922
|
+
try {
|
|
923
|
+
const initial = (
|
|
924
|
+
initializer as (
|
|
925
|
+
set: typeof setState,
|
|
926
|
+
get: typeof getState,
|
|
927
|
+
store: typeof api
|
|
928
|
+
) => Record<string, unknown>
|
|
929
|
+
)(setState, getState, api);
|
|
930
|
+
if (initial && typeof initial === 'object') {
|
|
931
|
+
state = initial;
|
|
932
|
+
}
|
|
933
|
+
} catch {
|
|
934
|
+
state = {};
|
|
935
|
+
}
|
|
936
|
+
const useBoundStore = (selector?: (s: Record<string, unknown>) => unknown) => {
|
|
937
|
+
if (typeof selector === 'function') {
|
|
938
|
+
try {
|
|
939
|
+
return selector(state);
|
|
940
|
+
} catch {
|
|
941
|
+
return undefined;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return state;
|
|
945
|
+
};
|
|
946
|
+
return Object.assign(useBoundStore, api);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
export function useStore(
|
|
950
|
+
store: { getState?: () => Record<string, unknown> } | ((s?: unknown) => unknown),
|
|
951
|
+
selector?: (s: Record<string, unknown>) => unknown
|
|
952
|
+
) {
|
|
953
|
+
const rawState =
|
|
954
|
+
typeof store === 'function'
|
|
955
|
+
? (store as () => Record<string, unknown>)()
|
|
956
|
+
: store?.getState?.() ?? {};
|
|
957
|
+
return typeof selector === 'function' ? selector(rawState) : rawState;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
export class QueryClient {
|
|
961
|
+
mount() {}
|
|
962
|
+
unmount() {}
|
|
963
|
+
clear() {}
|
|
964
|
+
getQueryData() {
|
|
965
|
+
return undefined;
|
|
966
|
+
}
|
|
967
|
+
setQueryData() {}
|
|
968
|
+
invalidateQueries() {
|
|
969
|
+
return Promise.resolve();
|
|
970
|
+
}
|
|
971
|
+
prefetchQuery() {
|
|
972
|
+
return Promise.resolve();
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
export const QueryClientProvider: React.FC<{ client?: unknown; children?: React.ReactNode }> = ({
|
|
977
|
+
children,
|
|
978
|
+
}) => <>{children}</>;
|
|
979
|
+
|
|
980
|
+
const singletonQueryClient = new QueryClient();
|
|
981
|
+
|
|
982
|
+
export function useQueryClient() {
|
|
983
|
+
return singletonQueryClient;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
const STABLE_EMPTY_ARRAY: unknown[] = [];
|
|
987
|
+
|
|
988
|
+
const STABLE_QUERY_RESULT = {
|
|
989
|
+
data: undefined,
|
|
990
|
+
error: null,
|
|
991
|
+
isLoading: false,
|
|
992
|
+
isPending: false,
|
|
993
|
+
isFetching: false,
|
|
994
|
+
isError: false,
|
|
995
|
+
isSuccess: true,
|
|
996
|
+
status: 'success',
|
|
997
|
+
refetch: async () => ({ data: undefined, error: null }),
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
export function useQuery() {
|
|
1001
|
+
return STABLE_QUERY_RESULT;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
const STABLE_INFINITE_QUERY_RESULT = {
|
|
1005
|
+
data: { pages: STABLE_EMPTY_ARRAY, pageParams: STABLE_EMPTY_ARRAY },
|
|
1006
|
+
error: null,
|
|
1007
|
+
isLoading: false,
|
|
1008
|
+
isPending: false,
|
|
1009
|
+
isFetching: false,
|
|
1010
|
+
isFetchingNextPage: false,
|
|
1011
|
+
hasNextPage: false,
|
|
1012
|
+
fetchNextPage: async () => ({}),
|
|
1013
|
+
refetch: async () => ({}),
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
export function useInfiniteQuery() {
|
|
1017
|
+
return STABLE_INFINITE_QUERY_RESULT;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
const STABLE_MUTATION_RESULT = {
|
|
1021
|
+
mutate: () => undefined,
|
|
1022
|
+
mutateAsync: async () => ({}),
|
|
1023
|
+
reset: () => undefined,
|
|
1024
|
+
data: undefined,
|
|
1025
|
+
error: null,
|
|
1026
|
+
isLoading: false,
|
|
1027
|
+
isPending: false,
|
|
1028
|
+
isError: false,
|
|
1029
|
+
isSuccess: false,
|
|
1030
|
+
status: 'idle',
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
export function useMutation() {
|
|
1034
|
+
return STABLE_MUTATION_RESULT;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// ============================================================================
|
|
1038
|
+
// 11. Universal Chainable Proxy, Zod, React Hook Form & Context Fallbacks
|
|
1039
|
+
// ============================================================================
|
|
1040
|
+
export function createSafeChainableProxy(): unknown {
|
|
1041
|
+
const fnTarget = function (..._args: unknown[]) {
|
|
1042
|
+
return proxy;
|
|
1043
|
+
};
|
|
1044
|
+
const proxy: unknown = new Proxy(fnTarget, {
|
|
1045
|
+
get(_target, prop) {
|
|
1046
|
+
if (prop === Symbol.toPrimitive) {
|
|
1047
|
+
return (hint: string) => (hint === 'number' ? 0 : '');
|
|
1048
|
+
}
|
|
1049
|
+
if (prop === 'valueOf') return () => 0;
|
|
1050
|
+
if (prop === 'toString') return () => '';
|
|
1051
|
+
if (prop === Symbol.iterator) {
|
|
1052
|
+
return function* () {
|
|
1053
|
+
yield proxy;
|
|
1054
|
+
yield proxy;
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
if (prop === 'then') {
|
|
1058
|
+
return (onFulfilled?: (v: unknown) => unknown, onRejected?: (e: unknown) => unknown) =>
|
|
1059
|
+
Promise.resolve({ data: null, error: null }).then(onFulfilled, onRejected);
|
|
1060
|
+
}
|
|
1061
|
+
if (prop === 'catch') return () => Promise.resolve({ data: null, error: null });
|
|
1062
|
+
if (prop === 'finally')
|
|
1063
|
+
return (cb?: () => void) => Promise.resolve({ data: null, error: null }).finally(cb);
|
|
1064
|
+
if (prop === 'safeParse' || prop === 'spa' || prop === 'safeParseAsync') {
|
|
1065
|
+
return (val?: unknown) => ({ success: true, data: val ?? {}, error: null });
|
|
1066
|
+
}
|
|
1067
|
+
if (prop === 'parse' || prop === 'parseAsync') {
|
|
1068
|
+
return (val?: unknown) => val ?? {};
|
|
1069
|
+
}
|
|
1070
|
+
if (
|
|
1071
|
+
prop === 'isLoading' ||
|
|
1072
|
+
prop === 'loading' ||
|
|
1073
|
+
prop === 'isPending' ||
|
|
1074
|
+
prop === 'isError' ||
|
|
1075
|
+
prop === 'disabled' ||
|
|
1076
|
+
prop === 'isSubmitting'
|
|
1077
|
+
) {
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
if (
|
|
1081
|
+
prop === 'isReady' ||
|
|
1082
|
+
prop === 'granted' ||
|
|
1083
|
+
prop === 'isSuccess' ||
|
|
1084
|
+
prop === 'isAuthenticated' ||
|
|
1085
|
+
prop === 'isValid'
|
|
1086
|
+
) {
|
|
1087
|
+
return true;
|
|
1088
|
+
}
|
|
1089
|
+
if (prop === 'error' || prop === 'errors') return null;
|
|
1090
|
+
if (prop === 'status') return 'granted';
|
|
1091
|
+
if (prop === 'data' || prop === 'items' || prop === 'results' || prop === 'list') {
|
|
1092
|
+
return STABLE_EMPTY_ARRAY;
|
|
1093
|
+
}
|
|
1094
|
+
if (prop === 'length' || prop === 'size' || prop === 'count' || prop === 'value') return 0;
|
|
1095
|
+
if (prop === 'ref') return { current: null };
|
|
1096
|
+
if (prop === 'map' || prop === 'filter' || prop === 'slice' || prop === 'flatMap') {
|
|
1097
|
+
return () => STABLE_EMPTY_ARRAY;
|
|
1098
|
+
}
|
|
1099
|
+
if (prop === 'forEach') return () => undefined;
|
|
1100
|
+
if (prop === 'reduce') return (_fn: unknown, init: unknown) => init;
|
|
1101
|
+
if (prop === 'shape' || prop === '_def') return {};
|
|
1102
|
+
return proxy;
|
|
1103
|
+
},
|
|
1104
|
+
});
|
|
1105
|
+
return proxy;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
export const SAFE_CHAINABLE_PROXY = createSafeChainableProxy();
|
|
1109
|
+
|
|
1110
|
+
// Zod Shims (import { z } from 'zod' or import * as z from 'zod')
|
|
1111
|
+
export const z = SAFE_CHAINABLE_PROXY as Record<string, unknown>;
|
|
1112
|
+
export const string = () => SAFE_CHAINABLE_PROXY;
|
|
1113
|
+
export const number = () => SAFE_CHAINABLE_PROXY;
|
|
1114
|
+
export const boolean = () => SAFE_CHAINABLE_PROXY;
|
|
1115
|
+
export const object = () => SAFE_CHAINABLE_PROXY;
|
|
1116
|
+
export const array = () => SAFE_CHAINABLE_PROXY;
|
|
1117
|
+
export const union = () => SAFE_CHAINABLE_PROXY;
|
|
1118
|
+
export const literal = () => SAFE_CHAINABLE_PROXY;
|
|
1119
|
+
export const record = () => SAFE_CHAINABLE_PROXY;
|
|
1120
|
+
export const tuple = () => SAFE_CHAINABLE_PROXY;
|
|
1121
|
+
export const any = () => SAFE_CHAINABLE_PROXY;
|
|
1122
|
+
export const unknown = () => SAFE_CHAINABLE_PROXY;
|
|
1123
|
+
export const optional = () => SAFE_CHAINABLE_PROXY;
|
|
1124
|
+
export const nullable = () => SAFE_CHAINABLE_PROXY;
|
|
1125
|
+
export const coerce = SAFE_CHAINABLE_PROXY;
|
|
1126
|
+
export const zodResolver = () => async (values: unknown) => ({
|
|
1127
|
+
values: values ?? {},
|
|
1128
|
+
errors: {},
|
|
1129
|
+
});
|
|
1130
|
+
export const yupResolver = zodResolver;
|
|
1131
|
+
|
|
1132
|
+
// Common React Native Sizing & Classname Utility Shims
|
|
1133
|
+
export const scale = (size: number) => size;
|
|
1134
|
+
export const verticalScale = (size: number) => size;
|
|
1135
|
+
export const moderateScale = (size: number) => size;
|
|
1136
|
+
export const moderateVerticalScale = (size: number) => size;
|
|
1137
|
+
export const s = scale;
|
|
1138
|
+
export const vs = verticalScale;
|
|
1139
|
+
export const ms = moderateScale;
|
|
1140
|
+
export const mvs = moderateVerticalScale;
|
|
1141
|
+
export const RFValue = (size: number) => size;
|
|
1142
|
+
export const RFPercentage = (pct: number) => Math.round(pct * 8);
|
|
1143
|
+
export const widthPercentageToDP = (pct: number | string) =>
|
|
1144
|
+
typeof pct === 'number' ? Math.round((393 * pct) / 100) : 100;
|
|
1145
|
+
export const heightPercentageToDP = (pct: number | string) =>
|
|
1146
|
+
typeof pct === 'number' ? Math.round((852 * pct) / 100) : 100;
|
|
1147
|
+
export const wp = widthPercentageToDP;
|
|
1148
|
+
export const hp = heightPercentageToDP;
|
|
1149
|
+
export const clsx = (...args: unknown[]) =>
|
|
1150
|
+
args.filter((a): a is string => typeof a === 'string' && a.length > 0).join(' ');
|
|
1151
|
+
export const cn = clsx;
|
|
1152
|
+
export const twMerge = clsx;
|
|
1153
|
+
|
|
1154
|
+
// React Hook Form Shims (react-hook-form)
|
|
1155
|
+
export function useForm(config?: { defaultValues?: Record<string, unknown> }) {
|
|
1156
|
+
const defaults = config?.defaultValues ?? {};
|
|
1157
|
+
return {
|
|
1158
|
+
control: {},
|
|
1159
|
+
register: (name: string) => ({
|
|
1160
|
+
name,
|
|
1161
|
+
onChange: () => undefined,
|
|
1162
|
+
onBlur: () => undefined,
|
|
1163
|
+
ref: () => undefined,
|
|
1164
|
+
}),
|
|
1165
|
+
handleSubmit: (onValid?: (data: Record<string, unknown>) => unknown) => () =>
|
|
1166
|
+
onValid?.(defaults),
|
|
1167
|
+
watch: (name?: string) => (name ? defaults[name] ?? '' : defaults),
|
|
1168
|
+
getValues: (name?: string) => (name ? defaults[name] : defaults),
|
|
1169
|
+
setValue: () => undefined,
|
|
1170
|
+
reset: () => undefined,
|
|
1171
|
+
clearErrors: () => undefined,
|
|
1172
|
+
setError: () => undefined,
|
|
1173
|
+
trigger: async () => true,
|
|
1174
|
+
formState: {
|
|
1175
|
+
errors: {},
|
|
1176
|
+
isDirty: false,
|
|
1177
|
+
isLoading: false,
|
|
1178
|
+
isSubmitted: false,
|
|
1179
|
+
isSubmitting: false,
|
|
1180
|
+
isSubmitSuccessful: false,
|
|
1181
|
+
isValid: true,
|
|
1182
|
+
dirtyFields: {},
|
|
1183
|
+
touchedFields: {},
|
|
1184
|
+
},
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
export const useFormContext = () => useForm();
|
|
1189
|
+
export const FormProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
1190
|
+
<>{children}</>
|
|
1191
|
+
);
|
|
1192
|
+
export const useWatch = () => '';
|
|
1193
|
+
export const useFieldArray = () => ({
|
|
1194
|
+
fields: STABLE_EMPTY_ARRAY,
|
|
1195
|
+
append: () => undefined,
|
|
1196
|
+
prepend: () => undefined,
|
|
1197
|
+
remove: () => undefined,
|
|
1198
|
+
insert: () => undefined,
|
|
1199
|
+
move: () => undefined,
|
|
1200
|
+
update: () => undefined,
|
|
1201
|
+
replace: () => undefined,
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
export const Controller: React.FC<{
|
|
1205
|
+
name?: string;
|
|
1206
|
+
defaultValue?: unknown;
|
|
1207
|
+
render?: (params: {
|
|
1208
|
+
field: {
|
|
1209
|
+
name: string;
|
|
1210
|
+
value: unknown;
|
|
1211
|
+
onChange: (...args: unknown[]) => void;
|
|
1212
|
+
onBlur: () => void;
|
|
1213
|
+
ref: () => void;
|
|
1214
|
+
};
|
|
1215
|
+
fieldState: { invalid: boolean; isTouched: boolean; isDirty: boolean; error: undefined };
|
|
1216
|
+
formState: { errors: Record<string, unknown>; isSubmitting: boolean; isValid: boolean };
|
|
1217
|
+
}) => React.ReactNode;
|
|
1218
|
+
children?: React.ReactNode;
|
|
1219
|
+
}> = ({ name = '', defaultValue = '', render, children }) => {
|
|
1220
|
+
if (typeof render === 'function') {
|
|
1221
|
+
return (
|
|
1222
|
+
<>
|
|
1223
|
+
{render({
|
|
1224
|
+
field: {
|
|
1225
|
+
name,
|
|
1226
|
+
value: defaultValue ?? '',
|
|
1227
|
+
onChange: () => undefined,
|
|
1228
|
+
onBlur: () => undefined,
|
|
1229
|
+
ref: () => undefined,
|
|
1230
|
+
},
|
|
1231
|
+
fieldState: { invalid: false, isTouched: false, isDirty: false, error: undefined },
|
|
1232
|
+
formState: { errors: {}, isSubmitting: false, isValid: true },
|
|
1233
|
+
})}
|
|
1234
|
+
</>
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
return <>{children}</>;
|
|
1238
|
+
};
|
|
1239
|
+
|
|
1240
|
+
// Universal Unmounted Context Fallback (prevents "useAuth must be used within an AuthProvider")
|
|
1241
|
+
const previewUserBase: Record<string, unknown> = {
|
|
1242
|
+
id: 'usr_preview_01',
|
|
1243
|
+
uid: 'usr_preview_01',
|
|
1244
|
+
email: 'alex.morgan@example.com',
|
|
1245
|
+
name: 'Alex Morgan',
|
|
1246
|
+
fullName: 'Alex Morgan',
|
|
1247
|
+
full_name: 'Alex Morgan',
|
|
1248
|
+
firstName: 'Alex',
|
|
1249
|
+
first_name: 'Alex',
|
|
1250
|
+
lastName: 'Morgan',
|
|
1251
|
+
last_name: 'Morgan',
|
|
1252
|
+
displayName: 'Alex Morgan',
|
|
1253
|
+
display_name: 'Alex Morgan',
|
|
1254
|
+
username: 'alexmorgan',
|
|
1255
|
+
phone: '+1 (555) 019-2834',
|
|
1256
|
+
phoneNumber: '+1 (555) 019-2834',
|
|
1257
|
+
phone_number: '+1 (555) 019-2834',
|
|
1258
|
+
role: 'buyer',
|
|
1259
|
+
accountType: 'buyer',
|
|
1260
|
+
account_type: 'buyer',
|
|
1261
|
+
location: 'San Francisco, CA',
|
|
1262
|
+
city: 'San Francisco',
|
|
1263
|
+
bio: 'Product designer & automotive enthusiast.',
|
|
1264
|
+
avatar: '',
|
|
1265
|
+
avatarUrl: '',
|
|
1266
|
+
avatar_url: '',
|
|
1267
|
+
photoURL: '',
|
|
1268
|
+
profileImage: '',
|
|
1269
|
+
profile_image: '',
|
|
1270
|
+
isVerified: true,
|
|
1271
|
+
is_verified: true,
|
|
1272
|
+
verified: true,
|
|
1273
|
+
createdAt: '2025-01-15T10:00:00Z',
|
|
1274
|
+
created_at: '2025-01-15T10:00:00Z',
|
|
1275
|
+
user_metadata: {
|
|
1276
|
+
full_name: 'Alex Morgan',
|
|
1277
|
+
name: 'Alex Morgan',
|
|
1278
|
+
email: 'alex.morgan@example.com',
|
|
1279
|
+
role: 'buyer',
|
|
1280
|
+
avatar_url: '',
|
|
1281
|
+
},
|
|
1282
|
+
app_metadata: {
|
|
1283
|
+
provider: 'email',
|
|
1284
|
+
role: 'buyer',
|
|
1285
|
+
},
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1288
|
+
const previewUserProxy = new Proxy(previewUserBase, {
|
|
1289
|
+
get(target, prop) {
|
|
1290
|
+
if (prop in target) return target[prop as keyof typeof target];
|
|
1291
|
+
if (prop === Symbol.toPrimitive) return () => 'Alex Morgan';
|
|
1292
|
+
if (typeof prop === 'string') return '';
|
|
1293
|
+
return undefined;
|
|
1294
|
+
},
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
const previewColorsBase: Record<string, string> = {
|
|
1298
|
+
primary: '#2563EB',
|
|
1299
|
+
primaryLight: '#DBEAFE',
|
|
1300
|
+
secondary: '#64748B',
|
|
1301
|
+
accent: '#4F46E5',
|
|
1302
|
+
background: '#FFFFFF',
|
|
1303
|
+
backgroundSecondary: '#F8FAFC',
|
|
1304
|
+
surface: '#F8FAFC',
|
|
1305
|
+
card: '#FFFFFF',
|
|
1306
|
+
text: '#0F172A',
|
|
1307
|
+
textPrimary: '#0F172A',
|
|
1308
|
+
textSecondary: '#475569',
|
|
1309
|
+
textMuted: '#94A3B8',
|
|
1310
|
+
muted: '#94A3B8',
|
|
1311
|
+
placeholder: '#94A3B8',
|
|
1312
|
+
border: '#E2E8F0',
|
|
1313
|
+
divider: '#E2E8F0',
|
|
1314
|
+
error: '#EF4444',
|
|
1315
|
+
danger: '#EF4444',
|
|
1316
|
+
success: '#10B981',
|
|
1317
|
+
warning: '#F59E0B',
|
|
1318
|
+
info: '#3B82F6',
|
|
1319
|
+
white: '#FFFFFF',
|
|
1320
|
+
black: '#0F172A',
|
|
1321
|
+
tint: '#2563EB',
|
|
1322
|
+
icon: '#64748B',
|
|
1323
|
+
tabIconDefault: '#94A3B8',
|
|
1324
|
+
tabIconSelected: '#2563EB',
|
|
1325
|
+
notification: '#EF4444',
|
|
1326
|
+
};
|
|
1327
|
+
|
|
1328
|
+
const previewColorsProxy = new Proxy(previewColorsBase, {
|
|
1329
|
+
get(target, prop) {
|
|
1330
|
+
if (prop in target) return target[prop as keyof typeof target];
|
|
1331
|
+
return '#64748B';
|
|
1332
|
+
},
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
const safeContextFallbackBase: Record<string, unknown> = {
|
|
1336
|
+
user: previewUserProxy,
|
|
1337
|
+
currentUser: previewUserProxy,
|
|
1338
|
+
profile: previewUserProxy,
|
|
1339
|
+
session: {
|
|
1340
|
+
access_token: 'preview-access-token',
|
|
1341
|
+
refresh_token: 'preview-refresh-token',
|
|
1342
|
+
user: previewUserProxy,
|
|
1343
|
+
},
|
|
1344
|
+
isAuthenticated: true,
|
|
1345
|
+
isLoggedIn: true,
|
|
1346
|
+
isSignedIn: true,
|
|
1347
|
+
isLoading: false,
|
|
1348
|
+
loading: false,
|
|
1349
|
+
isPending: false,
|
|
1350
|
+
isRefreshing: false,
|
|
1351
|
+
isInitialized: true,
|
|
1352
|
+
isReady: true,
|
|
1353
|
+
error: null,
|
|
1354
|
+
theme: 'light',
|
|
1355
|
+
colorScheme: 'light',
|
|
1356
|
+
isDark: false,
|
|
1357
|
+
dark: false,
|
|
1358
|
+
colors: previewColorsProxy,
|
|
1359
|
+
items: STABLE_EMPTY_ARRAY,
|
|
1360
|
+
cart: STABLE_EMPTY_ARRAY,
|
|
1361
|
+
favorites: STABLE_EMPTY_ARRAY,
|
|
1362
|
+
wishlist: STABLE_EMPTY_ARRAY,
|
|
1363
|
+
notifications: STABLE_EMPTY_ARRAY,
|
|
1364
|
+
bookings: STABLE_EMPTY_ARRAY,
|
|
1365
|
+
listings: STABLE_EMPTY_ARRAY,
|
|
1366
|
+
vehicles: STABLE_EMPTY_ARRAY,
|
|
1367
|
+
cars: STABLE_EMPTY_ARRAY,
|
|
1368
|
+
orders: STABLE_EMPTY_ARRAY,
|
|
1369
|
+
transactions: STABLE_EMPTY_ARRAY,
|
|
1370
|
+
messages: STABLE_EMPTY_ARRAY,
|
|
1371
|
+
chats: STABLE_EMPTY_ARRAY,
|
|
1372
|
+
unreadCount: 0,
|
|
1373
|
+
count: 0,
|
|
1374
|
+
total: 0,
|
|
1375
|
+
balance: 0,
|
|
1376
|
+
signIn: async () => ({ data: { user: previewUserProxy }, error: null }),
|
|
1377
|
+
signUp: async () => ({ data: { user: previewUserProxy }, error: null }),
|
|
1378
|
+
signOut: async () => ({ error: null }),
|
|
1379
|
+
login: async () => ({ data: { user: previewUserProxy }, error: null }),
|
|
1380
|
+
logout: async () => undefined,
|
|
1381
|
+
register: async () => ({ data: { user: previewUserProxy }, error: null }),
|
|
1382
|
+
refresh: async () => undefined,
|
|
1383
|
+
refetch: async () => undefined,
|
|
1384
|
+
updateProfile: async () => ({ error: null }),
|
|
1385
|
+
toggleTheme: () => undefined,
|
|
1386
|
+
setTheme: () => undefined,
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
export const SAFE_CONTEXT_FALLBACK: Record<string, unknown> = new Proxy(safeContextFallbackBase, {
|
|
1390
|
+
get(target, prop) {
|
|
1391
|
+
if (prop in target) return target[prop as keyof typeof target];
|
|
1392
|
+
if (prop === Symbol.iterator) {
|
|
1393
|
+
return function* () {
|
|
1394
|
+
yield SAFE_CONTEXT_FALLBACK;
|
|
1395
|
+
yield () => undefined;
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
return SAFE_CHAINABLE_PROXY;
|
|
1399
|
+
},
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
// Install unmounted user-context fallback on React.createContext & React.useContext
|
|
1403
|
+
// (runs after react-native-web has already initialized its internal VirtualizedListContext)
|
|
1404
|
+
const origCreateContext = React.createContext;
|
|
1405
|
+
const origUseContext = React.useContext;
|
|
1406
|
+
|
|
1407
|
+
const wrappedCreateContext = function zeluneCreateContext(
|
|
1408
|
+
defaultValue: unknown,
|
|
1409
|
+
...rest: unknown[]
|
|
1410
|
+
) {
|
|
1411
|
+
const isEmptyDefault =
|
|
1412
|
+
defaultValue === undefined ||
|
|
1413
|
+
defaultValue === null ||
|
|
1414
|
+
(typeof defaultValue === 'object' &&
|
|
1415
|
+
defaultValue !== null &&
|
|
1416
|
+
Object.keys(defaultValue as object).length === 0);
|
|
1417
|
+
const effectiveDefault = isEmptyDefault ? SAFE_CONTEXT_FALLBACK : defaultValue;
|
|
1418
|
+
const ctx = (origCreateContext as (...a: unknown[]) => Record<string, unknown>).call(
|
|
1419
|
+
React,
|
|
1420
|
+
effectiveDefault,
|
|
1421
|
+
...rest
|
|
1422
|
+
);
|
|
1423
|
+
if (ctx && typeof ctx === 'object' && isEmptyDefault) {
|
|
1424
|
+
ctx.__zeluneUserContext = true;
|
|
1425
|
+
}
|
|
1426
|
+
return ctx;
|
|
1427
|
+
} as unknown as typeof React.createContext;
|
|
1428
|
+
|
|
1429
|
+
const wrappedUseContext = function zeluneUseContext(
|
|
1430
|
+
Context: React.Context<unknown>,
|
|
1431
|
+
...rest: unknown[]
|
|
1432
|
+
) {
|
|
1433
|
+
const val = (origUseContext as (...a: unknown[]) => unknown).call(React, Context, ...rest);
|
|
1434
|
+
if (
|
|
1435
|
+
val === undefined ||
|
|
1436
|
+
(val === null &&
|
|
1437
|
+
Boolean((Context as unknown as Record<string, unknown>)?.__zeluneUserContext))
|
|
1438
|
+
) {
|
|
1439
|
+
return SAFE_CONTEXT_FALLBACK;
|
|
1440
|
+
}
|
|
1441
|
+
return val;
|
|
1442
|
+
} as unknown as typeof React.useContext;
|
|
1443
|
+
|
|
1444
|
+
try {
|
|
1445
|
+
React.createContext = wrappedCreateContext;
|
|
1446
|
+
React.useContext = wrappedUseContext;
|
|
1447
|
+
} catch {
|
|
1448
|
+
// Ignore if React namespace is frozen in test environment
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
function createSupabaseQueryBuilder(): Record<string, unknown> {
|
|
1452
|
+
const resultPromise = Promise.resolve({ data: [], error: null, count: 0 });
|
|
1453
|
+
const builder: Record<string, unknown> = new Proxy(
|
|
1454
|
+
{},
|
|
1455
|
+
{
|
|
1456
|
+
get(_target, prop) {
|
|
1457
|
+
if (prop === 'then') return resultPromise.then.bind(resultPromise);
|
|
1458
|
+
if (prop === 'catch') return resultPromise.catch.bind(resultPromise);
|
|
1459
|
+
if (prop === 'finally') return resultPromise.finally.bind(resultPromise);
|
|
1460
|
+
if (prop === 'single' || prop === 'maybeSingle') {
|
|
1461
|
+
return async () => ({ data: null, error: null });
|
|
1462
|
+
}
|
|
1463
|
+
return () => builder;
|
|
1464
|
+
},
|
|
1465
|
+
}
|
|
1466
|
+
);
|
|
1467
|
+
return builder;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
export function createClient() {
|
|
1471
|
+
return {
|
|
1472
|
+
auth: {
|
|
1473
|
+
getSession: async () => ({ data: { session: null }, error: null }),
|
|
1474
|
+
getUser: async () => ({ data: { user: null }, error: null }),
|
|
1475
|
+
onAuthStateChange: () => ({
|
|
1476
|
+
data: { subscription: { unsubscribe: () => undefined } },
|
|
1477
|
+
}),
|
|
1478
|
+
signInWithPassword: async () => ({ data: { user: null, session: null }, error: null }),
|
|
1479
|
+
signInWithOtp: async () => ({ data: { user: null, session: null }, error: null }),
|
|
1480
|
+
signUp: async () => ({ data: { user: null, session: null }, error: null }),
|
|
1481
|
+
signOut: async () => ({ error: null }),
|
|
1482
|
+
startAutoRefresh: () => undefined,
|
|
1483
|
+
stopAutoRefresh: () => undefined,
|
|
1484
|
+
},
|
|
1485
|
+
from: () => createSupabaseQueryBuilder(),
|
|
1486
|
+
rpc: async () => ({ data: null, error: null }),
|
|
1487
|
+
storage: {
|
|
1488
|
+
from: () => ({
|
|
1489
|
+
upload: async () => ({ data: { path: '' }, error: null }),
|
|
1490
|
+
getPublicUrl: () => ({ data: { publicUrl: '' } }),
|
|
1491
|
+
download: async () => ({ data: null, error: null }),
|
|
1492
|
+
remove: async () => ({ data: [], error: null }),
|
|
1493
|
+
}),
|
|
1494
|
+
},
|
|
1495
|
+
channel: () => {
|
|
1496
|
+
const ch = {
|
|
1497
|
+
on: () => ch,
|
|
1498
|
+
subscribe: () => ch,
|
|
1499
|
+
unsubscribe: async () => 'ok',
|
|
1500
|
+
};
|
|
1501
|
+
return ch;
|
|
1502
|
+
},
|
|
1503
|
+
removeChannel: async () => 'ok',
|
|
1504
|
+
functions: {
|
|
1505
|
+
invoke: async () => ({ data: null, error: null }),
|
|
1506
|
+
},
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
function UniversalDefaultExportComponent(props: Record<string, unknown> = {}) {
|
|
1511
|
+
if (props && typeof props === 'object') {
|
|
1512
|
+
if (typeof props.name === 'string') {
|
|
1513
|
+
return Ionicons(props as VectorIconProps);
|
|
1514
|
+
}
|
|
1515
|
+
if ('viewBox' in props || 'xmlns' in props) {
|
|
1516
|
+
return React.createElement('svg', props, props.children as React.ReactNode);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return React.createElement(
|
|
1520
|
+
View,
|
|
1521
|
+
{ style: props?.style as never },
|
|
1522
|
+
props?.children as React.ReactNode
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const defaultExportProperties = {
|
|
1527
|
+
...Animated,
|
|
1528
|
+
...AsyncStorage,
|
|
1529
|
+
...Constants,
|
|
1530
|
+
Ionicons,
|
|
1531
|
+
Feather,
|
|
1532
|
+
MaterialIcons,
|
|
1533
|
+
MaterialCommunityIcons,
|
|
1534
|
+
FontAwesome,
|
|
1535
|
+
FontAwesome5,
|
|
1536
|
+
FontAwesome6,
|
|
1537
|
+
AntDesign,
|
|
1538
|
+
Entypo,
|
|
1539
|
+
EvilIcons,
|
|
1540
|
+
Foundation,
|
|
1541
|
+
Octicons,
|
|
1542
|
+
SimpleLineIcons,
|
|
1543
|
+
Zocial,
|
|
1544
|
+
Fontisto,
|
|
1545
|
+
LinearGradient,
|
|
1546
|
+
BlurView,
|
|
1547
|
+
Image,
|
|
1548
|
+
ImageBackground,
|
|
1549
|
+
FlashList,
|
|
1550
|
+
Svg,
|
|
1551
|
+
ImpactFeedbackStyle,
|
|
1552
|
+
NotificationFeedbackType,
|
|
1553
|
+
impactAsync,
|
|
1554
|
+
notificationAsync,
|
|
1555
|
+
selectionAsync,
|
|
1556
|
+
useFonts,
|
|
1557
|
+
loadAsync,
|
|
1558
|
+
isLoaded,
|
|
1559
|
+
preventAutoHideAsync,
|
|
1560
|
+
hideAsync,
|
|
1561
|
+
getItemAsync,
|
|
1562
|
+
setItemAsync,
|
|
1563
|
+
deleteItemAsync,
|
|
1564
|
+
setStringAsync,
|
|
1565
|
+
getStringAsync,
|
|
1566
|
+
openURL,
|
|
1567
|
+
createURL,
|
|
1568
|
+
create,
|
|
1569
|
+
useStore,
|
|
1570
|
+
QueryClient,
|
|
1571
|
+
QueryClientProvider,
|
|
1572
|
+
useQueryClient,
|
|
1573
|
+
useQuery,
|
|
1574
|
+
useInfiniteQuery,
|
|
1575
|
+
useMutation,
|
|
1576
|
+
createClient,
|
|
1577
|
+
z,
|
|
1578
|
+
string,
|
|
1579
|
+
number,
|
|
1580
|
+
boolean,
|
|
1581
|
+
object,
|
|
1582
|
+
array,
|
|
1583
|
+
union,
|
|
1584
|
+
literal,
|
|
1585
|
+
record,
|
|
1586
|
+
tuple,
|
|
1587
|
+
any,
|
|
1588
|
+
unknown,
|
|
1589
|
+
optional,
|
|
1590
|
+
nullable,
|
|
1591
|
+
coerce,
|
|
1592
|
+
zodResolver,
|
|
1593
|
+
yupResolver,
|
|
1594
|
+
useForm,
|
|
1595
|
+
useFormContext,
|
|
1596
|
+
FormProvider,
|
|
1597
|
+
useWatch,
|
|
1598
|
+
useFieldArray,
|
|
1599
|
+
Controller,
|
|
1600
|
+
};
|
|
1601
|
+
|
|
1602
|
+
Object.assign(UniversalDefaultExportComponent, defaultExportProperties);
|
|
1603
|
+
|
|
1604
|
+
const defaultExportProxy = new Proxy(UniversalDefaultExportComponent, {
|
|
1605
|
+
get(target, prop) {
|
|
1606
|
+
if (prop in target) {
|
|
1607
|
+
return (target as unknown as Record<string | symbol, unknown>)[prop];
|
|
1608
|
+
}
|
|
1609
|
+
if (prop in defaultExportProperties) {
|
|
1610
|
+
return defaultExportProperties[prop as keyof typeof defaultExportProperties];
|
|
1611
|
+
}
|
|
1612
|
+
if (typeof prop === 'string' && /^[A-Z]/.test(prop)) {
|
|
1613
|
+
return createVectorIconComponent(prop);
|
|
1614
|
+
}
|
|
1615
|
+
return SAFE_CHAINABLE_PROXY;
|
|
1616
|
+
},
|
|
1617
|
+
});
|
|
1618
|
+
|
|
1619
|
+
export default defaultExportProxy;
|