zelune 1.5.5 → 1.5.7
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 +20 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/plugins/viteReactNativeFallbackPlugin.ts +1 -1
- package/src/canvas/CanvasApp.tsx +112 -57
- package/src/runtime/MockNavigationContext.tsx +136 -19
- package/src/runtime/nativewindShim.ts +997 -0
- package/src/runtime/reactNativeShim.ts +99 -0
- package/vite.config.ts +61 -0
|
@@ -1,8 +1,89 @@
|
|
|
1
1
|
import React, { useRef } from 'react';
|
|
2
2
|
import * as RNW from 'react-native-web';
|
|
3
|
+
import { withNativeWind } from './nativewindShim';
|
|
3
4
|
|
|
4
5
|
export * from 'react-native-web';
|
|
5
6
|
|
|
7
|
+
// Wrap core React Native primitives with NativeWind className -> style support
|
|
8
|
+
export const View = withNativeWind(RNW.View as unknown as React.ComponentType<Record<string, unknown>>, 'View');
|
|
9
|
+
export const Text = withNativeWind(RNW.Text as unknown as React.ComponentType<Record<string, unknown>>, 'Text');
|
|
10
|
+
export const Pressable = withNativeWind(
|
|
11
|
+
RNW.Pressable as unknown as React.ComponentType<Record<string, unknown>>,
|
|
12
|
+
'Pressable'
|
|
13
|
+
);
|
|
14
|
+
export const TouchableOpacity = withNativeWind(
|
|
15
|
+
RNW.TouchableOpacity as unknown as React.ComponentType<Record<string, unknown>>,
|
|
16
|
+
'TouchableOpacity'
|
|
17
|
+
);
|
|
18
|
+
export const TouchableHighlight = withNativeWind(
|
|
19
|
+
RNW.TouchableHighlight as unknown as React.ComponentType<Record<string, unknown>>,
|
|
20
|
+
'TouchableHighlight'
|
|
21
|
+
);
|
|
22
|
+
export const TouchableWithoutFeedback = withNativeWind(
|
|
23
|
+
RNW.TouchableWithoutFeedback as unknown as React.ComponentType<Record<string, unknown>>,
|
|
24
|
+
'TouchableWithoutFeedback'
|
|
25
|
+
);
|
|
26
|
+
export const ScrollView = withNativeWind(
|
|
27
|
+
RNW.ScrollView as unknown as React.ComponentType<Record<string, unknown>>,
|
|
28
|
+
'ScrollView'
|
|
29
|
+
);
|
|
30
|
+
export const FlatList = withNativeWind(
|
|
31
|
+
RNW.FlatList as unknown as React.ComponentType<Record<string, unknown>>,
|
|
32
|
+
'FlatList'
|
|
33
|
+
);
|
|
34
|
+
export const SectionList = withNativeWind(
|
|
35
|
+
RNW.SectionList as unknown as React.ComponentType<Record<string, unknown>>,
|
|
36
|
+
'SectionList'
|
|
37
|
+
);
|
|
38
|
+
export const KeyboardAvoidingView = withNativeWind(
|
|
39
|
+
RNW.KeyboardAvoidingView as unknown as React.ComponentType<Record<string, unknown>>,
|
|
40
|
+
'KeyboardAvoidingView'
|
|
41
|
+
);
|
|
42
|
+
export const TextInput = withNativeWind(
|
|
43
|
+
RNW.TextInput as unknown as React.ComponentType<Record<string, unknown>>,
|
|
44
|
+
'TextInput'
|
|
45
|
+
);
|
|
46
|
+
export const Image = withNativeWind(
|
|
47
|
+
RNW.Image as unknown as React.ComponentType<Record<string, unknown>>,
|
|
48
|
+
'Image'
|
|
49
|
+
);
|
|
50
|
+
export const ImageBackground = withNativeWind(
|
|
51
|
+
RNW.ImageBackground as unknown as React.ComponentType<Record<string, unknown>>,
|
|
52
|
+
'ImageBackground'
|
|
53
|
+
);
|
|
54
|
+
export const SafeAreaView = withNativeWind(
|
|
55
|
+
RNW.SafeAreaView as unknown as React.ComponentType<Record<string, unknown>>,
|
|
56
|
+
'SafeAreaView'
|
|
57
|
+
);
|
|
58
|
+
export const ActivityIndicator = withNativeWind(
|
|
59
|
+
RNW.ActivityIndicator as unknown as React.ComponentType<Record<string, unknown>>,
|
|
60
|
+
'ActivityIndicator'
|
|
61
|
+
);
|
|
62
|
+
export const Modal = withNativeWind(
|
|
63
|
+
RNW.Modal as unknown as React.ComponentType<Record<string, unknown>>,
|
|
64
|
+
'Modal'
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Pin mobile artboard dimensions (393x852 iPhone 15 Pro) so Dimensions.get('window')
|
|
68
|
+
// and useWindowDimensions() never return the desktop browser's 1440x900 window size.
|
|
69
|
+
const ARTBOARD_DIMENSIONS = {
|
|
70
|
+
width: 393,
|
|
71
|
+
height: 852,
|
|
72
|
+
scale: 3,
|
|
73
|
+
fontScale: 1,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const Dimensions = {
|
|
77
|
+
get: (_dim?: 'window' | 'screen' | string) => ARTBOARD_DIMENSIONS,
|
|
78
|
+
set: () => undefined,
|
|
79
|
+
addEventListener: () => ({ remove: () => undefined }),
|
|
80
|
+
removeEventListener: () => undefined,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export function useWindowDimensions() {
|
|
84
|
+
return ARTBOARD_DIMENSIONS;
|
|
85
|
+
}
|
|
86
|
+
|
|
6
87
|
export function useAnimatedValue(initialValue = 0): RNW.Animated.Value {
|
|
7
88
|
const ref = useRef<RNW.Animated.Value | null>(null);
|
|
8
89
|
if (!ref.current) {
|
|
@@ -109,6 +190,24 @@ export const Settings = {
|
|
|
109
190
|
const ReactNativeDefault = new Proxy(
|
|
110
191
|
{
|
|
111
192
|
...RNW,
|
|
193
|
+
View,
|
|
194
|
+
Text,
|
|
195
|
+
Pressable,
|
|
196
|
+
TouchableOpacity,
|
|
197
|
+
TouchableHighlight,
|
|
198
|
+
TouchableWithoutFeedback,
|
|
199
|
+
ScrollView,
|
|
200
|
+
FlatList,
|
|
201
|
+
SectionList,
|
|
202
|
+
KeyboardAvoidingView,
|
|
203
|
+
TextInput,
|
|
204
|
+
Image,
|
|
205
|
+
ImageBackground,
|
|
206
|
+
SafeAreaView,
|
|
207
|
+
ActivityIndicator,
|
|
208
|
+
Modal,
|
|
209
|
+
Dimensions,
|
|
210
|
+
useWindowDimensions,
|
|
112
211
|
useAnimatedValue,
|
|
113
212
|
PermissionsAndroid,
|
|
114
213
|
ToastAndroid,
|
package/vite.config.ts
CHANGED
|
@@ -96,6 +96,65 @@ function loadPublicProjectEnv(roots: string[]): Record<string, string> {
|
|
|
96
96
|
|
|
97
97
|
const publicProjectEnv = loadPublicProjectEnv([workspaceRoot, rawTargetRoot, targetProjectRoot]);
|
|
98
98
|
|
|
99
|
+
function loadProjectTailwindTheme(roots: string[]): Record<string, unknown> {
|
|
100
|
+
const candidates = [
|
|
101
|
+
'tailwind.config.js',
|
|
102
|
+
'tailwind.config.cjs',
|
|
103
|
+
'tailwind.config.mjs',
|
|
104
|
+
'tailwind.config.ts',
|
|
105
|
+
];
|
|
106
|
+
const uniqueRoots = Array.from(new Set(roots.map((r) => path.resolve(r))));
|
|
107
|
+
for (const rootDir of uniqueRoots) {
|
|
108
|
+
for (const fileName of candidates) {
|
|
109
|
+
const fullPath = path.join(rootDir, fileName);
|
|
110
|
+
try {
|
|
111
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
112
|
+
const raw = fs.readFileSync(fullPath, 'utf-8');
|
|
113
|
+
const cleaned = raw
|
|
114
|
+
.replace(/^import\s+.*$/gm, '')
|
|
115
|
+
.replace(/\b(const|let|var)\s+([A-Za-z0-9_$]+)\s*:\s*[^=]+=/g, '$1 $2 =')
|
|
116
|
+
.replace(/\bsatisfies\s+[A-Za-z0-9_$.<>]+/g, '')
|
|
117
|
+
.replace(/\bas\s+const\b/g, '')
|
|
118
|
+
.replace(/export\s+default\s+/, 'module.exports = ');
|
|
119
|
+
const mod = { exports: {} as Record<string, unknown> };
|
|
120
|
+
const fakeRequire = () => ({});
|
|
121
|
+
const fn = new Function('module', 'exports', 'require', cleaned);
|
|
122
|
+
fn(mod, mod.exports, fakeRequire);
|
|
123
|
+
const cfg = mod.exports as {
|
|
124
|
+
theme?: Record<string, unknown> & { extend?: Record<string, unknown> };
|
|
125
|
+
};
|
|
126
|
+
if (cfg?.theme && typeof cfg.theme === 'object') {
|
|
127
|
+
const baseTheme = { ...cfg.theme };
|
|
128
|
+
const extendTheme =
|
|
129
|
+
cfg.theme.extend && typeof cfg.theme.extend === 'object' ? cfg.theme.extend : {};
|
|
130
|
+
delete baseTheme.extend;
|
|
131
|
+
const merged: Record<string, unknown> = { ...baseTheme };
|
|
132
|
+
for (const [k, v] of Object.entries(extendTheme)) {
|
|
133
|
+
if (v && typeof v === 'object' && !Array.isArray(v)) {
|
|
134
|
+
merged[k] = {
|
|
135
|
+
...((baseTheme[k] as Record<string, unknown>) ?? {}),
|
|
136
|
+
...(v as Record<string, unknown>),
|
|
137
|
+
};
|
|
138
|
+
} else {
|
|
139
|
+
merged[k] = v;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return merged;
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
// Ignore tailwind config parse errors
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const projectTailwindTheme = loadProjectTailwindTheme([
|
|
153
|
+
targetProjectRoot,
|
|
154
|
+
rawTargetRoot,
|
|
155
|
+
workspaceRoot,
|
|
156
|
+
]);
|
|
157
|
+
|
|
99
158
|
const allowedFsRoots = Array.from(
|
|
100
159
|
new Set([
|
|
101
160
|
__dirname,
|
|
@@ -115,8 +174,10 @@ export default defineConfig({
|
|
|
115
174
|
name: 'vite-zelune-process-env-shim',
|
|
116
175
|
transformIndexHtml(html) {
|
|
117
176
|
const serializedEnv = JSON.stringify(publicProjectEnv);
|
|
177
|
+
const serializedTailwindTheme = JSON.stringify(projectTailwindTheme);
|
|
118
178
|
const envScript = `<script>
|
|
119
179
|
(function() {
|
|
180
|
+
window.__ZELUNE_TAILWIND_THEME__ = ${serializedTailwindTheme};
|
|
120
181
|
var baseEnv = ${serializedEnv};
|
|
121
182
|
var envProxy = new Proxy(baseEnv, {
|
|
122
183
|
get: function(target, prop) {
|