zelune 1.6.1 → 1.6.3
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 +15 -0
- package/bin/cli.mjs +1 -2
- package/index.html +0 -6
- package/mcp/server.mjs +48 -7
- package/mcp/server.ts +1 -1
- package/package.json +1 -5
- package/plugin.json +1 -1
- package/plugins/viteReactNativeFallbackPlugin.ts +15 -12
- package/plugins/viteRnSourceInject.ts +4 -16
- package/src/canvas/FlowArrowsLayer.tsx +15 -12
- package/src/runtime/MockNavigationContext.tsx +252 -178
- package/src/runtime/reactNativeShim.ts +1558 -124
- package/src/server/apiMiddleware.ts +8 -5
- package/src/server/astEngine.ts +78 -7
- package/vite.config.ts +5 -6
|
@@ -1,71 +1,8 @@
|
|
|
1
|
-
import React, { useRef } from 'react';
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export * from 'react-native-web';
|
|
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
|
-
);
|
|
1
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
2
|
+
import { resolveTailwindClassNameToStyle } from './nativewindShim';
|
|
3
|
+
|
|
4
|
+
export type RnStyle = Record<string, unknown> | RnStyle[] | null | undefined | false | number;
|
|
66
5
|
|
|
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
6
|
const ARTBOARD_DIMENSIONS = {
|
|
70
7
|
width: 393,
|
|
71
8
|
height: 852,
|
|
@@ -73,6 +10,1169 @@ const ARTBOARD_DIMENSIONS = {
|
|
|
73
10
|
fontScale: 1,
|
|
74
11
|
};
|
|
75
12
|
|
|
13
|
+
export function flattenStyle(styleInput: RnStyle): Record<string, unknown> {
|
|
14
|
+
const result: Record<string, unknown> = {};
|
|
15
|
+
function walk(item: RnStyle) {
|
|
16
|
+
if (!item || typeof item !== 'object') return;
|
|
17
|
+
if (Array.isArray(item)) {
|
|
18
|
+
for (let i = 0; i < item.length; i++) {
|
|
19
|
+
walk(item[i]);
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
for (const [k, v] of Object.entries(item)) {
|
|
24
|
+
if (v !== undefined) {
|
|
25
|
+
result[k] = v;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
walk(styleInput);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function formatTransformArray(transforms: unknown[]): string {
|
|
34
|
+
const parts: string[] = [];
|
|
35
|
+
for (const item of transforms) {
|
|
36
|
+
if (!item || typeof item !== 'object') continue;
|
|
37
|
+
for (const [key, rawVal] of Object.entries(item as Record<string, unknown>)) {
|
|
38
|
+
if (rawVal === undefined || rawVal === null) continue;
|
|
39
|
+
if (
|
|
40
|
+
(key.startsWith('translate') || key === 'perspective') &&
|
|
41
|
+
typeof rawVal === 'number'
|
|
42
|
+
) {
|
|
43
|
+
parts.push(`${key}(${rawVal}px)`);
|
|
44
|
+
} else {
|
|
45
|
+
parts.push(`${key}(${String(rawVal)})`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return parts.join(' ');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function applyAlphaToColor(color: string, opacity: number): string {
|
|
53
|
+
const clamped = Math.max(0, Math.min(1, opacity));
|
|
54
|
+
const hexMatch = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim());
|
|
55
|
+
if (hexMatch) {
|
|
56
|
+
let hex = hexMatch[1];
|
|
57
|
+
if (hex.length === 3) {
|
|
58
|
+
hex = hex
|
|
59
|
+
.split('')
|
|
60
|
+
.map((c) => c + c)
|
|
61
|
+
.join('');
|
|
62
|
+
}
|
|
63
|
+
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
64
|
+
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
65
|
+
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
66
|
+
return `rgba(${r}, ${g}, ${b}, ${Number(clamped.toFixed(3))})`;
|
|
67
|
+
}
|
|
68
|
+
return color;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function toDomStyle(
|
|
72
|
+
styleInput: RnStyle,
|
|
73
|
+
baseDefaults: Record<string, unknown> = {},
|
|
74
|
+
className?: string
|
|
75
|
+
): React.CSSProperties {
|
|
76
|
+
const twStyle = className ? resolveTailwindClassNameToStyle(className) : null;
|
|
77
|
+
const flat = flattenStyle([baseDefaults, twStyle, styleInput]);
|
|
78
|
+
const out: Record<string, unknown> = {};
|
|
79
|
+
|
|
80
|
+
for (const [key, val] of Object.entries(flat)) {
|
|
81
|
+
if (val === undefined || val === null) continue;
|
|
82
|
+
switch (key) {
|
|
83
|
+
case 'paddingHorizontal':
|
|
84
|
+
if (flat.paddingLeft === undefined) out.paddingLeft = val;
|
|
85
|
+
if (flat.paddingRight === undefined) out.paddingRight = val;
|
|
86
|
+
break;
|
|
87
|
+
case 'paddingVertical':
|
|
88
|
+
if (flat.paddingTop === undefined) out.paddingTop = val;
|
|
89
|
+
if (flat.paddingBottom === undefined) out.paddingBottom = val;
|
|
90
|
+
break;
|
|
91
|
+
case 'paddingStart':
|
|
92
|
+
if (flat.paddingLeft === undefined) out.paddingLeft = val;
|
|
93
|
+
break;
|
|
94
|
+
case 'paddingEnd':
|
|
95
|
+
if (flat.paddingRight === undefined) out.paddingRight = val;
|
|
96
|
+
break;
|
|
97
|
+
case 'marginHorizontal':
|
|
98
|
+
if (flat.marginLeft === undefined) out.marginLeft = val;
|
|
99
|
+
if (flat.marginRight === undefined) out.marginRight = val;
|
|
100
|
+
break;
|
|
101
|
+
case 'marginVertical':
|
|
102
|
+
if (flat.marginTop === undefined) out.marginTop = val;
|
|
103
|
+
if (flat.marginBottom === undefined) out.marginBottom = val;
|
|
104
|
+
break;
|
|
105
|
+
case 'marginStart':
|
|
106
|
+
if (flat.marginLeft === undefined) out.marginLeft = val;
|
|
107
|
+
break;
|
|
108
|
+
case 'marginEnd':
|
|
109
|
+
if (flat.marginRight === undefined) out.marginRight = val;
|
|
110
|
+
break;
|
|
111
|
+
case 'borderStartWidth':
|
|
112
|
+
if (flat.borderLeftWidth === undefined) out.borderLeftWidth = val;
|
|
113
|
+
break;
|
|
114
|
+
case 'borderEndWidth':
|
|
115
|
+
if (flat.borderRightWidth === undefined) out.borderRightWidth = val;
|
|
116
|
+
break;
|
|
117
|
+
case 'borderTopStartRadius':
|
|
118
|
+
if (flat.borderTopLeftRadius === undefined) out.borderTopLeftRadius = val;
|
|
119
|
+
break;
|
|
120
|
+
case 'borderTopEndRadius':
|
|
121
|
+
if (flat.borderTopRightRadius === undefined) out.borderTopRightRadius = val;
|
|
122
|
+
break;
|
|
123
|
+
case 'borderBottomStartRadius':
|
|
124
|
+
if (flat.borderBottomLeftRadius === undefined) out.borderBottomLeftRadius = val;
|
|
125
|
+
break;
|
|
126
|
+
case 'borderBottomEndRadius':
|
|
127
|
+
if (flat.borderBottomRightRadius === undefined) out.borderBottomRightRadius = val;
|
|
128
|
+
break;
|
|
129
|
+
case 'lineHeight':
|
|
130
|
+
out.lineHeight = typeof val === 'number' ? `${val}px` : val;
|
|
131
|
+
break;
|
|
132
|
+
case 'flex':
|
|
133
|
+
if (typeof val === 'number') {
|
|
134
|
+
if (val > 0) {
|
|
135
|
+
if (flat.flexGrow === undefined) out.flexGrow = val;
|
|
136
|
+
if (flat.flexShrink === undefined) out.flexShrink = 1;
|
|
137
|
+
if (flat.flexBasis === undefined) out.flexBasis = '0%';
|
|
138
|
+
} else if (val === 0) {
|
|
139
|
+
if (flat.flexGrow === undefined) out.flexGrow = 0;
|
|
140
|
+
if (flat.flexShrink === undefined) out.flexShrink = 0;
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
out.flex = val;
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
case 'transform':
|
|
147
|
+
if (Array.isArray(val)) {
|
|
148
|
+
const cssTransform = formatTransformArray(val);
|
|
149
|
+
if (cssTransform) out.transform = cssTransform;
|
|
150
|
+
} else if (typeof val === 'string') {
|
|
151
|
+
out.transform = val;
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
case 'textDecorationLine':
|
|
155
|
+
out.textDecoration = val;
|
|
156
|
+
break;
|
|
157
|
+
case 'includeFontPadding':
|
|
158
|
+
case 'textAlignVertical':
|
|
159
|
+
case 'tintColor':
|
|
160
|
+
case 'resizeMode':
|
|
161
|
+
case 'overlayColor':
|
|
162
|
+
case 'shadowColor':
|
|
163
|
+
case 'shadowOffset':
|
|
164
|
+
case 'shadowOpacity':
|
|
165
|
+
case 'shadowRadius':
|
|
166
|
+
case 'elevation':
|
|
167
|
+
break;
|
|
168
|
+
default:
|
|
169
|
+
out[key] = val;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Ensure React Native borders render solid by default when borderWidth > 0
|
|
175
|
+
const hasBorderWidth =
|
|
176
|
+
(typeof out.borderWidth === 'number' && out.borderWidth > 0) ||
|
|
177
|
+
(typeof out.borderTopWidth === 'number' && out.borderTopWidth > 0) ||
|
|
178
|
+
(typeof out.borderRightWidth === 'number' && out.borderRightWidth > 0) ||
|
|
179
|
+
(typeof out.borderBottomWidth === 'number' && out.borderBottomWidth > 0) ||
|
|
180
|
+
(typeof out.borderLeftWidth === 'number' && out.borderLeftWidth > 0);
|
|
181
|
+
|
|
182
|
+
if (hasBorderWidth) {
|
|
183
|
+
if (!out.borderStyle) out.borderStyle = 'solid';
|
|
184
|
+
if (
|
|
185
|
+
!out.borderColor &&
|
|
186
|
+
!out.borderTopColor &&
|
|
187
|
+
!out.borderRightColor &&
|
|
188
|
+
!out.borderBottomColor &&
|
|
189
|
+
!out.borderLeftColor
|
|
190
|
+
) {
|
|
191
|
+
out.borderColor = 'transparent';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Synthesize CSS boxShadow from React Native shadow* / elevation props
|
|
196
|
+
if (!out.boxShadow) {
|
|
197
|
+
const shadowOpacity = typeof flat.shadowOpacity === 'number' ? flat.shadowOpacity : 0;
|
|
198
|
+
const elevation = typeof flat.elevation === 'number' ? flat.elevation : 0;
|
|
199
|
+
if (shadowOpacity > 0) {
|
|
200
|
+
const offset = (flat.shadowOffset as { width?: number; height?: number } | undefined) ?? {};
|
|
201
|
+
const ox = typeof offset.width === 'number' ? offset.width : 0;
|
|
202
|
+
const oy = typeof offset.height === 'number' ? offset.height : 2;
|
|
203
|
+
const radius = typeof flat.shadowRadius === 'number' ? flat.shadowRadius : 4;
|
|
204
|
+
const rawColor = typeof flat.shadowColor === 'string' ? flat.shadowColor : '#000000';
|
|
205
|
+
out.boxShadow = `${ox}px ${oy}px ${radius}px ${applyAlphaToColor(rawColor, shadowOpacity)}`;
|
|
206
|
+
} else if (elevation > 0) {
|
|
207
|
+
const oy = Math.max(1, Math.round(elevation * 0.5));
|
|
208
|
+
const blur = Math.max(2, Math.round(elevation * 1.5));
|
|
209
|
+
out.boxShadow = `0px ${oy}px ${blur}px rgba(15, 23, 42, 0.08)`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return out as React.CSSProperties;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function camelToKebab(str: string): string {
|
|
217
|
+
return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function extractDomAttributes(props: Record<string, unknown>): Record<string, unknown> {
|
|
221
|
+
const domAttrs: Record<string, unknown> = {};
|
|
222
|
+
for (const [k, v] of Object.entries(props)) {
|
|
223
|
+
if (k.startsWith('data-') || k.startsWith('aria-')) {
|
|
224
|
+
domAttrs[k] = v;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const dataSet = props.dataSet;
|
|
228
|
+
if (dataSet && typeof dataSet === 'object') {
|
|
229
|
+
for (const [dk, dv] of Object.entries(dataSet as Record<string, unknown>)) {
|
|
230
|
+
if (dv !== undefined && dv !== null) {
|
|
231
|
+
const attrName = `data-${camelToKebab(dk)}`;
|
|
232
|
+
if (!(attrName in domAttrs)) {
|
|
233
|
+
domAttrs[attrName] = String(dv);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (typeof props.nativeID === 'string') {
|
|
239
|
+
domAttrs.id = props.nativeID;
|
|
240
|
+
} else if (typeof props.id === 'string') {
|
|
241
|
+
domAttrs.id = props.id;
|
|
242
|
+
}
|
|
243
|
+
if (typeof props.testID === 'string') {
|
|
244
|
+
domAttrs['data-testid'] = props.testID;
|
|
245
|
+
}
|
|
246
|
+
if (typeof props.accessibilityLabel === 'string') {
|
|
247
|
+
domAttrs['aria-label'] = props.accessibilityLabel;
|
|
248
|
+
}
|
|
249
|
+
if (typeof props.accessibilityRole === 'string') {
|
|
250
|
+
domAttrs.role = props.accessibilityRole === ' header' ? 'heading' : props.accessibilityRole;
|
|
251
|
+
}
|
|
252
|
+
return domAttrs;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const VIEW_BASE_STYLE: Record<string, unknown> = {
|
|
256
|
+
display: 'flex',
|
|
257
|
+
flexDirection: 'column',
|
|
258
|
+
alignItems: 'stretch',
|
|
259
|
+
flexShrink: 0,
|
|
260
|
+
boxSizing: 'border-box',
|
|
261
|
+
position: 'relative',
|
|
262
|
+
minWidth: 0,
|
|
263
|
+
minHeight: 0,
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const TEXT_BASE_STYLE: Record<string, unknown> = {
|
|
267
|
+
display: 'inline',
|
|
268
|
+
boxSizing: 'border-box',
|
|
269
|
+
color: '#0F172A',
|
|
270
|
+
fontFamily:
|
|
271
|
+
'var(--font-sans, "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)',
|
|
272
|
+
fontSize: 14,
|
|
273
|
+
whiteSpace: 'pre-wrap',
|
|
274
|
+
wordWrap: 'break-word',
|
|
275
|
+
margin: 0,
|
|
276
|
+
padding: 0,
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
function useSimulatedLayout(onLayout: unknown) {
|
|
280
|
+
const firedRef = useRef(false);
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (!firedRef.current && typeof onLayout === 'function') {
|
|
283
|
+
firedRef.current = true;
|
|
284
|
+
try {
|
|
285
|
+
onLayout({
|
|
286
|
+
nativeEvent: {
|
|
287
|
+
layout: { x: 0, y: 0, width: ARTBOARD_DIMENSIONS.width, height: 48 },
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
} catch {
|
|
291
|
+
// Ignore user layout handler errors
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}, [onLayout]);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export const View = forwardRef<HTMLDivElement, Record<string, unknown>>(function View(props, ref) {
|
|
298
|
+
useSimulatedLayout(props.onLayout);
|
|
299
|
+
const domAttrs = extractDomAttributes(props);
|
|
300
|
+
const style = toDomStyle(
|
|
301
|
+
props.style as RnStyle,
|
|
302
|
+
VIEW_BASE_STYLE,
|
|
303
|
+
props.className as string | undefined
|
|
304
|
+
);
|
|
305
|
+
if (props.pointerEvents === 'none') {
|
|
306
|
+
style.pointerEvents = 'none';
|
|
307
|
+
} else if (props.pointerEvents === 'box-none') {
|
|
308
|
+
style.pointerEvents = 'auto';
|
|
309
|
+
}
|
|
310
|
+
return React.createElement(
|
|
311
|
+
'div',
|
|
312
|
+
{
|
|
313
|
+
...domAttrs,
|
|
314
|
+
ref,
|
|
315
|
+
style,
|
|
316
|
+
onClick: typeof props.onClick === 'function' ? props.onClick : undefined,
|
|
317
|
+
},
|
|
318
|
+
props.children as React.ReactNode
|
|
319
|
+
);
|
|
320
|
+
});
|
|
321
|
+
View.displayName = 'View';
|
|
322
|
+
|
|
323
|
+
export const Text = forwardRef<HTMLSpanElement, Record<string, unknown>>(function Text(
|
|
324
|
+
props,
|
|
325
|
+
ref
|
|
326
|
+
) {
|
|
327
|
+
useSimulatedLayout(props.onLayout);
|
|
328
|
+
const domAttrs = extractDomAttributes(props);
|
|
329
|
+
const style = toDomStyle(
|
|
330
|
+
props.style as RnStyle,
|
|
331
|
+
TEXT_BASE_STYLE,
|
|
332
|
+
props.className as string | undefined
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
const numberOfLines =
|
|
336
|
+
typeof props.numberOfLines === 'number' && props.numberOfLines > 0
|
|
337
|
+
? props.numberOfLines
|
|
338
|
+
: undefined;
|
|
339
|
+
if (numberOfLines === 1) {
|
|
340
|
+
style.overflow = 'hidden';
|
|
341
|
+
style.textOverflow = 'ellipsis';
|
|
342
|
+
style.whiteSpace = 'nowrap';
|
|
343
|
+
style.maxWidth = '100%';
|
|
344
|
+
} else if (numberOfLines && numberOfLines > 1) {
|
|
345
|
+
style.display = '-webkit-box';
|
|
346
|
+
style.WebkitLineClamp = numberOfLines;
|
|
347
|
+
style.WebkitBoxOrient = 'vertical';
|
|
348
|
+
style.overflow = 'hidden';
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (props.selectable === false) {
|
|
352
|
+
style.userSelect = 'none';
|
|
353
|
+
}
|
|
354
|
+
const onPress = typeof props.onPress === 'function' ? (props.onPress as () => void) : undefined;
|
|
355
|
+
if (onPress) {
|
|
356
|
+
style.cursor = 'pointer';
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return React.createElement(
|
|
360
|
+
'span',
|
|
361
|
+
{
|
|
362
|
+
...domAttrs,
|
|
363
|
+
ref,
|
|
364
|
+
style,
|
|
365
|
+
onClick: onPress
|
|
366
|
+
? (e: React.MouseEvent) => {
|
|
367
|
+
onPress();
|
|
368
|
+
void e;
|
|
369
|
+
}
|
|
370
|
+
: undefined,
|
|
371
|
+
},
|
|
372
|
+
props.children as React.ReactNode
|
|
373
|
+
);
|
|
374
|
+
});
|
|
375
|
+
Text.displayName = 'Text';
|
|
376
|
+
|
|
377
|
+
function createInteractiveComponent(displayName: string, defaultActiveOpacity = 1) {
|
|
378
|
+
const Comp = forwardRef<HTMLDivElement, Record<string, unknown>>(function InteractiveView(
|
|
379
|
+
props,
|
|
380
|
+
ref
|
|
381
|
+
) {
|
|
382
|
+
const [pressed, setPressed] = useState(false);
|
|
383
|
+
useSimulatedLayout(props.onLayout);
|
|
384
|
+
const disabled = Boolean(props.disabled);
|
|
385
|
+
const domAttrs = extractDomAttributes(props);
|
|
386
|
+
|
|
387
|
+
const rawStyle =
|
|
388
|
+
typeof props.style === 'function'
|
|
389
|
+
? (props.style as (state: { pressed: boolean; hovered: boolean; focused: boolean }) => RnStyle)({
|
|
390
|
+
pressed,
|
|
391
|
+
hovered: false,
|
|
392
|
+
focused: false,
|
|
393
|
+
})
|
|
394
|
+
: (props.style as RnStyle);
|
|
395
|
+
|
|
396
|
+
const style = toDomStyle(rawStyle, VIEW_BASE_STYLE, props.className as string | undefined);
|
|
397
|
+
style.cursor = disabled ? 'default' : 'pointer';
|
|
398
|
+
style.userSelect = 'none';
|
|
399
|
+
|
|
400
|
+
const activeOpacity =
|
|
401
|
+
typeof props.activeOpacity === 'number' ? props.activeOpacity : defaultActiveOpacity;
|
|
402
|
+
if (pressed && !disabled && activeOpacity < 1) {
|
|
403
|
+
style.opacity = activeOpacity;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const onPress = typeof props.onPress === 'function' ? (props.onPress as (e: unknown) => void) : undefined;
|
|
407
|
+
const onPressIn =
|
|
408
|
+
typeof props.onPressIn === 'function' ? (props.onPressIn as (e: unknown) => void) : undefined;
|
|
409
|
+
const onPressOut =
|
|
410
|
+
typeof props.onPressOut === 'function' ? (props.onPressOut as (e: unknown) => void) : undefined;
|
|
411
|
+
|
|
412
|
+
const resolvedChildren =
|
|
413
|
+
typeof props.children === 'function'
|
|
414
|
+
? (props.children as (state: { pressed: boolean }) => React.ReactNode)({ pressed })
|
|
415
|
+
: (props.children as React.ReactNode);
|
|
416
|
+
|
|
417
|
+
return React.createElement(
|
|
418
|
+
'div',
|
|
419
|
+
{
|
|
420
|
+
...domAttrs,
|
|
421
|
+
ref,
|
|
422
|
+
role: (domAttrs.role as string | undefined) ?? 'button',
|
|
423
|
+
'aria-disabled': disabled || undefined,
|
|
424
|
+
style,
|
|
425
|
+
onMouseDown: (e: React.MouseEvent) => {
|
|
426
|
+
if (disabled) return;
|
|
427
|
+
setPressed(true);
|
|
428
|
+
onPressIn?.(e);
|
|
429
|
+
},
|
|
430
|
+
onMouseUp: (e: React.MouseEvent) => {
|
|
431
|
+
if (disabled) return;
|
|
432
|
+
setPressed(false);
|
|
433
|
+
onPressOut?.(e);
|
|
434
|
+
},
|
|
435
|
+
onMouseLeave: () => {
|
|
436
|
+
if (pressed) setPressed(false);
|
|
437
|
+
},
|
|
438
|
+
onClick: (e: React.MouseEvent) => {
|
|
439
|
+
if (disabled) return;
|
|
440
|
+
onPress?.(e);
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
resolvedChildren
|
|
444
|
+
);
|
|
445
|
+
});
|
|
446
|
+
Comp.displayName = displayName;
|
|
447
|
+
return Comp;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export const Pressable = createInteractiveComponent('Pressable', 1);
|
|
451
|
+
export const TouchableOpacity = createInteractiveComponent('TouchableOpacity', 0.78);
|
|
452
|
+
export const TouchableHighlight = createInteractiveComponent('TouchableHighlight', 0.85);
|
|
453
|
+
export const TouchableWithoutFeedback = createInteractiveComponent('TouchableWithoutFeedback', 1);
|
|
454
|
+
export const TouchableNativeFeedback = createInteractiveComponent('TouchableNativeFeedback', 0.85);
|
|
455
|
+
|
|
456
|
+
export const ScrollView = forwardRef<unknown, Record<string, unknown>>(function ScrollView(
|
|
457
|
+
props,
|
|
458
|
+
ref
|
|
459
|
+
) {
|
|
460
|
+
const domRef = useRef<HTMLDivElement | null>(null);
|
|
461
|
+
useSimulatedLayout(props.onLayout);
|
|
462
|
+
|
|
463
|
+
useImperativeHandle(ref, () => ({
|
|
464
|
+
scrollTo: (opts?: { x?: number; y?: number; animated?: boolean }) => {
|
|
465
|
+
if (domRef.current && opts) {
|
|
466
|
+
domRef.current.scrollTo({
|
|
467
|
+
left: opts.x ?? 0,
|
|
468
|
+
top: opts.y ?? 0,
|
|
469
|
+
behavior: opts.animated ? 'smooth' : 'auto',
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
scrollToEnd: (opts?: { animated?: boolean }) => {
|
|
474
|
+
if (domRef.current) {
|
|
475
|
+
domRef.current.scrollTo({
|
|
476
|
+
top: domRef.current.scrollHeight,
|
|
477
|
+
left: domRef.current.scrollWidth,
|
|
478
|
+
behavior: opts?.animated ? 'smooth' : 'auto',
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
flashScrollIndicators: () => undefined,
|
|
483
|
+
getScrollResponder: () => ({}),
|
|
484
|
+
getInnerViewNode: () => domRef.current,
|
|
485
|
+
}));
|
|
486
|
+
|
|
487
|
+
const horizontal = Boolean(props.horizontal);
|
|
488
|
+
const domAttrs = extractDomAttributes(props);
|
|
489
|
+
|
|
490
|
+
const outerStyle = toDomStyle(
|
|
491
|
+
props.style as RnStyle,
|
|
492
|
+
{
|
|
493
|
+
...VIEW_BASE_STYLE,
|
|
494
|
+
flexGrow: 1,
|
|
495
|
+
flexShrink: 1,
|
|
496
|
+
overflowX: horizontal ? 'auto' : 'hidden',
|
|
497
|
+
overflowY: horizontal ? 'hidden' : 'auto',
|
|
498
|
+
WebkitOverflowScrolling: 'touch',
|
|
499
|
+
scrollbarWidth:
|
|
500
|
+
props.showsVerticalScrollIndicator === false ||
|
|
501
|
+
props.showsHorizontalScrollIndicator === false
|
|
502
|
+
? 'none'
|
|
503
|
+
: undefined,
|
|
504
|
+
},
|
|
505
|
+
props.className as string | undefined
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
const innerStyle = toDomStyle(
|
|
509
|
+
props.contentContainerStyle as RnStyle,
|
|
510
|
+
{
|
|
511
|
+
...VIEW_BASE_STYLE,
|
|
512
|
+
flexDirection: horizontal ? 'row' : 'column',
|
|
513
|
+
minWidth: horizontal ? 'max-content' : undefined,
|
|
514
|
+
},
|
|
515
|
+
props.contentContainerClassName as string | undefined
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
return React.createElement(
|
|
519
|
+
'div',
|
|
520
|
+
{
|
|
521
|
+
...domAttrs,
|
|
522
|
+
ref: domRef,
|
|
523
|
+
style: outerStyle,
|
|
524
|
+
onScroll: typeof props.onScroll === 'function' ? props.onScroll : undefined,
|
|
525
|
+
},
|
|
526
|
+
React.createElement('div', { style: innerStyle }, props.children as React.ReactNode)
|
|
527
|
+
);
|
|
528
|
+
});
|
|
529
|
+
ScrollView.displayName = 'ScrollView';
|
|
530
|
+
|
|
531
|
+
function renderSlotComponent(slot: unknown): React.ReactNode {
|
|
532
|
+
if (!slot) return null;
|
|
533
|
+
if (React.isValidElement(slot)) return slot;
|
|
534
|
+
if (typeof slot === 'function') {
|
|
535
|
+
const Comp = slot as React.ComponentType;
|
|
536
|
+
return React.createElement(Comp);
|
|
537
|
+
}
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export const FlatList = forwardRef<unknown, Record<string, unknown>>(function FlatList(props, ref) {
|
|
542
|
+
const data = Array.isArray(props.data) ? (props.data as unknown[]) : [];
|
|
543
|
+
const renderItem =
|
|
544
|
+
typeof props.renderItem === 'function'
|
|
545
|
+
? (props.renderItem as (info: {
|
|
546
|
+
item: unknown;
|
|
547
|
+
index: number;
|
|
548
|
+
separators: {
|
|
549
|
+
highlight: () => void;
|
|
550
|
+
unhighlight: () => void;
|
|
551
|
+
updateProps: () => void;
|
|
552
|
+
};
|
|
553
|
+
}) => React.ReactNode)
|
|
554
|
+
: null;
|
|
555
|
+
const keyExtractor =
|
|
556
|
+
typeof props.keyExtractor === 'function'
|
|
557
|
+
? (props.keyExtractor as (item: unknown, index: number) => string)
|
|
558
|
+
: (item: unknown, index: number) => {
|
|
559
|
+
if (item && typeof item === 'object' && 'id' in item) {
|
|
560
|
+
return String((item as Record<string, unknown>).id);
|
|
561
|
+
}
|
|
562
|
+
if (item && typeof item === 'object' && 'key' in item) {
|
|
563
|
+
return String((item as Record<string, unknown>).key);
|
|
564
|
+
}
|
|
565
|
+
return String(index);
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const numColumns =
|
|
569
|
+
typeof props.numColumns === 'number' && props.numColumns > 1 ? props.numColumns : 1;
|
|
570
|
+
const separators = {
|
|
571
|
+
highlight: () => undefined,
|
|
572
|
+
unhighlight: () => undefined,
|
|
573
|
+
updateProps: () => undefined,
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
const renderedItems: React.ReactNode[] = [];
|
|
577
|
+
if (data.length === 0) {
|
|
578
|
+
renderedItems.push(
|
|
579
|
+
React.createElement(
|
|
580
|
+
React.Fragment,
|
|
581
|
+
{ key: '__empty' },
|
|
582
|
+
renderSlotComponent(props.ListEmptyComponent)
|
|
583
|
+
)
|
|
584
|
+
);
|
|
585
|
+
} else if (renderItem) {
|
|
586
|
+
if (numColumns > 1) {
|
|
587
|
+
for (let i = 0; i < data.length; i += numColumns) {
|
|
588
|
+
const rowSlice = data.slice(i, i + numColumns);
|
|
589
|
+
const rowStyle = toDomStyle(props.columnWrapperStyle as RnStyle, {
|
|
590
|
+
...VIEW_BASE_STYLE,
|
|
591
|
+
flexDirection: 'row',
|
|
592
|
+
});
|
|
593
|
+
renderedItems.push(
|
|
594
|
+
React.createElement(
|
|
595
|
+
'div',
|
|
596
|
+
{ key: `row_${i}`, style: rowStyle },
|
|
597
|
+
rowSlice.map((item, colIdx) => {
|
|
598
|
+
const idx = i + colIdx;
|
|
599
|
+
return React.createElement(
|
|
600
|
+
React.Fragment,
|
|
601
|
+
{ key: keyExtractor(item, idx) },
|
|
602
|
+
renderItem({ item, index: idx, separators })
|
|
603
|
+
);
|
|
604
|
+
})
|
|
605
|
+
)
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
} else {
|
|
609
|
+
data.forEach((item, index) => {
|
|
610
|
+
if (index > 0 && props.ItemSeparatorComponent) {
|
|
611
|
+
renderedItems.push(
|
|
612
|
+
React.createElement(
|
|
613
|
+
React.Fragment,
|
|
614
|
+
{ key: `sep_${index}` },
|
|
615
|
+
renderSlotComponent(props.ItemSeparatorComponent)
|
|
616
|
+
)
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
renderedItems.push(
|
|
620
|
+
React.createElement(
|
|
621
|
+
React.Fragment,
|
|
622
|
+
{ key: keyExtractor(item, index) },
|
|
623
|
+
renderItem({ item, index, separators })
|
|
624
|
+
)
|
|
625
|
+
);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return React.createElement(
|
|
631
|
+
ScrollView,
|
|
632
|
+
{ ...props, ref },
|
|
633
|
+
renderSlotComponent(props.ListHeaderComponent),
|
|
634
|
+
...renderedItems,
|
|
635
|
+
renderSlotComponent(props.ListFooterComponent)
|
|
636
|
+
);
|
|
637
|
+
});
|
|
638
|
+
FlatList.displayName = 'FlatList';
|
|
639
|
+
|
|
640
|
+
export const SectionList = forwardRef<unknown, Record<string, unknown>>(function SectionList(
|
|
641
|
+
props,
|
|
642
|
+
ref
|
|
643
|
+
) {
|
|
644
|
+
const sections = Array.isArray(props.sections)
|
|
645
|
+
? (props.sections as Array<{ data?: unknown[]; [k: string]: unknown }>)
|
|
646
|
+
: [];
|
|
647
|
+
const renderItem =
|
|
648
|
+
typeof props.renderItem === 'function'
|
|
649
|
+
? (props.renderItem as (info: {
|
|
650
|
+
item: unknown;
|
|
651
|
+
index: number;
|
|
652
|
+
section: unknown;
|
|
653
|
+
separators: Record<string, () => void>;
|
|
654
|
+
}) => React.ReactNode)
|
|
655
|
+
: null;
|
|
656
|
+
const renderSectionHeader =
|
|
657
|
+
typeof props.renderSectionHeader === 'function'
|
|
658
|
+
? (props.renderSectionHeader as (info: { section: unknown }) => React.ReactNode)
|
|
659
|
+
: null;
|
|
660
|
+
const renderSectionFooter =
|
|
661
|
+
typeof props.renderSectionFooter === 'function'
|
|
662
|
+
? (props.renderSectionFooter as (info: { section: unknown }) => React.ReactNode)
|
|
663
|
+
: null;
|
|
664
|
+
|
|
665
|
+
const separators = {
|
|
666
|
+
highlight: () => undefined,
|
|
667
|
+
unhighlight: () => undefined,
|
|
668
|
+
updateProps: () => undefined,
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const children: React.ReactNode[] = [];
|
|
672
|
+
if (sections.length === 0) {
|
|
673
|
+
children.push(
|
|
674
|
+
React.createElement(
|
|
675
|
+
React.Fragment,
|
|
676
|
+
{ key: '__empty' },
|
|
677
|
+
renderSlotComponent(props.ListEmptyComponent)
|
|
678
|
+
)
|
|
679
|
+
);
|
|
680
|
+
} else {
|
|
681
|
+
sections.forEach((section, sIdx) => {
|
|
682
|
+
if ( renderSectionHeader) {
|
|
683
|
+
children.push(
|
|
684
|
+
React.createElement(
|
|
685
|
+
React.Fragment,
|
|
686
|
+
{ key: `sec_hdr_${sIdx}` },
|
|
687
|
+
renderSectionHeader({ section })
|
|
688
|
+
)
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
const items = Array.isArray(section?.data) ? section.data : [];
|
|
692
|
+
items.forEach((item, iIdx) => {
|
|
693
|
+
if (iIdx > 0 && props.ItemSeparatorComponent) {
|
|
694
|
+
children.push(
|
|
695
|
+
React.createElement(
|
|
696
|
+
React.Fragment,
|
|
697
|
+
{ key: `sec_${sIdx}_sep_${iIdx}` },
|
|
698
|
+
renderSlotComponent(props.ItemSeparatorComponent)
|
|
699
|
+
)
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
if (renderItem) {
|
|
703
|
+
children.push(
|
|
704
|
+
React.createElement(
|
|
705
|
+
React.Fragment,
|
|
706
|
+
{ key: `sec_${sIdx}_item_${iIdx}` },
|
|
707
|
+
renderItem({ item, index: iIdx, section, separators })
|
|
708
|
+
)
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
if (renderSectionFooter) {
|
|
713
|
+
children.push(
|
|
714
|
+
React.createElement(
|
|
715
|
+
React.Fragment,
|
|
716
|
+
{ key: `sec_ftr_${sIdx}` },
|
|
717
|
+
renderSectionFooter({ section })
|
|
718
|
+
)
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return React.createElement(
|
|
725
|
+
ScrollView,
|
|
726
|
+
{ ...props, ref },
|
|
727
|
+
renderSlotComponent(props.ListHeaderComponent),
|
|
728
|
+
...children,
|
|
729
|
+
renderSlotComponent(props.ListFooterComponent)
|
|
730
|
+
);
|
|
731
|
+
});
|
|
732
|
+
SectionList.displayName = 'SectionList';
|
|
733
|
+
|
|
734
|
+
export const VirtualizedList = FlatList;
|
|
735
|
+
|
|
736
|
+
export const SafeAreaView = forwardRef<HTMLDivElement, Record<string, unknown>>(
|
|
737
|
+
function SafeAreaView(props, ref) {
|
|
738
|
+
return React.createElement(View, {
|
|
739
|
+
...props,
|
|
740
|
+
ref,
|
|
741
|
+
style: [{ flex: 1 }, props.style as RnStyle],
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
);
|
|
745
|
+
SafeAreaView.displayName = 'SafeAreaView';
|
|
746
|
+
|
|
747
|
+
export const KeyboardAvoidingView = forwardRef<HTMLDivElement, Record<string, unknown>>(
|
|
748
|
+
function KeyboardAvoidingView(props, ref) {
|
|
749
|
+
return React.createElement(View, {
|
|
750
|
+
...props,
|
|
751
|
+
ref,
|
|
752
|
+
style: [{ flex: 1 }, props.style as RnStyle],
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
KeyboardAvoidingView.displayName = 'KeyboardAvoidingView';
|
|
757
|
+
|
|
758
|
+
export const TextInput = forwardRef<unknown, Record<string, unknown>>(function TextInput(
|
|
759
|
+
props,
|
|
760
|
+
ref
|
|
761
|
+
) {
|
|
762
|
+
const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);
|
|
763
|
+
useSimulatedLayout(props.onLayout);
|
|
764
|
+
|
|
765
|
+
useImperativeHandle(ref, () => ({
|
|
766
|
+
focus: () => inputRef.current?.focus(),
|
|
767
|
+
blur: () => inputRef.current?.blur(),
|
|
768
|
+
clear: () => {
|
|
769
|
+
if (inputRef.current) inputRef.current.value = '';
|
|
770
|
+
},
|
|
771
|
+
isFocused: () =>
|
|
772
|
+
typeof document !== 'undefined' && document.activeElement === inputRef.current,
|
|
773
|
+
}));
|
|
774
|
+
|
|
775
|
+
const domAttrs = extractDomAttributes(props);
|
|
776
|
+
const style = toDomStyle(
|
|
777
|
+
props.style as RnStyle,
|
|
778
|
+
{
|
|
779
|
+
boxSizing: 'border-box',
|
|
780
|
+
fontFamily:
|
|
781
|
+
'var(--font-sans, "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)',
|
|
782
|
+
fontSize: 14,
|
|
783
|
+
color: '#0F172A',
|
|
784
|
+
backgroundColor: 'transparent',
|
|
785
|
+
borderWidth: 0,
|
|
786
|
+
outline: 'none',
|
|
787
|
+
padding: 0,
|
|
788
|
+
margin: 0,
|
|
789
|
+
},
|
|
790
|
+
props.className as string | undefined
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
const multiline = Boolean(props.multiline);
|
|
794
|
+
const editable = props.editable !== false;
|
|
795
|
+
const onChangeText =
|
|
796
|
+
typeof props.onChangeText === 'function'
|
|
797
|
+
? (props.onChangeText as (text: string) => void)
|
|
798
|
+
: undefined;
|
|
799
|
+
const onChange =
|
|
800
|
+
typeof props.onChange === 'function' ? (props.onChange as (e: unknown) => void) : undefined;
|
|
801
|
+
const onSubmitEditing =
|
|
802
|
+
typeof props.onSubmitEditing === 'function'
|
|
803
|
+
? (props.onSubmitEditing as (e: unknown) => void)
|
|
804
|
+
: undefined;
|
|
805
|
+
|
|
806
|
+
const commonProps: Record<string, unknown> = {
|
|
807
|
+
...domAttrs,
|
|
808
|
+
ref: inputRef,
|
|
809
|
+
style,
|
|
810
|
+
placeholder: typeof props.placeholder === 'string' ? props.placeholder : undefined,
|
|
811
|
+
readOnly: !editable,
|
|
812
|
+
disabled: !editable,
|
|
813
|
+
maxLength: typeof props.maxLength === 'number' ? props.maxLength : undefined,
|
|
814
|
+
onFocus: typeof props.onFocus === 'function' ? props.onFocus : undefined,
|
|
815
|
+
onBlur: typeof props.onBlur === 'function' ? props.onBlur : undefined,
|
|
816
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
817
|
+
onChange?.({ nativeEvent: { text: e.target.value } });
|
|
818
|
+
onChangeText?.(e.target.value);
|
|
819
|
+
},
|
|
820
|
+
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
821
|
+
if (!multiline && e.key === 'Enter' && onSubmitEditing) {
|
|
822
|
+
onSubmitEditing({ nativeEvent: { text: e.currentTarget.value } });
|
|
823
|
+
}
|
|
824
|
+
},
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
if (props.value !== undefined) {
|
|
828
|
+
commonProps.value = String(props.value ?? '');
|
|
829
|
+
} else if (props.defaultValue !== undefined) {
|
|
830
|
+
commonProps.defaultValue = String(props.defaultValue ?? '');
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (multiline) {
|
|
834
|
+
return React.createElement('textarea', {
|
|
835
|
+
...commonProps,
|
|
836
|
+
rows: typeof props.numberOfLines === 'number' ? props.numberOfLines : 3,
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
return React.createElement('input', {
|
|
841
|
+
...commonProps,
|
|
842
|
+
type: props.secureTextEntry ? 'password' : 'text',
|
|
843
|
+
});
|
|
844
|
+
});
|
|
845
|
+
TextInput.displayName = 'TextInput';
|
|
846
|
+
|
|
847
|
+
function resolveImageUri(source: unknown): string {
|
|
848
|
+
if (typeof source === 'string') return source;
|
|
849
|
+
if (Array.isArray(source) && source[0] && typeof source[0] === 'object') {
|
|
850
|
+
return String((source[0] as Record<string, unknown>).uri ?? '');
|
|
851
|
+
}
|
|
852
|
+
if (source && typeof source === 'object') {
|
|
853
|
+
return String((source as Record<string, unknown>).uri ?? '');
|
|
854
|
+
}
|
|
855
|
+
return '';
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
const BaseImage = forwardRef<HTMLDivElement, Record<string, unknown>>(function Image(props, ref) {
|
|
859
|
+
useSimulatedLayout(props.onLayout);
|
|
860
|
+
const domAttrs = extractDomAttributes(props);
|
|
861
|
+
const uri = resolveImageUri(props.source ?? props.src);
|
|
862
|
+
const flatStyle = flattenStyle(props.style as RnStyle);
|
|
863
|
+
const resizeMode = String(
|
|
864
|
+
props.resizeMode ?? flatStyle.resizeMode ?? 'cover'
|
|
865
|
+
) as React.CSSProperties['objectFit'];
|
|
866
|
+
|
|
867
|
+
const style = toDomStyle(
|
|
868
|
+
props.style as RnStyle,
|
|
869
|
+
{
|
|
870
|
+
...VIEW_BASE_STYLE,
|
|
871
|
+
overflow: 'hidden',
|
|
872
|
+
},
|
|
873
|
+
props.className as string | undefined
|
|
874
|
+
);
|
|
875
|
+
|
|
876
|
+
return React.createElement(
|
|
877
|
+
'div',
|
|
878
|
+
{
|
|
879
|
+
...domAttrs,
|
|
880
|
+
ref,
|
|
881
|
+
style,
|
|
882
|
+
},
|
|
883
|
+
uri
|
|
884
|
+
? React.createElement('img', {
|
|
885
|
+
src: uri,
|
|
886
|
+
alt: (props.accessibilityLabel as string | undefined) ?? '',
|
|
887
|
+
draggable: false,
|
|
888
|
+
style: {
|
|
889
|
+
width: '100%',
|
|
890
|
+
height: '100%',
|
|
891
|
+
objectFit: resizeMode === 'stretch' ? 'fill' : resizeMode,
|
|
892
|
+
display: 'block',
|
|
893
|
+
},
|
|
894
|
+
onLoad: typeof props.onLoad === 'function' ? props.onLoad : undefined,
|
|
895
|
+
onError: typeof props.onError === 'function' ? props.onError : undefined,
|
|
896
|
+
})
|
|
897
|
+
: null
|
|
898
|
+
);
|
|
899
|
+
});
|
|
900
|
+
BaseImage.displayName = 'Image';
|
|
901
|
+
|
|
902
|
+
export const Image = Object.assign(BaseImage, {
|
|
903
|
+
getSize: (
|
|
904
|
+
_uri: string,
|
|
905
|
+
success?: (width: number, height: number) => void
|
|
906
|
+
) => {
|
|
907
|
+
success?.(393, 240);
|
|
908
|
+
},
|
|
909
|
+
getSizeWithHeaders: (
|
|
910
|
+
_uri: string,
|
|
911
|
+
_headers: Record<string, string>,
|
|
912
|
+
success?: (width: number, height: number) => void
|
|
913
|
+
) => {
|
|
914
|
+
success?.(393, 240);
|
|
915
|
+
},
|
|
916
|
+
prefetch: async () => true,
|
|
917
|
+
abortPrefetch: () => undefined,
|
|
918
|
+
queryCache: async () => ({}),
|
|
919
|
+
resolveAssetSource: (source: unknown) => ({
|
|
920
|
+
uri: resolveImageUri(source),
|
|
921
|
+
width: 393,
|
|
922
|
+
height: 240,
|
|
923
|
+
scale: 1,
|
|
924
|
+
}),
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
export const ImageBackground = forwardRef<HTMLDivElement, Record<string, unknown>>(
|
|
928
|
+
function ImageBackground(props, ref) {
|
|
929
|
+
const domAttrs = extractDomAttributes(props);
|
|
930
|
+
const uri = resolveImageUri(props.source);
|
|
931
|
+
const style = toDomStyle(
|
|
932
|
+
props.style as RnStyle,
|
|
933
|
+
{
|
|
934
|
+
...VIEW_BASE_STYLE,
|
|
935
|
+
overflow: 'hidden',
|
|
936
|
+
},
|
|
937
|
+
props.className as string | undefined
|
|
938
|
+
);
|
|
939
|
+
const imageStyle = toDomStyle(props.imageStyle as RnStyle, {
|
|
940
|
+
position: 'absolute',
|
|
941
|
+
top: 0,
|
|
942
|
+
left: 0,
|
|
943
|
+
right: 0,
|
|
944
|
+
bottom: 0,
|
|
945
|
+
width: '100%',
|
|
946
|
+
height: '100%',
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
return React.createElement(
|
|
950
|
+
'div',
|
|
951
|
+
{ ...domAttrs, ref, style },
|
|
952
|
+
uri
|
|
953
|
+
? React.createElement('img', {
|
|
954
|
+
src: uri,
|
|
955
|
+
alt: '',
|
|
956
|
+
draggable: false,
|
|
957
|
+
style: {
|
|
958
|
+
...imageStyle,
|
|
959
|
+
objectFit: 'cover',
|
|
960
|
+
pointerEvents: 'none',
|
|
961
|
+
},
|
|
962
|
+
})
|
|
963
|
+
: null,
|
|
964
|
+
props.children as React.ReactNode
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
ImageBackground.displayName = 'ImageBackground';
|
|
969
|
+
|
|
970
|
+
export const ActivityIndicator = forwardRef<HTMLDivElement, Record<string, unknown>>(
|
|
971
|
+
function ActivityIndicator(props, ref) {
|
|
972
|
+
if (props.animating === false) return null;
|
|
973
|
+
const domAttrs = extractDomAttributes(props);
|
|
974
|
+
const rawSize = props.size;
|
|
975
|
+
const pxSize = rawSize === 'large' ? 32 : typeof rawSize === 'number' ? rawSize : 20;
|
|
976
|
+
const color = typeof props.color === 'string' ? props.color : '#6366F1';
|
|
977
|
+
const style = toDomStyle(
|
|
978
|
+
props.style as RnStyle,
|
|
979
|
+
{
|
|
980
|
+
...VIEW_BASE_STYLE,
|
|
981
|
+
alignItems: 'center',
|
|
982
|
+
justifyContent: 'center',
|
|
983
|
+
},
|
|
984
|
+
props.className as string | undefined
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
return React.createElement(
|
|
988
|
+
'div',
|
|
989
|
+
{ ...domAttrs, ref, role: 'progressbar', style },
|
|
990
|
+
React.createElement('div', {
|
|
991
|
+
style: {
|
|
992
|
+
width: pxSize,
|
|
993
|
+
height: pxSize,
|
|
994
|
+
borderRadius: '50%',
|
|
995
|
+
border: `2.5px solid ${applyAlphaToColor(color, 0.25)}`,
|
|
996
|
+
borderTopColor: color,
|
|
997
|
+
boxSizing: 'border-box',
|
|
998
|
+
},
|
|
999
|
+
})
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
);
|
|
1003
|
+
ActivityIndicator.displayName = 'ActivityIndicator';
|
|
1004
|
+
|
|
1005
|
+
export const Switch = forwardRef<HTMLButtonElement, Record<string, unknown>>(function Switch(
|
|
1006
|
+
props,
|
|
1007
|
+
ref
|
|
1008
|
+
) {
|
|
1009
|
+
const domAttrs = extractDomAttributes(props);
|
|
1010
|
+
const value = Boolean(props.value);
|
|
1011
|
+
const disabled = Boolean(props.disabled);
|
|
1012
|
+
const trackColor = (props.trackColor as { false?: string; true?: string } | undefined) ?? {};
|
|
1013
|
+
const activeBg = trackColor.true ?? '#6366F1';
|
|
1014
|
+
const inactiveBg = trackColor.false ?? '#CBD5E1';
|
|
1015
|
+
const thumbColor = typeof props.thumbColor === 'string' ? props.thumbColor : '#FFFFFF';
|
|
1016
|
+
const onValueChange =
|
|
1017
|
+
typeof props.onValueChange === 'function'
|
|
1018
|
+
? (props.onValueChange as (next: boolean) => void)
|
|
1019
|
+
: undefined;
|
|
1020
|
+
|
|
1021
|
+
const style = toDomStyle(
|
|
1022
|
+
props.style as RnStyle,
|
|
1023
|
+
{
|
|
1024
|
+
width: 44,
|
|
1025
|
+
height: 24,
|
|
1026
|
+
borderRadius: 12,
|
|
1027
|
+
backgroundColor: value ? activeBg : inactiveBg,
|
|
1028
|
+
padding: 2,
|
|
1029
|
+
border: 'none',
|
|
1030
|
+
cursor: disabled ? 'default' : 'pointer',
|
|
1031
|
+
display: 'inline-flex',
|
|
1032
|
+
alignItems: 'center',
|
|
1033
|
+
justifyContent: value ? 'flex-end' : 'flex-start',
|
|
1034
|
+
boxSizing: 'border-box',
|
|
1035
|
+
opacity: disabled ? 0.5 : 1,
|
|
1036
|
+
},
|
|
1037
|
+
props.className as string | undefined
|
|
1038
|
+
);
|
|
1039
|
+
|
|
1040
|
+
return React.createElement(
|
|
1041
|
+
'button',
|
|
1042
|
+
{
|
|
1043
|
+
...domAttrs,
|
|
1044
|
+
ref,
|
|
1045
|
+
type: 'button',
|
|
1046
|
+
role: 'switch',
|
|
1047
|
+
'aria-checked': value,
|
|
1048
|
+
disabled,
|
|
1049
|
+
style,
|
|
1050
|
+
onClick: () => {
|
|
1051
|
+
if (!disabled) onValueChange?.(!value);
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
React.createElement('span', {
|
|
1055
|
+
style: {
|
|
1056
|
+
width: 20,
|
|
1057
|
+
height: 20,
|
|
1058
|
+
borderRadius: 10,
|
|
1059
|
+
backgroundColor: thumbColor,
|
|
1060
|
+
display: 'block',
|
|
1061
|
+
boxShadow: '0 1px 2px rgba(0,0,0,0.2)',
|
|
1062
|
+
},
|
|
1063
|
+
})
|
|
1064
|
+
);
|
|
1065
|
+
});
|
|
1066
|
+
Switch.displayName = 'Switch';
|
|
1067
|
+
|
|
1068
|
+
export const Modal: React.FC<Record<string, unknown>> = (props) => {
|
|
1069
|
+
if (props.visible !== true) return null;
|
|
1070
|
+
const domAttrs = extractDomAttributes(props);
|
|
1071
|
+
return React.createElement(
|
|
1072
|
+
'div',
|
|
1073
|
+
{
|
|
1074
|
+
...domAttrs,
|
|
1075
|
+
style: {
|
|
1076
|
+
position: 'absolute',
|
|
1077
|
+
top: 0,
|
|
1078
|
+
left: 0,
|
|
1079
|
+
right: 0,
|
|
1080
|
+
bottom: 0,
|
|
1081
|
+
zIndex: 100,
|
|
1082
|
+
display: 'flex',
|
|
1083
|
+
flexDirection: 'column',
|
|
1084
|
+
},
|
|
1085
|
+
},
|
|
1086
|
+
props.children as React.ReactNode
|
|
1087
|
+
);
|
|
1088
|
+
};
|
|
1089
|
+
Modal.displayName = 'Modal';
|
|
1090
|
+
|
|
1091
|
+
export const Button: React.FC<{
|
|
1092
|
+
title?: string;
|
|
1093
|
+
onPress?: () => void;
|
|
1094
|
+
color?: string;
|
|
1095
|
+
disabled?: boolean;
|
|
1096
|
+
testID?: string;
|
|
1097
|
+
}> = ({ title = 'Button', onPress, color = '#6366F1', disabled = false, testID }) =>
|
|
1098
|
+
React.createElement(
|
|
1099
|
+
TouchableOpacity,
|
|
1100
|
+
{
|
|
1101
|
+
onPress,
|
|
1102
|
+
disabled,
|
|
1103
|
+
testID,
|
|
1104
|
+
style: {
|
|
1105
|
+
backgroundColor: disabled ? '#94A3B8' : color,
|
|
1106
|
+
paddingVertical: 10,
|
|
1107
|
+
paddingHorizontal: 16,
|
|
1108
|
+
borderRadius: 8,
|
|
1109
|
+
alignItems: 'center',
|
|
1110
|
+
justifyContent: 'center',
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
React.createElement(
|
|
1114
|
+
Text,
|
|
1115
|
+
{ style: { color: '#FFFFFF', fontWeight: '600', fontSize: 14 } },
|
|
1116
|
+
title
|
|
1117
|
+
)
|
|
1118
|
+
);
|
|
1119
|
+
|
|
1120
|
+
export const RefreshControl: React.FC<Record<string, unknown>> = () => null;
|
|
1121
|
+
|
|
1122
|
+
export const StatusBar = Object.assign(
|
|
1123
|
+
function StatusBar(): React.ReactElement | null {
|
|
1124
|
+
return null;
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
currentHeight: 0,
|
|
1128
|
+
setBarStyle: () => undefined,
|
|
1129
|
+
setBackgroundColor: () => undefined,
|
|
1130
|
+
setHidden: () => undefined,
|
|
1131
|
+
setTranslucent: () => undefined,
|
|
1132
|
+
setNetworkActivityIndicatorVisible: () => undefined,
|
|
1133
|
+
pushStackEntry: () => ({}),
|
|
1134
|
+
popStackEntry: () => undefined,
|
|
1135
|
+
replaceStackEntry: () => ({}),
|
|
1136
|
+
}
|
|
1137
|
+
);
|
|
1138
|
+
|
|
1139
|
+
export const StyleSheet = {
|
|
1140
|
+
create: <T extends Record<string, unknown>>(styles: T): T => styles,
|
|
1141
|
+
flatten: flattenStyle,
|
|
1142
|
+
compose: (s1: unknown, s2: unknown) => [s1, s2],
|
|
1143
|
+
hairlineWidth: 1,
|
|
1144
|
+
absoluteFillObject: {
|
|
1145
|
+
position: 'absolute' as const,
|
|
1146
|
+
left: 0,
|
|
1147
|
+
right: 0,
|
|
1148
|
+
top: 0,
|
|
1149
|
+
bottom: 0,
|
|
1150
|
+
},
|
|
1151
|
+
absoluteFill: {
|
|
1152
|
+
position: 'absolute' as const,
|
|
1153
|
+
left: 0,
|
|
1154
|
+
right: 0,
|
|
1155
|
+
top: 0,
|
|
1156
|
+
bottom: 0,
|
|
1157
|
+
},
|
|
1158
|
+
setStyleAttributePreprocessor: () => undefined,
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1161
|
+
export const Platform = {
|
|
1162
|
+
OS: 'ios' as const,
|
|
1163
|
+
Version: '17.0',
|
|
1164
|
+
isPad: false,
|
|
1165
|
+
isTV: false,
|
|
1166
|
+
isTesting: false,
|
|
1167
|
+
Constants: {
|
|
1168
|
+
reactNativeVersion: { major: 0, minor: 76, patch: 0 },
|
|
1169
|
+
osVersion: '17.0',
|
|
1170
|
+
systemName: 'iOS',
|
|
1171
|
+
},
|
|
1172
|
+
select: <T,>(spec: Record<string, T>): T =>
|
|
1173
|
+
spec.ios ?? spec.default ?? spec.web ?? spec.native ?? spec.android ?? Object.values(spec)[0],
|
|
1174
|
+
};
|
|
1175
|
+
|
|
76
1176
|
export const Dimensions = {
|
|
77
1177
|
get: (_dim?: 'window' | 'screen' | string) => ARTBOARD_DIMENSIONS,
|
|
78
1178
|
set: () => undefined,
|
|
@@ -84,18 +1184,332 @@ export function useWindowDimensions() {
|
|
|
84
1184
|
return ARTBOARD_DIMENSIONS;
|
|
85
1185
|
}
|
|
86
1186
|
|
|
87
|
-
export
|
|
88
|
-
|
|
1187
|
+
export const PixelRatio = {
|
|
1188
|
+
get: () => 3,
|
|
1189
|
+
getFontScale: () => 1,
|
|
1190
|
+
getPixelSizeForLayoutSize: (size: number) => Math.round(size * 3),
|
|
1191
|
+
roundToNearestPixel: (size: number) => Math.round(size * 3) / 3,
|
|
1192
|
+
startDetecting: () => undefined,
|
|
1193
|
+
};
|
|
1194
|
+
|
|
1195
|
+
export class AnimatedValue {
|
|
1196
|
+
private _value: number;
|
|
1197
|
+
constructor(value = 0) {
|
|
1198
|
+
this._value = value;
|
|
1199
|
+
}
|
|
1200
|
+
setValue(value: number) {
|
|
1201
|
+
this._value = value;
|
|
1202
|
+
}
|
|
1203
|
+
setOffset(_offset: number) {}
|
|
1204
|
+
flattenOffset() {}
|
|
1205
|
+
extractOffset() {}
|
|
1206
|
+
addListener(_cb: (state: { value: number }) => void): string {
|
|
1207
|
+
return 'listener_0';
|
|
1208
|
+
}
|
|
1209
|
+
removeListener(_id: string) {}
|
|
1210
|
+
removeAllListeners() {}
|
|
1211
|
+
stopAnimation(cb?: (value: number) => void) {
|
|
1212
|
+
cb?.(this._value);
|
|
1213
|
+
}
|
|
1214
|
+
resetAnimation(cb?: (value: number) => void) {
|
|
1215
|
+
cb?.(this._value);
|
|
1216
|
+
}
|
|
1217
|
+
interpolate(config: { inputRange?: number[]; outputRange?: Array<number | string> }) {
|
|
1218
|
+
const out = config?.outputRange;
|
|
1219
|
+
if (Array.isArray(out) && out.length > 0) {
|
|
1220
|
+
return out[0];
|
|
1221
|
+
}
|
|
1222
|
+
return this._value;
|
|
1223
|
+
}
|
|
1224
|
+
__getValue() {
|
|
1225
|
+
return this._value;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
export class AnimatedValueXY {
|
|
1230
|
+
x: AnimatedValue;
|
|
1231
|
+
y: AnimatedValue;
|
|
1232
|
+
constructor(value?: { x?: number; y?: number }) {
|
|
1233
|
+
this.x = new AnimatedValue(value?.x ?? 0);
|
|
1234
|
+
this.y = new AnimatedValue(value?.y ?? 0);
|
|
1235
|
+
}
|
|
1236
|
+
setValue(value: { x: number; y: number }) {
|
|
1237
|
+
this.x.setValue(value.x);
|
|
1238
|
+
this.y.setValue(value.y);
|
|
1239
|
+
}
|
|
1240
|
+
setOffset(_offset: { x: number; y: number }) {}
|
|
1241
|
+
flattenOffset() {}
|
|
1242
|
+
extractOffset() {}
|
|
1243
|
+
stopAnimation(cb?: (value: { x: number; y: number }) => void) {
|
|
1244
|
+
cb?.({ x: this.x.__getValue(), y: this.y.__getValue() });
|
|
1245
|
+
}
|
|
1246
|
+
resetAnimation(cb?: (value: { x: number; y: number }) => void) {
|
|
1247
|
+
cb?.({ x: this.x.__getValue(), y: this.y.__getValue() });
|
|
1248
|
+
}
|
|
1249
|
+
getLayout() {
|
|
1250
|
+
return { left: this.x.__getValue(), top: this.y.__getValue() };
|
|
1251
|
+
}
|
|
1252
|
+
getTranslateTransform() {
|
|
1253
|
+
return [{ translateX: this.x.__getValue() }, { translateY: this.y.__getValue() }];
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
function createNoopCompositeAnimation() {
|
|
1258
|
+
return {
|
|
1259
|
+
start: (cb?: (result: { finished: boolean }) => void) => {
|
|
1260
|
+
cb?.({ finished: true });
|
|
1261
|
+
},
|
|
1262
|
+
stop: () => undefined,
|
|
1263
|
+
reset: () => undefined,
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
export function createAnimatedComponent<P extends object>(Component: React.ComponentType<P>) {
|
|
1268
|
+
return Component;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
export const Animated = {
|
|
1272
|
+
Value: AnimatedValue,
|
|
1273
|
+
ValueXY: AnimatedValueXY,
|
|
1274
|
+
View,
|
|
1275
|
+
Text,
|
|
1276
|
+
Image,
|
|
1277
|
+
ScrollView,
|
|
1278
|
+
FlatList,
|
|
1279
|
+
SectionList,
|
|
1280
|
+
createAnimatedComponent,
|
|
1281
|
+
timing: (_value: unknown, _config: unknown) => createNoopCompositeAnimation(),
|
|
1282
|
+
spring: (_value: unknown, _config: unknown) => createNoopCompositeAnimation(),
|
|
1283
|
+
decay: (_value: unknown, _config: unknown) => createNoopCompositeAnimation(),
|
|
1284
|
+
parallel: (_animations: unknown[]) => createNoopCompositeAnimation(),
|
|
1285
|
+
sequence: (_animations: unknown[]) => createNoopCompositeAnimation(),
|
|
1286
|
+
stagger: (_delay: number, _animations: unknown[]) => createNoopCompositeAnimation(),
|
|
1287
|
+
loop: (_animation: unknown) => createNoopCompositeAnimation(),
|
|
1288
|
+
delay: (_ms: number) => createNoopCompositeAnimation(),
|
|
1289
|
+
event: () => () => undefined,
|
|
1290
|
+
add: (a: unknown) => a,
|
|
1291
|
+
subtract: (a: unknown) => a,
|
|
1292
|
+
divide: (a: unknown) => a,
|
|
1293
|
+
multiply: (a: unknown) => a,
|
|
1294
|
+
modulo: (a: unknown) => a,
|
|
1295
|
+
diffClamp: (a: unknown) => a,
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
export function useAnimatedValue(initialValue = 0): AnimatedValue {
|
|
1299
|
+
const ref = useRef<AnimatedValue | null>(null);
|
|
89
1300
|
if (!ref.current) {
|
|
90
|
-
ref.current = new
|
|
1301
|
+
ref.current = new AnimatedValue(initialValue);
|
|
91
1302
|
}
|
|
92
1303
|
return ref.current;
|
|
93
1304
|
}
|
|
94
1305
|
|
|
1306
|
+
export const Easing = {
|
|
1307
|
+
step0: (n: number) => (n > 0 ? 1 : 0),
|
|
1308
|
+
step1: (n: number) => (n >= 1 ? 1 : 0),
|
|
1309
|
+
linear: (t: number) => t,
|
|
1310
|
+
ease: (t: number) => t,
|
|
1311
|
+
quad: (t: number) => t * t,
|
|
1312
|
+
cubic: (t: number) => t * t * t,
|
|
1313
|
+
poly: () => (t: number) => t,
|
|
1314
|
+
sin: (t: number) => t,
|
|
1315
|
+
circle: (t: number) => t,
|
|
1316
|
+
exp: (t: number) => t,
|
|
1317
|
+
elastic: () => (t: number) => t,
|
|
1318
|
+
back: () => (t: number) => t,
|
|
1319
|
+
bounce: (t: number) => t,
|
|
1320
|
+
bezier: () => (t: number) => t,
|
|
1321
|
+
in: (fn: (t: number) => number) => fn,
|
|
1322
|
+
out: (fn: (t: number) => number) => fn,
|
|
1323
|
+
inOut: (fn: (t: number) => number) => fn,
|
|
1324
|
+
};
|
|
1325
|
+
|
|
1326
|
+
export const Alert = {
|
|
1327
|
+
alert: (_title?: string, _message?: string, _buttons?: unknown[]) => undefined,
|
|
1328
|
+
prompt: (_title?: string, _message?: string, _callbackOrButtons?: unknown) => undefined,
|
|
1329
|
+
};
|
|
1330
|
+
|
|
1331
|
+
export const Linking = {
|
|
1332
|
+
openURL: async (_url: string) => true,
|
|
1333
|
+
canOpenURL: async (_url: string) => true,
|
|
1334
|
+
openSettings: async () => undefined,
|
|
1335
|
+
getInitialURL: async () => null,
|
|
1336
|
+
sendIntent: async () => undefined,
|
|
1337
|
+
addEventListener: () => ({ remove: () => undefined }),
|
|
1338
|
+
removeEventListener: () => undefined,
|
|
1339
|
+
};
|
|
1340
|
+
|
|
1341
|
+
export const Share = {
|
|
1342
|
+
share: async () => ({ action: 'sharedAction' }),
|
|
1343
|
+
sharedAction: 'sharedAction',
|
|
1344
|
+
dismissedAction: 'dismissedAction',
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
export const Vibration = {
|
|
1348
|
+
vibrate: () => undefined,
|
|
1349
|
+
cancel: () => undefined,
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
export const Keyboard = {
|
|
1353
|
+
dismiss: () => undefined,
|
|
1354
|
+
isVisible: () => false,
|
|
1355
|
+
metrics: () => undefined,
|
|
1356
|
+
addListener: () => ({ remove: () => undefined }),
|
|
1357
|
+
removeListener: () => undefined,
|
|
1358
|
+
removeAllListeners: () => undefined,
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
export const BackHandler = {
|
|
1362
|
+
exitApp: () => undefined,
|
|
1363
|
+
addEventListener: () => ({ remove: () => undefined }),
|
|
1364
|
+
removeEventListener: () => undefined,
|
|
1365
|
+
};
|
|
1366
|
+
|
|
1367
|
+
export const AppState = {
|
|
1368
|
+
currentState: 'active',
|
|
1369
|
+
isAvailable: true,
|
|
1370
|
+
addEventListener: () => ({ remove: () => undefined }),
|
|
1371
|
+
removeEventListener: () => undefined,
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
export const Appearance = {
|
|
1375
|
+
getColorScheme: () => 'light' as const,
|
|
1376
|
+
setColorScheme: () => undefined,
|
|
1377
|
+
addChangeListener: () => ({ remove: () => undefined }),
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
export function useColorScheme(): 'light' | 'dark' {
|
|
1381
|
+
return 'light';
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
export const PanResponder = {
|
|
1385
|
+
create: () => ({ panHandlers: {} }),
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
export const LayoutAnimation = {
|
|
1389
|
+
configureNext: (_config: unknown, onAnimationDidEnd?: () => void) => {
|
|
1390
|
+
onAnimationDidEnd?.();
|
|
1391
|
+
},
|
|
1392
|
+
create: () => ({}),
|
|
1393
|
+
Types: {
|
|
1394
|
+
spring: 'spring',
|
|
1395
|
+
linear: 'linear',
|
|
1396
|
+
easeInEaseOut: 'easeInEaseOut',
|
|
1397
|
+
easeIn: 'easeIn',
|
|
1398
|
+
easeOut: 'easeOut',
|
|
1399
|
+
keyboard: 'keyboard',
|
|
1400
|
+
},
|
|
1401
|
+
Properties: {
|
|
1402
|
+
opacity: 'opacity',
|
|
1403
|
+
scaleX: 'scaleX',
|
|
1404
|
+
scaleY: 'scaleY',
|
|
1405
|
+
scaleXY: 'scaleXY',
|
|
1406
|
+
},
|
|
1407
|
+
Presets: {
|
|
1408
|
+
easeInEaseOut: {},
|
|
1409
|
+
linear: {},
|
|
1410
|
+
spring: {},
|
|
1411
|
+
},
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
export const UIManager = {
|
|
1415
|
+
setLayoutAnimationEnabledExperimental: () => undefined,
|
|
1416
|
+
measure: (
|
|
1417
|
+
_node: unknown,
|
|
1418
|
+
callback?: (x: number, y: number, w: number, h: number, px: number, py: number) => void
|
|
1419
|
+
) => callback?.(0, 0, 393, 48, 0, 0),
|
|
1420
|
+
measureInWindow: (
|
|
1421
|
+
_node: unknown,
|
|
1422
|
+
callback?: (x: number, y: number, w: number, h: number) => void
|
|
1423
|
+
) => callback?.(0, 0, 393, 48),
|
|
1424
|
+
measureLayout: () => undefined,
|
|
1425
|
+
dispatchViewManagerCommand: () => undefined,
|
|
1426
|
+
getViewManagerConfig: () => ({}),
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
export const InteractionManager = {
|
|
1430
|
+
runAfterInteractions: (task?: () => void) => {
|
|
1431
|
+
task?.();
|
|
1432
|
+
return {
|
|
1433
|
+
then: (cb?: () => unknown) => Promise.resolve().then(cb),
|
|
1434
|
+
done: (cb?: () => unknown) => cb?.(),
|
|
1435
|
+
cancel: () => undefined,
|
|
1436
|
+
};
|
|
1437
|
+
},
|
|
1438
|
+
createInteractionHandle: () => 1,
|
|
1439
|
+
clearInteractionHandle: () => undefined,
|
|
1440
|
+
setDeadline: () => undefined,
|
|
1441
|
+
};
|
|
1442
|
+
|
|
1443
|
+
export class NativeEventEmitter {
|
|
1444
|
+
addListener() {
|
|
1445
|
+
return { remove: () => undefined };
|
|
1446
|
+
}
|
|
1447
|
+
removeAllListeners() {}
|
|
1448
|
+
removeSubscription() {}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
export const DeviceEventEmitter = new NativeEventEmitter();
|
|
1452
|
+
export const NativeAppEventEmitter = new NativeEventEmitter();
|
|
1453
|
+
|
|
1454
|
+
export const NativeModules: Record<string, Record<string, unknown>> = {
|
|
1455
|
+
StatusBarManager: { HEIGHT: 0, getHeight: (cb?: (h: { height: number }) => void) => cb?.({ height: 0 }) },
|
|
1456
|
+
PlatformConstants: { forceTouchAvailable: false, interfaceIdiom: 'phone' },
|
|
1457
|
+
SourceCode: { scriptURL: '' },
|
|
1458
|
+
UIManager,
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
export const I18nManager = {
|
|
1462
|
+
isRTL: false,
|
|
1463
|
+
doLeftAndRightSwapInRTL: true,
|
|
1464
|
+
allowRTL: () => undefined,
|
|
1465
|
+
forceRTL: () => undefined,
|
|
1466
|
+
swapLeftAndRightInRTL: () => undefined,
|
|
1467
|
+
getConstants: () => ({ isRTL: false, doLeftAndRightSwapInRTL: true }),
|
|
1468
|
+
};
|
|
1469
|
+
|
|
1470
|
+
export const AccessibilityInfo = {
|
|
1471
|
+
isBoldTextEnabled: async () => false,
|
|
1472
|
+
isGrayscaleEnabled: async () => false,
|
|
1473
|
+
isInvertColorsEnabled: async () => false,
|
|
1474
|
+
isReduceMotionEnabled: async () => false,
|
|
1475
|
+
isReduceTransparencyEnabled: async () => false,
|
|
1476
|
+
isScreenReaderEnabled: async () => false,
|
|
1477
|
+
addEventListener: () => ({ remove: () => undefined }),
|
|
1478
|
+
announceForAccessibility: () => undefined,
|
|
1479
|
+
setAccessibilityFocus: () => undefined,
|
|
1480
|
+
};
|
|
1481
|
+
|
|
1482
|
+
export const LogBox = {
|
|
1483
|
+
ignoreLogs: () => undefined,
|
|
1484
|
+
ignoreAllLogs: () => undefined,
|
|
1485
|
+
install: () => undefined,
|
|
1486
|
+
uninstall: () => undefined,
|
|
1487
|
+
};
|
|
1488
|
+
|
|
1489
|
+
export const YellowBox = {
|
|
1490
|
+
ignoreWarnings: () => undefined,
|
|
1491
|
+
};
|
|
1492
|
+
|
|
1493
|
+
export function findNodeHandle(_componentOrHandle: unknown): number | null {
|
|
1494
|
+
return null;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
export function processColor(color: unknown): unknown {
|
|
1498
|
+
return color;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
95
1501
|
export const PermissionsAndroid = {
|
|
96
|
-
PERMISSIONS:
|
|
97
|
-
|
|
98
|
-
|
|
1502
|
+
PERMISSIONS: {
|
|
1503
|
+
CAMERA: 'android.permission.CAMERA',
|
|
1504
|
+
ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION',
|
|
1505
|
+
ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION',
|
|
1506
|
+
READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE',
|
|
1507
|
+
WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE',
|
|
1508
|
+
READ_MEDIA_IMAGES: 'android.permission.READ_MEDIA_IMAGES',
|
|
1509
|
+
POST_NOTIFICATIONS: 'android.permission.POST_NOTIFICATIONS',
|
|
1510
|
+
RECORD_AUDIO: 'android.permission.RECORD_AUDIO',
|
|
1511
|
+
READ_CONTACTS: 'android.permission.READ_CONTACTS',
|
|
1512
|
+
},
|
|
99
1513
|
RESULTS: {
|
|
100
1514
|
GRANTED: 'granted',
|
|
101
1515
|
DENIED: 'denied',
|
|
@@ -130,7 +1544,7 @@ export const DrawerLayoutAndroid: React.FC<{
|
|
|
130
1544
|
children?: React.ReactNode;
|
|
131
1545
|
style?: unknown;
|
|
132
1546
|
}> = ({ children, style }) =>
|
|
133
|
-
React.createElement(
|
|
1547
|
+
React.createElement(View, { style: [{ flex: 1 }, style] as never }, children);
|
|
134
1548
|
|
|
135
1549
|
export const TurboModuleRegistry = {
|
|
136
1550
|
get: () => ({}),
|
|
@@ -141,7 +1555,7 @@ export function requireNativeComponent(viewName: string) {
|
|
|
141
1555
|
const Comp: React.FC<{ children?: React.ReactNode; style?: unknown }> = ({
|
|
142
1556
|
children,
|
|
143
1557
|
style,
|
|
144
|
-
}) => React.createElement(
|
|
1558
|
+
}) => React.createElement(View, { style: style as never }, children);
|
|
145
1559
|
Comp.displayName = viewName;
|
|
146
1560
|
return Comp;
|
|
147
1561
|
}
|
|
@@ -187,54 +1601,74 @@ export const Settings = {
|
|
|
187
1601
|
clearWatch: () => undefined,
|
|
188
1602
|
};
|
|
189
1603
|
|
|
190
|
-
const ReactNativeDefault =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1604
|
+
const ReactNativeDefault = {
|
|
1605
|
+
View,
|
|
1606
|
+
Text,
|
|
1607
|
+
Pressable,
|
|
1608
|
+
TouchableOpacity,
|
|
1609
|
+
TouchableHighlight,
|
|
1610
|
+
TouchableWithoutFeedback,
|
|
1611
|
+
TouchableNativeFeedback,
|
|
1612
|
+
ScrollView,
|
|
1613
|
+
FlatList,
|
|
1614
|
+
SectionList,
|
|
1615
|
+
VirtualizedList,
|
|
1616
|
+
KeyboardAvoidingView,
|
|
1617
|
+
TextInput,
|
|
1618
|
+
Image,
|
|
1619
|
+
ImageBackground,
|
|
1620
|
+
SafeAreaView,
|
|
1621
|
+
ActivityIndicator,
|
|
1622
|
+
Switch,
|
|
1623
|
+
Modal,
|
|
1624
|
+
Button,
|
|
1625
|
+
RefreshControl,
|
|
1626
|
+
StatusBar,
|
|
1627
|
+
StyleSheet,
|
|
1628
|
+
Platform,
|
|
1629
|
+
Dimensions,
|
|
1630
|
+
useWindowDimensions,
|
|
1631
|
+
PixelRatio,
|
|
1632
|
+
Animated,
|
|
1633
|
+
useAnimatedValue,
|
|
1634
|
+
Easing,
|
|
1635
|
+
Alert,
|
|
1636
|
+
Linking,
|
|
1637
|
+
Share,
|
|
1638
|
+
Vibration,
|
|
1639
|
+
Keyboard,
|
|
1640
|
+
BackHandler,
|
|
1641
|
+
AppState,
|
|
1642
|
+
Appearance,
|
|
1643
|
+
useColorScheme,
|
|
1644
|
+
PanResponder,
|
|
1645
|
+
LayoutAnimation,
|
|
1646
|
+
UIManager,
|
|
1647
|
+
InteractionManager,
|
|
1648
|
+
NativeEventEmitter,
|
|
1649
|
+
DeviceEventEmitter,
|
|
1650
|
+
NativeAppEventEmitter,
|
|
1651
|
+
NativeModules,
|
|
1652
|
+
I18nManager,
|
|
1653
|
+
AccessibilityInfo,
|
|
1654
|
+
LogBox,
|
|
1655
|
+
YellowBox,
|
|
1656
|
+
findNodeHandle,
|
|
1657
|
+
processColor,
|
|
1658
|
+
PermissionsAndroid,
|
|
1659
|
+
ToastAndroid,
|
|
1660
|
+
ActionSheetIOS,
|
|
1661
|
+
InputAccessoryView,
|
|
1662
|
+
DrawerLayoutAndroid,
|
|
1663
|
+
TurboModuleRegistry,
|
|
1664
|
+
requireNativeComponent,
|
|
1665
|
+
codegenNativeComponent,
|
|
1666
|
+
PlatformColor,
|
|
1667
|
+
DynamicColorIOS,
|
|
1668
|
+
DevSettings,
|
|
1669
|
+
Systrace,
|
|
1670
|
+
Networking,
|
|
1671
|
+
Settings,
|
|
1672
|
+
};
|
|
239
1673
|
|
|
240
1674
|
export default ReactNativeDefault;
|