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,385 @@
1
+ /**
2
+ * DeskForge UI Components - Implementation Guide
3
+ *
4
+ * This document explains the core principles and usage patterns
5
+ * for building apps with DeskForge's functional UI components.
6
+ */
7
+
8
+ # DeskForge UI Components - Implementation Guide
9
+
10
+ ## Core Philosophy
11
+
12
+ DeskForge UI is built on a single principle:
13
+ > **Everything is a pure function that returns a DFNode**
14
+
15
+ No JSX, no HTML, no XML. No className strings. No CSS files. No hooks.
16
+
17
+ ## The Pattern
18
+
19
+ Every UI component follows this exact pattern:
20
+
21
+ ```typescript
22
+ import { createNode } from '@deskforge/core'
23
+ import type { DFNode, StyleObject } from '@deskforge/core'
24
+
25
+ export function ComponentName(
26
+ prop1: Type,
27
+ prop2?: Type,
28
+ children: DFNode[] = []
29
+ ): DFNode {
30
+ return createNode(
31
+ 'ComponentType',
32
+ {
33
+ prop1,
34
+ prop2: prop2 ?? defaultValue,
35
+ } as Record<string, unknown>,
36
+ children
37
+ )
38
+ }
39
+ ```
40
+
41
+ ## Usage Examples
42
+
43
+ ### View - Primary Container
44
+
45
+ ```typescript
46
+ View({ flex: 1, backgroundColor: '#fff' }, [
47
+ Text('Hello World'),
48
+ Text('Second line'),
49
+ ])
50
+ ```
51
+
52
+ ### Text - Simple Text Rendering
53
+
54
+ ```typescript
55
+ Text('Simple text', { fontSize: 16, fontWeight: 'bold' })
56
+ Text(42, { color: '#0077ff' }) // Numbers auto-convert
57
+ ```
58
+
59
+ ### Pressable - Tappable Container
60
+
61
+ ```typescript
62
+ Pressable(
63
+ { padding: 16, borderRadius: 8 },
64
+ {
65
+ onPress: () => handlePress(),
66
+ onLongPress: () => handleLongPress(),
67
+ disabled: false,
68
+ },
69
+ [
70
+ Text('Tap me', { color: '#0077ff' }),
71
+ ]
72
+ )
73
+ ```
74
+
75
+ ### Button - Quick Button Shorthand
76
+
77
+ ```typescript
78
+ Button('Submit', { backgroundColor: '#2ecc71', padding: 12 }, {
79
+ onPress: () => submitForm(),
80
+ })
81
+ ```
82
+
83
+ ### TextInput - Text Input Field
84
+
85
+ ```typescript
86
+ TextInput({ flex: 1, padding: 12, borderWidth: 1, borderColor: '#ccc' }, {
87
+ placeholder: 'Enter text',
88
+ value: state.text,
89
+ onChangeText: (text) => state.text = text,
90
+ keyboardType: 'email-address',
91
+ secureTextEntry: false,
92
+ })
93
+ ```
94
+
95
+ ### FlatList - Efficient List Rendering
96
+
97
+ ```typescript
98
+ // Simple list
99
+ FlatList(
100
+ items,
101
+ (item) => Text(item.name),
102
+ { flex: 1 }
103
+ )
104
+
105
+ // List with configuration
106
+ FlatList(
107
+ items,
108
+ (item, index) => Pressable(
109
+ { padding: 12, borderBottomWidth: 1, borderBottomColor: '#eee' },
110
+ { onPress: () => selectItem(item) },
111
+ [
112
+ Text(item.title, { fontSize: 16, fontWeight: 'bold' }),
113
+ Text(item.subtitle, { color: '#999' }),
114
+ ]
115
+ ),
116
+ { flex: 1 },
117
+ {
118
+ ItemSeparatorComponent: () => View({ height: 1, backgroundColor: '#f0f0f0' }, []),
119
+ onEndReached: () => loadMore(),
120
+ onEndReachedThreshold: 0.5,
121
+ }
122
+ )
123
+ ```
124
+
125
+ ### Modal - Full-Screen Overlay
126
+
127
+ ```typescript
128
+ Modal(
129
+ isOpen,
130
+ () => setIsOpen(false),
131
+ { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' },
132
+ [
133
+ View({
134
+ backgroundColor: '#fff',
135
+ borderRadius: 12,
136
+ padding: 20,
137
+ width: '85%',
138
+ }, [
139
+ Text('Modal Title', { fontSize: 20, fontWeight: 'bold' }),
140
+ Text('Modal content here', { marginTop: 12, color: '#666' }),
141
+ ]),
142
+ ],
143
+ { animationType: 'fade' }
144
+ )
145
+ ```
146
+
147
+ ### Switch - Toggle Control
148
+
149
+ ```typescript
150
+ Switch(
151
+ isDarkMode,
152
+ (value) => setDarkMode(value),
153
+ {
154
+ onTintColor: '#0077ff',
155
+ thumbTintColor: '#fff',
156
+ }
157
+ )
158
+ ```
159
+
160
+ ### Slider - Range Input
161
+
162
+ ```typescript
163
+ Slider({ height: 40, padding: 20 }, {
164
+ value: volume,
165
+ minimumValue: 0,
166
+ maximumValue: 100,
167
+ step: 5,
168
+ onValueChange: (v) => setVolume(v),
169
+ minimumTrackTintColor: '#0077ff',
170
+ })
171
+ ```
172
+
173
+ ### Image - Image Rendering
174
+
175
+ ```typescript
176
+ // From file path
177
+ Image('/assets/logo.png', { width: 100, height: 100 })
178
+
179
+ // From URI
180
+ Image({ uri: 'https://example.com/image.png' }, {
181
+ width: 200,
182
+ height: 200,
183
+ borderRadius: 12,
184
+ })
185
+ ```
186
+
187
+ ### Platform - Cross-Platform Support
188
+
189
+ ```typescript
190
+ // Detect OS
191
+ if (Platform.OS === 'ios') {
192
+ // iOS-specific code
193
+ }
194
+
195
+ // Select value by platform
196
+ const behavior = Platform.select({
197
+ ios: 'padding',
198
+ android: 'height',
199
+ default: 'padding',
200
+ })
201
+
202
+ // Render platform-specific components
203
+ Platform.desktop(DesktopComponent) // Returns node on desktop, null on mobile
204
+ Platform.mobile(MobileComponent) // Returns node on mobile, null on desktop
205
+ Platform.any(AlwaysRender) // Always returns node
206
+ ```
207
+
208
+ ## State Management
209
+
210
+ DeskForge uses reactive state with direct mutations:
211
+
212
+ ```typescript
213
+ import { State, Computed, Watch, Effect } from 'deskforge/state'
214
+
215
+ // Create reactive state
216
+ const state = State({
217
+ count: 0,
218
+ name: '',
219
+ })
220
+
221
+ // Mutate directly - NO setState needed
222
+ state.count++
223
+ state.name = 'John'
224
+
225
+ // Computed values
226
+ const doubled = Computed(() => state.count * 2)
227
+ console.log(doubled.value) // Automatically updates
228
+
229
+ // Effects (like useEffect)
230
+ Effect(() => {
231
+ console.log('Count changed:', state.count)
232
+ // Optional cleanup function
233
+ return () => console.log('Cleanup')
234
+ })
235
+
236
+ // Watch specific values
237
+ Watch(
238
+ () => state.count,
239
+ (newValue, oldValue) => {
240
+ console.log(`Count: ${oldValue} -> ${newValue}`)
241
+ }
242
+ )
243
+ ```
244
+
245
+ ## StyleSheet - Style Objects
246
+
247
+ All styles use React Native property names via StyleObject:
248
+
249
+ ```typescript
250
+ const styles = StyleSheet.create({
251
+ container: {
252
+ flex: 1,
253
+ backgroundColor: '#fff',
254
+ padding: 16,
255
+ justifyContent: 'center',
256
+ alignItems: 'center',
257
+ },
258
+ title: {
259
+ fontSize: 20,
260
+ fontWeight: 'bold',
261
+ color: '#111',
262
+ marginBottom: 8,
263
+ },
264
+ button: {
265
+ backgroundColor: '#0077ff',
266
+ borderRadius: 8,
267
+ paddingHorizontal: 16,
268
+ paddingVertical: 12,
269
+ elevation: 2,
270
+ shadowColor: '#000',
271
+ shadowOpacity: 0.1,
272
+ shadowRadius: 4,
273
+ },
274
+ })
275
+
276
+ // Use styles
277
+ View(styles.container, [...])
278
+ ```
279
+
280
+ ## Style Properties
281
+
282
+ ### Layout
283
+ `flex`, `flexDirection`, `justifyContent`, `alignItems`, `alignSelf`, `flexWrap`, `gap`, `rowGap`, `columnGap`
284
+
285
+ ### Spacing
286
+ `margin`, `marginTop`, `marginBottom`, `marginLeft`, `marginRight`, `marginHorizontal`, `marginVertical`
287
+ `padding`, `paddingTop`, `paddingBottom`, `paddingLeft`, `paddingRight`, `paddingHorizontal`, `paddingVertical`
288
+
289
+ ### Dimensions
290
+ `width`, `height`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`
291
+
292
+ ### Appearance
293
+ `backgroundColor`, `borderRadius`, `borderWidth`, `borderColor`, `opacity`, `overflow`, `zIndex`
294
+ `shadowColor`, `shadowOpacity`, `shadowRadius`, `shadowOffset`, `elevation`
295
+
296
+ ### Typography
297
+ `fontSize`, `fontWeight`, `fontFamily`, `color`, `textAlign`, `lineHeight`, `letterSpacing`, `textDecorationLine`
298
+
299
+ ### Position
300
+ `position`, `top`, `bottom`, `left`, `right`
301
+
302
+ ## Key Patterns
303
+
304
+ ### Conditional Rendering
305
+
306
+ ```typescript
307
+ View({ flex: 1 }, [
308
+ isLoading ? ActivityIndicator() : renderContent(),
309
+ state.error ? View({}, [Text(state.error, { color: 'red' })]) : null,
310
+ ].filter(Boolean))
311
+ ```
312
+
313
+ ### List Operations
314
+
315
+ ```typescript
316
+ // Array filtering
317
+ state.items = state.items.filter(item => item.id !== toDelete)
318
+
319
+ // Array mutations
320
+ state.items.unshift(newItem)
321
+ state.items.push(newItem)
322
+ state.items.splice(index, 1)
323
+
324
+ // Array mapping with FlatList
325
+ FlatList(
326
+ state.items,
327
+ (item) => renderItem(item),
328
+ { flex: 1 }
329
+ )
330
+ ```
331
+
332
+ ### Nested Components
333
+
334
+ ```typescript
335
+ const Header = (title: string) => View(
336
+ { padding: 16, backgroundColor: '#fff' },
337
+ [Text(title, { fontSize: 20, fontWeight: 'bold' })]
338
+ )
339
+
340
+ const Container = (children: DFNode[]) => View(
341
+ { flex: 1, backgroundColor: '#f8f9fc' },
342
+ children
343
+ )
344
+
345
+ // Usage
346
+ Container([
347
+ Header('My App'),
348
+ Content(),
349
+ ])
350
+ ```
351
+
352
+ ### Error Handling
353
+
354
+ ```typescript
355
+ const state = State({ error: null as string | null })
356
+
357
+ Effect(() => {
358
+ DB.query('items')
359
+ .all()
360
+ .then(items => state.items = items)
361
+ .catch(err => state.error = err.message)
362
+ })
363
+
364
+ // In render
365
+ state.error
366
+ ? View({ padding: 20 }, [Text(state.error, { color: '#e74c3c' })])
367
+ : renderContent()
368
+ ```
369
+
370
+ ## Best Practices
371
+
372
+ 1. **Use StyleSheet.create()** - Provides type safety and freezes styles
373
+ 2. **Name your styles** - Use descriptive names like `buttonPrimary`, not `button1`
374
+ 3. **Leverage State directly** - Mutate state, don't create new state objects
375
+ 4. **Use Computed for derived values** - Don't manually track computed state
376
+ 5. **Keep components small** - Extract common patterns into helper functions
377
+ 6. **Type your props** - Use TypeScript interfaces for component arguments
378
+ 7. **Document with JSDoc** - Add comments above functions
379
+ 8. **Use FlatList for lists** - Not manual maps; FlatList virtualizes for performance
380
+ 9. **Use Platform for OS detection** - Don't manually detect with userAgent
381
+ 10. **Combine Pressable + styles** - Create semantic button styles, don't hard-code
382
+
383
+ ## Complete Example
384
+
385
+ See `NotesApp.ts`, `TodoApp.ts`, `SettingsApp.ts`, `CounterApp.ts`, and `GalleryApp.ts` for full working examples of all patterns combined.