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.
Files changed (84) hide show
  1. package/COMPLETION_REPORT.md +426 -0
  2. package/COMPONENT_API.md +529 -0
  3. package/DELIVERY_SUMMARY.md +455 -0
  4. package/IMPLEMENTATION_GUIDE.md +385 -0
  5. package/IMPORT_GUIDE.md +404 -0
  6. package/QUICK_REFERENCE.md +352 -0
  7. package/README.md +245 -31
  8. package/README_UI_COMPLETE.md +395 -0
  9. package/TYPE_DEFINITIONS.md +671 -0
  10. package/UI_GETTING_STARTED.md +523 -0
  11. package/examples/deskforge-app/App.ts +7 -11
  12. package/examples/deskforge-app/screens/CounterApp.ts +181 -0
  13. package/examples/deskforge-app/screens/GalleryApp.ts +267 -0
  14. package/examples/deskforge-app/screens/NotesApp.ts +376 -0
  15. package/examples/deskforge-app/screens/SettingsApp.ts +226 -0
  16. package/examples/deskforge-app/screens/TodoApp.ts +288 -0
  17. package/examples/deskforge-app/screens/index.ts +50 -0
  18. package/package.json +1 -1
  19. package/packages/cli/dist/commands/start.d.ts +7 -1
  20. package/packages/cli/dist/commands/start.d.ts.map +1 -1
  21. package/packages/cli/dist/commands/start.js +75 -21
  22. package/packages/cli/dist/commands/start.js.map +1 -1
  23. package/packages/cli/src/commands/start.ts +93 -21
  24. package/packages/cli/test/start.test.js +24 -0
  25. package/packages/core/dist/index.d.ts +1 -0
  26. package/packages/core/dist/index.d.ts.map +1 -1
  27. package/packages/core/dist/index.js +1 -0
  28. package/packages/core/dist/index.js.map +1 -1
  29. package/packages/core/dist/style/StyleObject.d.ts +115 -0
  30. package/packages/core/dist/style/StyleObject.d.ts.map +1 -0
  31. package/packages/core/dist/style/StyleObject.js +6 -0
  32. package/packages/core/dist/style/StyleObject.js.map +1 -0
  33. package/packages/core/dist/style/StyleSheet.d.ts +7 -0
  34. package/packages/core/dist/style/StyleSheet.d.ts.map +1 -0
  35. package/packages/core/dist/style/StyleSheet.js +13 -0
  36. package/packages/core/dist/style/StyleSheet.js.map +1 -0
  37. package/packages/core/dist/style/index.d.ts +3 -0
  38. package/packages/core/dist/style/index.d.ts.map +1 -0
  39. package/packages/core/dist/style/index.js +21 -0
  40. package/packages/core/dist/style/index.js.map +1 -0
  41. package/packages/core/src/index.ts +2 -1
  42. package/packages/core/src/style/StyleObject.ts +134 -0
  43. package/packages/core/src/style/StyleSheet.ts +19 -0
  44. package/packages/core/src/style/index.ts +5 -0
  45. package/packages/db/src/db.ts +4 -4
  46. package/packages/deskforge/src/index.ts +95 -0
  47. package/packages/file/dist/file.d.ts +1 -1
  48. package/packages/file/dist/file.d.ts.map +1 -1
  49. package/packages/file/dist/file.js +75 -3
  50. package/packages/file/dist/file.js.map +1 -1
  51. package/packages/file/src/file.ts +96 -4
  52. package/packages/file/test/file.test.js +23 -0
  53. package/packages/router/dist/index.d.ts +1 -0
  54. package/packages/router/dist/index.d.ts.map +1 -1
  55. package/packages/router/dist/index.js +1 -0
  56. package/packages/router/dist/index.js.map +1 -1
  57. package/packages/router/dist/navigation.d.ts +23 -0
  58. package/packages/router/dist/navigation.d.ts.map +1 -0
  59. package/packages/router/dist/navigation.js +61 -0
  60. package/packages/router/dist/navigation.js.map +1 -0
  61. package/packages/router/src/index.ts +2 -1
  62. package/packages/router/src/navigation.ts +86 -0
  63. package/packages/router/test/router.test.js +21 -1
  64. package/packages/theme/src/theme.ts +23 -0
  65. package/packages/ui/src/base/Button.ts +67 -0
  66. package/packages/ui/src/base/Image.ts +59 -0
  67. package/packages/ui/src/base/Pressable.ts +69 -0
  68. package/packages/ui/src/base/Text.ts +42 -0
  69. package/packages/ui/src/base/TextInput.ts +113 -0
  70. package/packages/ui/src/base/TouchableOpacity.ts +52 -0
  71. package/packages/ui/src/base/View.ts +43 -0
  72. package/packages/ui/src/index.ts +40 -25
  73. package/packages/ui/src/input/CheckBox.ts +69 -0
  74. package/packages/ui/src/input/Slider.ts +19 -2
  75. package/packages/ui/src/input/Switch.ts +68 -0
  76. package/packages/ui/src/layout/KeyboardAvoidingView.ts +65 -0
  77. package/packages/ui/src/layout/SafeAreaView.ts +58 -0
  78. package/packages/ui/src/list/FlatList.ts +111 -0
  79. package/packages/ui/src/list/ScrollView.ts +80 -0
  80. package/packages/ui/src/list/SectionList.ts +120 -0
  81. package/packages/ui/src/overlay/ActivityIndicator.ts +70 -0
  82. package/packages/ui/src/overlay/Modal.ts +28 -6
  83. package/packages/ui/src/platform/Platform.ts +119 -0
  84. 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 { createApp, ManifestBuilder } from '@deskforge/router'
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
- // Define routes using the manifest builder (Expo Router style).
8
- const routes = new ManifestBuilder()
9
- .add('index.ts', HomeRoute.component)
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
- router.render() ?? Text('No screen selected.', { style: { color: '#6b7280', fontSize: 16 } }),
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
- router.navigate('/')
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
- router.navigate('/details')
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')