deskforge 1.0.0 → 1.0.1
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/COMPLETION_REPORT.md +426 -0
- package/COMPONENT_API.md +529 -0
- package/DELIVERY_SUMMARY.md +455 -0
- package/IMPLEMENTATION_GUIDE.md +385 -0
- package/IMPORT_GUIDE.md +404 -0
- package/QUICK_REFERENCE.md +352 -0
- package/README.md +245 -31
- package/README_UI_COMPLETE.md +395 -0
- package/TYPE_DEFINITIONS.md +671 -0
- package/UI_GETTING_STARTED.md +523 -0
- package/examples/deskforge-app/App.ts +7 -11
- package/examples/deskforge-app/screens/CounterApp.ts +181 -0
- package/examples/deskforge-app/screens/GalleryApp.ts +267 -0
- package/examples/deskforge-app/screens/NotesApp.ts +376 -0
- package/examples/deskforge-app/screens/SettingsApp.ts +226 -0
- package/examples/deskforge-app/screens/TodoApp.ts +288 -0
- package/examples/deskforge-app/screens/index.ts +50 -0
- package/package.json +1 -1
- package/packages/cli/dist/commands/start.d.ts +7 -1
- package/packages/cli/dist/commands/start.d.ts.map +1 -1
- package/packages/cli/dist/commands/start.js +75 -21
- package/packages/cli/dist/commands/start.js.map +1 -1
- package/packages/cli/src/commands/start.ts +93 -21
- package/packages/cli/test/start.test.js +24 -0
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/style/StyleObject.d.ts +115 -0
- package/packages/core/dist/style/StyleObject.d.ts.map +1 -0
- package/packages/core/dist/style/StyleObject.js +6 -0
- package/packages/core/dist/style/StyleObject.js.map +1 -0
- package/packages/core/dist/style/StyleSheet.d.ts +7 -0
- package/packages/core/dist/style/StyleSheet.d.ts.map +1 -0
- package/packages/core/dist/style/StyleSheet.js +13 -0
- package/packages/core/dist/style/StyleSheet.js.map +1 -0
- package/packages/core/dist/style/index.d.ts +3 -0
- package/packages/core/dist/style/index.d.ts.map +1 -0
- package/packages/core/dist/style/index.js +21 -0
- package/packages/core/dist/style/index.js.map +1 -0
- package/packages/core/src/index.ts +2 -1
- package/packages/core/src/style/StyleObject.ts +134 -0
- package/packages/core/src/style/StyleSheet.ts +19 -0
- package/packages/core/src/style/index.ts +5 -0
- package/packages/db/src/db.ts +4 -4
- package/packages/deskforge/src/index.ts +95 -0
- package/packages/file/dist/file.d.ts +1 -1
- package/packages/file/dist/file.d.ts.map +1 -1
- package/packages/file/dist/file.js +75 -3
- package/packages/file/dist/file.js.map +1 -1
- package/packages/file/src/file.ts +96 -4
- package/packages/file/test/file.test.js +23 -0
- package/packages/router/dist/index.d.ts +1 -0
- package/packages/router/dist/index.d.ts.map +1 -1
- package/packages/router/dist/index.js +1 -0
- package/packages/router/dist/index.js.map +1 -1
- package/packages/router/dist/navigation.d.ts +23 -0
- package/packages/router/dist/navigation.d.ts.map +1 -0
- package/packages/router/dist/navigation.js +61 -0
- package/packages/router/dist/navigation.js.map +1 -0
- package/packages/router/src/index.ts +2 -1
- package/packages/router/src/navigation.ts +86 -0
- package/packages/router/test/router.test.js +21 -1
- package/packages/theme/src/theme.ts +23 -0
- package/packages/ui/src/base/Button.ts +67 -0
- package/packages/ui/src/base/Image.ts +59 -0
- package/packages/ui/src/base/Pressable.ts +69 -0
- package/packages/ui/src/base/Text.ts +42 -0
- package/packages/ui/src/base/TextInput.ts +113 -0
- package/packages/ui/src/base/TouchableOpacity.ts +52 -0
- package/packages/ui/src/base/View.ts +43 -0
- package/packages/ui/src/index.ts +40 -25
- package/packages/ui/src/input/CheckBox.ts +69 -0
- package/packages/ui/src/input/Slider.ts +19 -2
- package/packages/ui/src/input/Switch.ts +68 -0
- package/packages/ui/src/layout/KeyboardAvoidingView.ts +65 -0
- package/packages/ui/src/layout/SafeAreaView.ts +58 -0
- package/packages/ui/src/list/FlatList.ts +111 -0
- package/packages/ui/src/list/ScrollView.ts +80 -0
- package/packages/ui/src/list/SectionList.ts +120 -0
- package/packages/ui/src/overlay/ActivityIndicator.ts +70 -0
- package/packages/ui/src/overlay/Modal.ts +28 -6
- package/packages/ui/src/platform/Platform.ts +119 -0
- package/packages/ui/src/platform/StatusBar.ts +63 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeskForge UI Components - Migration & Getting Started Guide
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
# DeskForge UI Components - Getting Started
|
|
6
|
+
|
|
7
|
+
## What Changed
|
|
8
|
+
|
|
9
|
+
DeskForge UI has been completely rewritten to use **pure functional syntax without JSX**.
|
|
10
|
+
|
|
11
|
+
### Before (Old Syntax)
|
|
12
|
+
```tsx
|
|
13
|
+
// Old JSX-based approach (NOT USED)
|
|
14
|
+
export const MyComponent = () => {
|
|
15
|
+
const [count, setCount] = useState(0)
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<View style={styles.container}>
|
|
19
|
+
<Text style={styles.title}>Count: {count}</Text>
|
|
20
|
+
<Pressable onPress={() => setCount(count + 1)}>
|
|
21
|
+
<Text>Increment</Text>
|
|
22
|
+
</Pressable>
|
|
23
|
+
</View>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### After (New Syntax)
|
|
29
|
+
```typescript
|
|
30
|
+
// New pure functional approach
|
|
31
|
+
const MyComponent = () => {
|
|
32
|
+
const state = State({ count: 0 })
|
|
33
|
+
|
|
34
|
+
return View(styles.container, [
|
|
35
|
+
Text(`Count: ${state.count}`, styles.title),
|
|
36
|
+
Pressable({ padding: 12 }, {
|
|
37
|
+
onPress: () => state.count++,
|
|
38
|
+
}, [
|
|
39
|
+
Text('Increment'),
|
|
40
|
+
]),
|
|
41
|
+
])
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Key Differences
|
|
46
|
+
|
|
47
|
+
| Aspect | Old | New |
|
|
48
|
+
|--------|-----|-----|
|
|
49
|
+
| **Syntax** | JSX/TSX with angle brackets | Pure function calls |
|
|
50
|
+
| **State** | `useState()` with `setState()` | `State()` with direct mutations |
|
|
51
|
+
| **Hooks** | `useState`, `useEffect`, etc | `State()`, `Effect()`, `Computed()` |
|
|
52
|
+
| **Styling** | CSS classes or inline style objects | StyleObject only (React Native props) |
|
|
53
|
+
| **Returns** | JSX elements | DFNode objects |
|
|
54
|
+
| **Files** | `.tsx` or `.jsx` | `.ts` (pure TypeScript) |
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install @deskforge/ui @deskforge/state @deskforge/core
|
|
60
|
+
# or
|
|
61
|
+
yarn add @deskforge/ui @deskforge/state @deskforge/core
|
|
62
|
+
# or monorepo
|
|
63
|
+
yarn workspaces run build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
### 1. Import Components
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import {
|
|
72
|
+
View, Text, Pressable, Button,
|
|
73
|
+
FlatList, TextInput, Modal,
|
|
74
|
+
StyleSheet, Platform,
|
|
75
|
+
} from 'deskforge'
|
|
76
|
+
|
|
77
|
+
import { State, Computed, Effect } from 'deskforge/state'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 2. Create Styles
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const styles = StyleSheet.create({
|
|
84
|
+
container: {
|
|
85
|
+
flex: 1,
|
|
86
|
+
backgroundColor: '#f8f9fc',
|
|
87
|
+
padding: 16,
|
|
88
|
+
},
|
|
89
|
+
button: {
|
|
90
|
+
backgroundColor: '#0077ff',
|
|
91
|
+
borderRadius: 8,
|
|
92
|
+
paddingVertical: 12,
|
|
93
|
+
paddingHorizontal: 16,
|
|
94
|
+
},
|
|
95
|
+
buttonText: {
|
|
96
|
+
color: '#ffffff',
|
|
97
|
+
fontWeight: 'bold',
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. Create State
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const state = State({
|
|
106
|
+
count: 0,
|
|
107
|
+
name: '',
|
|
108
|
+
items: [],
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4. Build UI
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
export const MyApp = () => {
|
|
116
|
+
return View(styles.container, [
|
|
117
|
+
Text(`Count: ${state.count}`, { fontSize: 20 }),
|
|
118
|
+
|
|
119
|
+
Button('Increment', styles.button, {
|
|
120
|
+
onPress: () => state.count++,
|
|
121
|
+
}),
|
|
122
|
+
])
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Component Syntax
|
|
127
|
+
|
|
128
|
+
### View (Container)
|
|
129
|
+
```typescript
|
|
130
|
+
View(
|
|
131
|
+
{ flex: 1, backgroundColor: '#fff' }, // style
|
|
132
|
+
[ // children
|
|
133
|
+
Text('Content'),
|
|
134
|
+
Text('More content'),
|
|
135
|
+
]
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Text
|
|
140
|
+
```typescript
|
|
141
|
+
Text('Hello', { fontSize: 16, color: '#000' })
|
|
142
|
+
Text(42) // Numbers work too
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Pressable (Button-like)
|
|
146
|
+
```typescript
|
|
147
|
+
Pressable(
|
|
148
|
+
{ padding: 12 }, // style
|
|
149
|
+
{ // handlers
|
|
150
|
+
onPress: () => handlePress(),
|
|
151
|
+
onLongPress: () => handleLongPress(),
|
|
152
|
+
disabled: false,
|
|
153
|
+
},
|
|
154
|
+
[Text('Press me')] // children
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Button (Quick)
|
|
159
|
+
```typescript
|
|
160
|
+
Button(
|
|
161
|
+
'Click Me', // title
|
|
162
|
+
{ backgroundColor: '#0077ff' }, // style
|
|
163
|
+
{ onPress: () => handleClick() } // handlers
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### TextInput
|
|
168
|
+
```typescript
|
|
169
|
+
TextInput(
|
|
170
|
+
{ flex: 1, borderWidth: 1, padding: 12 }, // style
|
|
171
|
+
{ // props
|
|
172
|
+
placeholder: 'Enter text',
|
|
173
|
+
value: state.text,
|
|
174
|
+
onChangeText: (text) => state.text = text,
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### FlatList (Lists)
|
|
180
|
+
```typescript
|
|
181
|
+
FlatList(
|
|
182
|
+
items, // data
|
|
183
|
+
(item) => Text(item.name), // renderItem
|
|
184
|
+
{ flex: 1 }, // style
|
|
185
|
+
{ onEndReached: () => loadMore() } // optional props
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Switch (Toggle)
|
|
190
|
+
```typescript
|
|
191
|
+
Switch(
|
|
192
|
+
state.darkMode, // value
|
|
193
|
+
(value) => state.darkMode = value, // onValueChange
|
|
194
|
+
{ onTintColor: '#0077ff' } // optional props
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Slider (Range)
|
|
199
|
+
```typescript
|
|
200
|
+
Slider({ width: 200 }, {
|
|
201
|
+
value: state.volume,
|
|
202
|
+
minimumValue: 0,
|
|
203
|
+
maximumValue: 100,
|
|
204
|
+
onValueChange: (v) => state.volume = v,
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Image
|
|
209
|
+
```typescript
|
|
210
|
+
Image('/assets/logo.png', { width: 100, height: 100 })
|
|
211
|
+
Image({ uri: 'https://example.com/image.jpg' })
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Modal (Overlay)
|
|
215
|
+
```typescript
|
|
216
|
+
Modal(
|
|
217
|
+
state.isOpen, // visible
|
|
218
|
+
() => state.isOpen = false, // onClose
|
|
219
|
+
{ flex: 1, justifyContent: 'center' }, // style
|
|
220
|
+
[ // children
|
|
221
|
+
View({}, [Text('Modal content')])
|
|
222
|
+
]
|
|
223
|
+
)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## State Management
|
|
227
|
+
|
|
228
|
+
### Basic State
|
|
229
|
+
```typescript
|
|
230
|
+
const state = State({
|
|
231
|
+
count: 0,
|
|
232
|
+
name: '',
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// Mutate directly
|
|
236
|
+
state.count++
|
|
237
|
+
state.name = 'John'
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Computed Values
|
|
241
|
+
```typescript
|
|
242
|
+
import { Computed } from 'deskforge/state'
|
|
243
|
+
|
|
244
|
+
const doubled = Computed(() => state.count * 2)
|
|
245
|
+
|
|
246
|
+
// Use it
|
|
247
|
+
Text(`Doubled: ${doubled.value}`) // Auto-updates when count changes
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Effects (Side Effects)
|
|
251
|
+
```typescript
|
|
252
|
+
import { Effect } from 'deskforge/state'
|
|
253
|
+
|
|
254
|
+
Effect(() => {
|
|
255
|
+
console.log('Count changed:', state.count)
|
|
256
|
+
|
|
257
|
+
// Optional cleanup
|
|
258
|
+
return () => console.log('Cleanup')
|
|
259
|
+
})
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Watch (Specific Values)
|
|
263
|
+
```typescript
|
|
264
|
+
import { Watch } from 'deskforge/state'
|
|
265
|
+
|
|
266
|
+
Watch(
|
|
267
|
+
() => state.count,
|
|
268
|
+
(newValue, oldValue) => {
|
|
269
|
+
console.log(`Count: ${oldValue} -> ${newValue}`)
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Styling
|
|
275
|
+
|
|
276
|
+
All styles use **React Native property names**:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
const styles = StyleSheet.create({
|
|
280
|
+
container: {
|
|
281
|
+
// Layout
|
|
282
|
+
flex: 1,
|
|
283
|
+
flexDirection: 'column',
|
|
284
|
+
justifyContent: 'center',
|
|
285
|
+
alignItems: 'center',
|
|
286
|
+
gap: 12,
|
|
287
|
+
|
|
288
|
+
// Spacing
|
|
289
|
+
padding: 16,
|
|
290
|
+
marginBottom: 8,
|
|
291
|
+
|
|
292
|
+
// Dimensions
|
|
293
|
+
width: 100,
|
|
294
|
+
height: 200,
|
|
295
|
+
|
|
296
|
+
// Appearance
|
|
297
|
+
backgroundColor: '#ffffff',
|
|
298
|
+
borderRadius: 8,
|
|
299
|
+
borderWidth: 1,
|
|
300
|
+
borderColor: '#e2e8f0',
|
|
301
|
+
|
|
302
|
+
// Typography
|
|
303
|
+
fontSize: 16,
|
|
304
|
+
fontWeight: 'bold',
|
|
305
|
+
color: '#000000',
|
|
306
|
+
|
|
307
|
+
// Shadow
|
|
308
|
+
shadowColor: '#000',
|
|
309
|
+
shadowOpacity: 0.1,
|
|
310
|
+
shadowRadius: 4,
|
|
311
|
+
elevation: 2,
|
|
312
|
+
},
|
|
313
|
+
})
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Cross-Platform
|
|
317
|
+
|
|
318
|
+
Use `Platform` for OS detection:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { Platform } from 'deskforge'
|
|
322
|
+
|
|
323
|
+
// Detect current OS
|
|
324
|
+
if (Platform.OS === 'ios') { }
|
|
325
|
+
if (Platform.OS === 'android') { }
|
|
326
|
+
if (Platform.OS === 'windows') { }
|
|
327
|
+
|
|
328
|
+
// Select value by platform
|
|
329
|
+
const behavior = Platform.select({
|
|
330
|
+
ios: 'padding',
|
|
331
|
+
android: 'height',
|
|
332
|
+
default: 'padding',
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
// Render platform-specific components
|
|
336
|
+
Platform.mobile(MobileComponent) // null on desktop
|
|
337
|
+
Platform.desktop(DesktopComponent) // null on mobile
|
|
338
|
+
Platform.any(AlwaysShow) // always renders
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Common Patterns
|
|
342
|
+
|
|
343
|
+
### Conditional Rendering
|
|
344
|
+
```typescript
|
|
345
|
+
View({}, [
|
|
346
|
+
state.loading ? ActivityIndicator() : null,
|
|
347
|
+
state.error ? Text(state.error, { color: 'red' }) : null,
|
|
348
|
+
Text('Content'),
|
|
349
|
+
].filter(Boolean))
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### List with Operations
|
|
353
|
+
```typescript
|
|
354
|
+
FlatList(
|
|
355
|
+
state.items,
|
|
356
|
+
(item) => Pressable(
|
|
357
|
+
{ padding: 12, borderBottomWidth: 1, borderBottomColor: '#eee' },
|
|
358
|
+
{ onPress: () => selectItem(item) },
|
|
359
|
+
[
|
|
360
|
+
Text(item.name, { fontWeight: 'bold' }),
|
|
361
|
+
Pressable({ padding: 4 }, {
|
|
362
|
+
onPress: () => {
|
|
363
|
+
const idx = state.items.indexOf(item)
|
|
364
|
+
state.items.splice(idx, 1)
|
|
365
|
+
},
|
|
366
|
+
}, [Text('×', { color: 'red' })])
|
|
367
|
+
]
|
|
368
|
+
),
|
|
369
|
+
{ flex: 1 }
|
|
370
|
+
)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Forms with Validation
|
|
374
|
+
```typescript
|
|
375
|
+
const state = State({
|
|
376
|
+
email: '',
|
|
377
|
+
password: '',
|
|
378
|
+
errors: {} as Record<string, string>,
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
const handleSubmit = () => {
|
|
382
|
+
state.errors = {}
|
|
383
|
+
|
|
384
|
+
if (!state.email) state.errors.email = 'Required'
|
|
385
|
+
if (!state.password) state.errors.password = 'Required'
|
|
386
|
+
|
|
387
|
+
if (Object.keys(state.errors).length === 0) {
|
|
388
|
+
submitForm(state.email, state.password)
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// In render
|
|
393
|
+
View({}, [
|
|
394
|
+
TextInput({ flex: 1 }, {
|
|
395
|
+
placeholder: 'Email',
|
|
396
|
+
value: state.email,
|
|
397
|
+
onChangeText: (v) => state.email = v,
|
|
398
|
+
}),
|
|
399
|
+
state.errors.email
|
|
400
|
+
? Text(state.errors.email, { color: 'red', fontSize: 12 })
|
|
401
|
+
: null,
|
|
402
|
+
])
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Database Integration
|
|
406
|
+
```typescript
|
|
407
|
+
const state = State({
|
|
408
|
+
items: [],
|
|
409
|
+
loading: false,
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
// Load on mount
|
|
413
|
+
Effect(() => {
|
|
414
|
+
state.loading = true
|
|
415
|
+
DB.query('items')
|
|
416
|
+
.all()
|
|
417
|
+
.then(items => state.items = items)
|
|
418
|
+
.finally(() => state.loading = false)
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
// Add item
|
|
422
|
+
const addItem = (name: string) => {
|
|
423
|
+
DB.insert('items', { name })
|
|
424
|
+
.then(item => state.items.unshift(item))
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Delete item
|
|
428
|
+
const deleteItem = (id: string) => {
|
|
429
|
+
DB.delete('items', id)
|
|
430
|
+
.then(() => {
|
|
431
|
+
state.items = state.items.filter(i => i.id !== id)
|
|
432
|
+
})
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Migration Checklist
|
|
437
|
+
|
|
438
|
+
If migrating from old JSX syntax:
|
|
439
|
+
|
|
440
|
+
- [ ] Rename files from `.tsx` to `.ts`
|
|
441
|
+
- [ ] Remove all `<>` JSX brackets
|
|
442
|
+
- [ ] Replace `useState()` with `State()`
|
|
443
|
+
- [ ] Replace `useEffect()` with `Effect()`
|
|
444
|
+
- [ ] Replace `setState()` with direct mutations
|
|
445
|
+
- [ ] Convert component returns to function calls
|
|
446
|
+
- [ ] Update styles to use StyleSheet.create()
|
|
447
|
+
- [ ] Replace all CSS/classNames with StyleObject
|
|
448
|
+
- [ ] Test all interactions and state changes
|
|
449
|
+
- [ ] Verify cross-platform compatibility
|
|
450
|
+
|
|
451
|
+
## Examples
|
|
452
|
+
|
|
453
|
+
See the following files for complete working examples:
|
|
454
|
+
|
|
455
|
+
1. **[NotesApp.ts](examples/deskforge-app/screens/NotesApp.ts)** - FlatList, Modal, TextInput, DB
|
|
456
|
+
2. **[CounterApp.ts](examples/deskforge-app/screens/CounterApp.ts)** - Simple State, Computed
|
|
457
|
+
3. **[SettingsApp.ts](examples/deskforge-app/screens/SettingsApp.ts)** - Switch, Slider, Platform
|
|
458
|
+
4. **[TodoApp.ts](examples/deskforge-app/screens/TodoApp.ts)** - FlatList, CheckBox, Array ops
|
|
459
|
+
5. **[GalleryApp.ts](examples/deskforge-app/screens/GalleryApp.ts)** - Image, Modal preview
|
|
460
|
+
|
|
461
|
+
## Troubleshooting
|
|
462
|
+
|
|
463
|
+
### "style is required"
|
|
464
|
+
All components need a style object. Use empty `{}` if no style needed.
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
// ❌ Wrong
|
|
468
|
+
Text('Hello')
|
|
469
|
+
|
|
470
|
+
// ✅ Correct
|
|
471
|
+
Text('Hello', { fontSize: 16 })
|
|
472
|
+
Text('Hello', {}) // Empty style okay
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### "children is required"
|
|
476
|
+
Container components need children array (even if empty).
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
// ❌ Wrong
|
|
480
|
+
View({ flex: 1 })
|
|
481
|
+
|
|
482
|
+
// ✅ Correct
|
|
483
|
+
View({ flex: 1 }, [])
|
|
484
|
+
View({ flex: 1 }, [Text('Content')])
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### State not updating
|
|
488
|
+
Make sure you're mutating state directly, not creating new objects.
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
// ❌ Wrong
|
|
492
|
+
state.items = [...state.items, newItem]
|
|
493
|
+
|
|
494
|
+
// ✅ Correct
|
|
495
|
+
state.items.push(newItem)
|
|
496
|
+
state.items.unshift(newItem)
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Styles not applying
|
|
500
|
+
Check that you're using React Native style property names, not CSS.
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
// ❌ Wrong
|
|
504
|
+
{ className: 'my-class', color: 'red', fontSize: '16px' }
|
|
505
|
+
|
|
506
|
+
// ✅ Correct
|
|
507
|
+
{ color: '#ff0000', fontSize: 16 }
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Next Steps
|
|
511
|
+
|
|
512
|
+
1. ✅ Read [IMPLEMENTATION_GUIDE.md](IMPLEMENTATION_GUIDE.md) for detailed patterns
|
|
513
|
+
2. ✅ Read [COMPONENT_API.md](COMPONENT_API.md) for all component signatures
|
|
514
|
+
3. ✅ Review the example apps in [examples/deskforge-app/screens/](examples/deskforge-app/screens/)
|
|
515
|
+
4. ✅ Start building your app!
|
|
516
|
+
|
|
517
|
+
## Support
|
|
518
|
+
|
|
519
|
+
Questions? See:
|
|
520
|
+
- Component API: [COMPONENT_API.md](COMPONENT_API.md)
|
|
521
|
+
- Implementation patterns: [IMPLEMENTATION_GUIDE.md](IMPLEMENTATION_GUIDE.md)
|
|
522
|
+
- Working examples: [examples/deskforge-app/screens/](examples/deskforge-app/screens/)
|
|
523
|
+
- Main README: [README.md](README.md)
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import * as fs from 'fs'
|
|
2
2
|
import { Renderer } from '@deskforge/renderer'
|
|
3
|
-
import {
|
|
3
|
+
import { createNavigation } from '@deskforge/router'
|
|
4
4
|
import { HomeRoute, DetailsRoute } from './src/screens'
|
|
5
5
|
import { Text, View, Window } from './src/ui/Responsive'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
.add('details.ts', DetailsRoute.component)
|
|
11
|
-
.build()
|
|
12
|
-
|
|
13
|
-
const { router } = createApp({ manifest: routes })
|
|
7
|
+
const navigation = createNavigation()
|
|
8
|
+
navigation.register('home', HomeRoute)
|
|
9
|
+
navigation.register('details', DetailsRoute)
|
|
14
10
|
|
|
15
11
|
function createRoot() {
|
|
16
12
|
return Window({ style: { background: '#f7f8fb', padding: 24 } })
|
|
17
13
|
.add(
|
|
18
14
|
View({ style: { background: '#ffffff', borderRadius: 32, padding: 24 } }),
|
|
19
15
|
Text('DeskForge App Example', { style: { fontSize: 24, fontWeight: '700' } }),
|
|
20
|
-
|
|
16
|
+
navigation.render() ?? Text('No screen selected.', { style: { color: '#6b7280', fontSize: 16 } }),
|
|
21
17
|
)
|
|
22
18
|
.build()
|
|
23
19
|
}
|
|
@@ -32,13 +28,13 @@ async function main() {
|
|
|
32
28
|
})
|
|
33
29
|
|
|
34
30
|
// Navigate to home and render
|
|
35
|
-
|
|
31
|
+
navigation.navigate('home')
|
|
36
32
|
renderer.renderNode(createRoot())
|
|
37
33
|
await renderer.saveAs('./dist/deskforge-app-home.png')
|
|
38
34
|
console.log('Rendered home screen to dist/deskforge-app-home.png')
|
|
39
35
|
|
|
40
36
|
// Navigate to details and render
|
|
41
|
-
|
|
37
|
+
navigation.navigate('details', { noteId: 42 })
|
|
42
38
|
renderer.renderNode(createRoot())
|
|
43
39
|
await renderer.saveAs('./dist/deskforge-app-details.png')
|
|
44
40
|
console.log('Rendered details screen to dist/deskforge-app-details.png')
|