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,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeskForge Components - Quick Reference Card
|
|
3
|
+
*
|
|
4
|
+
* One-page cheat sheet for all components and patterns
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
# DeskForge UI - Quick Reference
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
```typescript
|
|
11
|
+
import {
|
|
12
|
+
View, Text, Pressable, Button, TouchableOpacity, Image, TextInput,
|
|
13
|
+
ScrollView, FlatList, SectionList,
|
|
14
|
+
SafeAreaView, KeyboardAvoidingView,
|
|
15
|
+
Modal, ActivityIndicator,
|
|
16
|
+
Switch, Slider, CheckBox,
|
|
17
|
+
StatusBar, Platform,
|
|
18
|
+
StyleSheet,
|
|
19
|
+
} from 'deskforge'
|
|
20
|
+
|
|
21
|
+
import { State, Computed, Watch, Effect } from 'deskforge/state'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Components at a Glance
|
|
27
|
+
|
|
28
|
+
### Containers
|
|
29
|
+
```typescript
|
|
30
|
+
// Flex container
|
|
31
|
+
View({ flex: 1 }, [children])
|
|
32
|
+
|
|
33
|
+
// Scroll content
|
|
34
|
+
ScrollView({ flex: 1 }, [children])
|
|
35
|
+
|
|
36
|
+
// Safe areas
|
|
37
|
+
SafeAreaView({ flex: 1 }, [children])
|
|
38
|
+
KeyboardAvoidingView({ flex: 1 }, [children])
|
|
39
|
+
|
|
40
|
+
// Full-screen overlay
|
|
41
|
+
Modal(visible, onClose, style, [children])
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Text & Input
|
|
45
|
+
```typescript
|
|
46
|
+
// Static text
|
|
47
|
+
Text('Hello', { fontSize: 16 })
|
|
48
|
+
|
|
49
|
+
// Text input
|
|
50
|
+
TextInput({ flex: 1 }, { placeholder, value, onChangeText })
|
|
51
|
+
|
|
52
|
+
// Password
|
|
53
|
+
TextInput({ flex: 1 }, { secureTextEntry: true })
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Buttons & Touch
|
|
57
|
+
```typescript
|
|
58
|
+
// Tappable
|
|
59
|
+
Pressable(style, { onPress, onLongPress, disabled }, [children])
|
|
60
|
+
|
|
61
|
+
// Quick button
|
|
62
|
+
Button('Click', style, { onPress })
|
|
63
|
+
|
|
64
|
+
// With opacity animation
|
|
65
|
+
TouchableOpacity(style, { onPress }, [children])
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Lists
|
|
69
|
+
```typescript
|
|
70
|
+
// Simple list
|
|
71
|
+
FlatList(data, (item) => renderItem(item), style)
|
|
72
|
+
|
|
73
|
+
// With config
|
|
74
|
+
FlatList(data, renderItem, style, {
|
|
75
|
+
onEndReached: () => loadMore(),
|
|
76
|
+
ItemSeparatorComponent: () => Separator(),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Grouped
|
|
80
|
+
SectionList(sections, renderItem, renderSectionHeader, style)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Media
|
|
84
|
+
```typescript
|
|
85
|
+
// Images
|
|
86
|
+
Image('/path/file.jpg', { width: 100, height: 100 })
|
|
87
|
+
Image({ uri: 'https://...' }, { width: 100 })
|
|
88
|
+
|
|
89
|
+
// Loading
|
|
90
|
+
ActivityIndicator({ margin: 20 }, { size: 'large' })
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Inputs
|
|
94
|
+
```typescript
|
|
95
|
+
// Toggle
|
|
96
|
+
Switch(value, onChange, { onTintColor: '#0077ff' })
|
|
97
|
+
|
|
98
|
+
// Slider
|
|
99
|
+
Slider({ width: 200 }, {
|
|
100
|
+
value: 50,
|
|
101
|
+
minimumValue: 0,
|
|
102
|
+
maximumValue: 100,
|
|
103
|
+
onValueChange: (v) => setState(v),
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// Checkbox
|
|
107
|
+
CheckBox(checked, onChange)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Platform
|
|
111
|
+
```typescript
|
|
112
|
+
// Detect OS
|
|
113
|
+
Platform.OS // 'ios' | 'android' | 'windows' | 'macos' | 'linux'
|
|
114
|
+
|
|
115
|
+
// Select by platform
|
|
116
|
+
Platform.select({ ios: 'x', android: 'y', default: 'z' })
|
|
117
|
+
|
|
118
|
+
// Conditional render
|
|
119
|
+
Platform.mobile(node) // null on desktop
|
|
120
|
+
Platform.desktop(node) // null on mobile
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Styles
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const styles = StyleSheet.create({
|
|
129
|
+
// Layout
|
|
130
|
+
flex: 1,
|
|
131
|
+
flexDirection: 'row' | 'column',
|
|
132
|
+
justifyContent: 'center' | 'flex-start' | 'flex-end' | 'space-between',
|
|
133
|
+
alignItems: 'center',
|
|
134
|
+
gap: 12,
|
|
135
|
+
|
|
136
|
+
// Spacing
|
|
137
|
+
padding: 16,
|
|
138
|
+
margin: 8,
|
|
139
|
+
paddingHorizontal: 12,
|
|
140
|
+
marginVertical: 4,
|
|
141
|
+
|
|
142
|
+
// Size
|
|
143
|
+
width: 100,
|
|
144
|
+
height: 200,
|
|
145
|
+
|
|
146
|
+
// Visual
|
|
147
|
+
backgroundColor: '#fff',
|
|
148
|
+
borderRadius: 8,
|
|
149
|
+
borderWidth: 1,
|
|
150
|
+
borderColor: '#ddd',
|
|
151
|
+
|
|
152
|
+
// Text
|
|
153
|
+
fontSize: 16,
|
|
154
|
+
fontWeight: 'bold' | '600',
|
|
155
|
+
color: '#000',
|
|
156
|
+
textAlign: 'center',
|
|
157
|
+
|
|
158
|
+
// Shadow
|
|
159
|
+
shadowColor: '#000',
|
|
160
|
+
shadowOpacity: 0.1,
|
|
161
|
+
shadowRadius: 4,
|
|
162
|
+
elevation: 2,
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## State Management
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// Reactive state - mutate directly
|
|
172
|
+
const state = State({ count: 0, items: [] })
|
|
173
|
+
state.count++
|
|
174
|
+
state.items.push(item)
|
|
175
|
+
|
|
176
|
+
// Computed value - auto-updates
|
|
177
|
+
const doubled = Computed(() => state.count * 2)
|
|
178
|
+
Text(`${doubled.value}`)
|
|
179
|
+
|
|
180
|
+
// Side effects
|
|
181
|
+
Effect(() => {
|
|
182
|
+
console.log('count changed')
|
|
183
|
+
return () => console.log('cleanup')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
// Watch specific value
|
|
187
|
+
Watch(() => state.count, (newVal, oldVal) => {
|
|
188
|
+
console.log(`${oldVal} -> ${newVal}`)
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Common Patterns
|
|
195
|
+
|
|
196
|
+
### Conditional Rendering
|
|
197
|
+
```typescript
|
|
198
|
+
View({}, [
|
|
199
|
+
state.loading ? ActivityIndicator() : Content(),
|
|
200
|
+
state.error ? Error(state.error) : null,
|
|
201
|
+
].filter(Boolean))
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### List with Delete
|
|
205
|
+
```typescript
|
|
206
|
+
FlatList(state.items, (item) =>
|
|
207
|
+
Pressable({ padding: 12 }, {}, [
|
|
208
|
+
Text(item.name),
|
|
209
|
+
Pressable({ padding: 4 }, {
|
|
210
|
+
onPress: () => {
|
|
211
|
+
const idx = state.items.indexOf(item)
|
|
212
|
+
state.items.splice(idx, 1)
|
|
213
|
+
},
|
|
214
|
+
}, [Text('×')]),
|
|
215
|
+
])
|
|
216
|
+
)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Form Validation
|
|
220
|
+
```typescript
|
|
221
|
+
const state = State({ email: '', errors: {} })
|
|
222
|
+
|
|
223
|
+
const validate = () => {
|
|
224
|
+
state.errors = {}
|
|
225
|
+
if (!state.email) state.errors.email = 'Required'
|
|
226
|
+
return Object.keys(state.errors).length === 0
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
Pressable({ padding: 12 }, {
|
|
230
|
+
onPress: () => validate() && submit(),
|
|
231
|
+
}, [Text('Submit')])
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Data Loading
|
|
235
|
+
```typescript
|
|
236
|
+
Effect(() => {
|
|
237
|
+
state.loading = true
|
|
238
|
+
fetch('/api/items')
|
|
239
|
+
.then(r => r.json())
|
|
240
|
+
.then(data => state.items = data)
|
|
241
|
+
.catch(e => state.error = e.message)
|
|
242
|
+
.finally(() => state.loading = false)
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Common Properties
|
|
249
|
+
|
|
250
|
+
### Pressable Handlers
|
|
251
|
+
```typescript
|
|
252
|
+
{
|
|
253
|
+
onPress: () => {}, // Tap/click
|
|
254
|
+
onLongPress: () => {}, // 500ms hold
|
|
255
|
+
onPressIn: () => {}, // Press starts
|
|
256
|
+
onPressOut: () => {}, // Press ends
|
|
257
|
+
disabled: false, // Block handlers
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### TextInput Props
|
|
262
|
+
```typescript
|
|
263
|
+
{
|
|
264
|
+
value: '',
|
|
265
|
+
placeholder: '',
|
|
266
|
+
onChangeText: (text) => {},
|
|
267
|
+
keyboardType: 'default' | 'numeric' | 'email-address' | 'phone-pad',
|
|
268
|
+
multiline: false,
|
|
269
|
+
maxLength: 100,
|
|
270
|
+
secureTextEntry: false,
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### FlatList Props
|
|
275
|
+
```typescript
|
|
276
|
+
{
|
|
277
|
+
ItemSeparatorComponent: () => Separator(),
|
|
278
|
+
ListHeaderComponent: Header(),
|
|
279
|
+
ListFooterComponent: Footer(),
|
|
280
|
+
ListEmptyComponent: EmptyState(),
|
|
281
|
+
onEndReached: () => loadMore(),
|
|
282
|
+
onEndReachedThreshold: 0.5,
|
|
283
|
+
horizontal: false,
|
|
284
|
+
numColumns: 1,
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Quick Rules
|
|
291
|
+
|
|
292
|
+
1. ✅ All components return DFNode
|
|
293
|
+
2. ✅ All styles use StyleSheet.create()
|
|
294
|
+
3. ✅ State mutations are direct (no setState)
|
|
295
|
+
4. ✅ Children always in array
|
|
296
|
+
5. ✅ Style is always first arg
|
|
297
|
+
6. ✅ Handlers go in object
|
|
298
|
+
7. ✅ Platform.OS detects environment
|
|
299
|
+
8. ✅ Use Computed for derived values
|
|
300
|
+
9. ✅ Use Effect for side effects
|
|
301
|
+
10. ✅ Filter booleans with .filter(Boolean)
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Anti-Patterns
|
|
306
|
+
|
|
307
|
+
❌ Don't use JSX
|
|
308
|
+
❌ Don't use useState/useEffect
|
|
309
|
+
❌ Don't mutate state with setState
|
|
310
|
+
❌ Don't use CSS/className
|
|
311
|
+
❌ Don't return plain JSX elements
|
|
312
|
+
❌ Don't forget style object
|
|
313
|
+
❌ Don't forget children array
|
|
314
|
+
❌ Don't use any type
|
|
315
|
+
❌ Don't create new state objects
|
|
316
|
+
❌ Don't use manual renders over FlatList
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Getting Help
|
|
321
|
+
|
|
322
|
+
- **Full Guide:** See `IMPLEMENTATION_GUIDE.md`
|
|
323
|
+
- **API Reference:** See `COMPONENT_API.md`
|
|
324
|
+
- **Examples:** See `examples/deskforge-app/screens/`
|
|
325
|
+
- **Getting Started:** See `UI_GETTING_STARTED.md`
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Template
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { View, Text, Pressable, StyleSheet } from 'deskforge'
|
|
333
|
+
import { State } from 'deskforge/state'
|
|
334
|
+
|
|
335
|
+
const styles = StyleSheet.create({
|
|
336
|
+
container: { flex: 1, padding: 16 },
|
|
337
|
+
button: { backgroundColor: '#0077ff', padding: 12, borderRadius: 8 },
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
export const MyComponent = () => {
|
|
341
|
+
const state = State({ count: 0 })
|
|
342
|
+
|
|
343
|
+
return View(styles.container, [
|
|
344
|
+
Text(`Count: ${state.count}`, { fontSize: 20 }),
|
|
345
|
+
Pressable(styles.button, {
|
|
346
|
+
onPress: () => state.count++,
|
|
347
|
+
}, [
|
|
348
|
+
Text('Increment'),
|
|
349
|
+
]),
|
|
350
|
+
])
|
|
351
|
+
}
|
|
352
|
+
```
|
package/README.md
CHANGED
|
@@ -27,7 +27,8 @@ This model is intentionally simple and close to the rendering pipeline used by m
|
|
|
27
27
|
### Core principles
|
|
28
28
|
|
|
29
29
|
- Declarative UI composition using node trees
|
|
30
|
-
- Screen-based navigation with route
|
|
30
|
+
- Screen-based navigation with automatic route discovery
|
|
31
|
+
- App.ts as the landing entry for the app shell and screen tree
|
|
31
32
|
- Renderer-driven output for images and visual artifacts
|
|
32
33
|
- Modular packages that can be used independently
|
|
33
34
|
|
|
@@ -81,9 +82,233 @@ You can also add the UI package:
|
|
|
81
82
|
npm install @deskforge/ui
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
To scaffold a new app from the published CLI:
|
|
85
86
|
|
|
86
|
-
|
|
87
|
+
```bash
|
|
88
|
+
npx create-deskforge-app my-app
|
|
89
|
+
cd my-app
|
|
90
|
+
npm install
|
|
91
|
+
npm run start
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 4. Current authoring syntax
|
|
95
|
+
|
|
96
|
+
The current DeskForge examples use a functional, no-JSX authoring style. Components are written as pure functions that return a DFNode tree created with helpers such as createNode and the built-in UI primitives.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import {
|
|
100
|
+
View,
|
|
101
|
+
Text,
|
|
102
|
+
StyleSheet,
|
|
103
|
+
Button,
|
|
104
|
+
} from '@deskforge/ui/src'
|
|
105
|
+
import { State } from '@deskforge/state/src'
|
|
106
|
+
|
|
107
|
+
const styles = StyleSheet.create({
|
|
108
|
+
container: { flex: 1, padding: 24, justifyContent: 'center' },
|
|
109
|
+
title: { fontSize: 24, fontWeight: '600', marginBottom: 12 },
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
export function CounterScreen() {
|
|
113
|
+
const state = State({ count: 0 })
|
|
114
|
+
|
|
115
|
+
return View(styles.container, [
|
|
116
|
+
Text(`Count: ${state.count}`, styles.title),
|
|
117
|
+
Button('Increment', { padding: 12 }, {
|
|
118
|
+
onPress: () => {
|
|
119
|
+
state.count += 1
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
])
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Key patterns in the current codebase:
|
|
127
|
+
|
|
128
|
+
- No JSX or HTML-style tags are used.
|
|
129
|
+
- UI is composed with functional helpers such as View, Text, Pressable, ScrollView, TextInput and Modal.
|
|
130
|
+
- State is created with State(...) and updated directly.
|
|
131
|
+
- Styling is declared with StyleSheet.create(...) using React Native-style objects.
|
|
132
|
+
- Theme usage is imported from @deskforge/theme/src and applied with Theme.apply(...).
|
|
133
|
+
|
|
134
|
+
## 5. Packages and what they are for
|
|
135
|
+
|
|
136
|
+
DeskForge is organized as a set of focused packages. Each package can be used independently, and they work together through the core node-tree model.
|
|
137
|
+
|
|
138
|
+
### Core packages
|
|
139
|
+
|
|
140
|
+
- @deskforge/core
|
|
141
|
+
- Core node model, createNode, diff engine, scheduler, and component primitives.
|
|
142
|
+
- Use this when you want to build a UI tree or define custom components.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { createNode } from '@deskforge/core'
|
|
146
|
+
|
|
147
|
+
const node = createNode('view', { style: { padding: 16 } }, [])
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- @deskforge/renderer
|
|
151
|
+
- Renders node trees to a canvas-style surface and exports to image/buffer output.
|
|
152
|
+
- Use this to display or export your UI.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { Renderer } from '@deskforge/renderer'
|
|
156
|
+
|
|
157
|
+
const renderer = new Renderer({ width: 800, height: 600, backgroundColor: '#fff' })
|
|
158
|
+
renderer.renderNode(node)
|
|
159
|
+
await renderer.saveAs('./dist/output.png')
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- @deskforge/router
|
|
163
|
+
- Screen routing, navigation helpers, and automatic file-based route discovery.
|
|
164
|
+
- Use this when your app needs multiple screens and navigation.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { Router } from '@deskforge/router'
|
|
168
|
+
|
|
169
|
+
// routes are discovered from the file structure automatically
|
|
170
|
+
Router.start()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
- @deskforge/ui
|
|
174
|
+
- A modern set of functional UI primitives for layout, text, input, lists, overlays, feedback, and platform-aware controls.
|
|
175
|
+
- The current examples use the monorepo entry point with /src imports, including View, Text, Pressable, Button, TouchableOpacity, Image, TextInput, ScrollView, FlatList, SectionList, SafeAreaView, KeyboardAvoidingView, Modal, ActivityIndicator, Switch, Slider, CheckBox, StatusBar, and Platform.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import {
|
|
179
|
+
View,
|
|
180
|
+
Text,
|
|
181
|
+
ScrollView,
|
|
182
|
+
Modal,
|
|
183
|
+
StyleSheet,
|
|
184
|
+
} from '@deskforge/ui/src'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### State and styling packages
|
|
188
|
+
|
|
189
|
+
- @deskforge/state
|
|
190
|
+
- Reactive state helpers for local app state and component state.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { State } from '@deskforge/state'
|
|
194
|
+
|
|
195
|
+
const state = State({ count: 0 })
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
- @deskforge/theme
|
|
199
|
+
- Theme tokens, color palettes, spacing, animation helpers, and a simple Theme API for switching modes and applying theme preferences.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { Theme } from '@deskforge/theme/src'
|
|
203
|
+
|
|
204
|
+
Theme.apply({ isDark: true })
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Device and platform integrations
|
|
208
|
+
|
|
209
|
+
- @deskforge/device
|
|
210
|
+
- Device APIs such as camera, contacts, sensors, and media helpers.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { Camera, Contacts } from '@deskforge/device'
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- @deskforge/file
|
|
217
|
+
- File system helpers for reading and writing files.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { readFile, writeFile } from '@deskforge/file'
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
- @deskforge/network
|
|
224
|
+
- Peer-to-peer networking helpers, mDNS discovery, and TCP transfer utilities.
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { discoverPeers } from '@deskforge/network'
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- @deskforge/notifications
|
|
231
|
+
- Toasts, push notifications, SMS, email, and notification helpers.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { Notify } from '@deskforge/notifications'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
- @deskforge/security
|
|
238
|
+
- Biometric helpers and encryption utilities.
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { encrypt } from '@deskforge/security'
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### AI, data, and app platform packages
|
|
245
|
+
|
|
246
|
+
- @deskforge/ai
|
|
247
|
+
- Local AI helpers and brain-style node creation for on-device reasoning.
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
import { createBrain } from '@deskforge/ai'
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
- @deskforge/db
|
|
254
|
+
- Database adapters for SQLite, Postgres, MySQL, and MongoDB.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { connect } from '@deskforge/db'
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- @deskforge/background
|
|
261
|
+
- Background tasks and scheduling helpers.
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
import { BackgroundTask } from '@deskforge/background'
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
- @deskforge/updater
|
|
268
|
+
- Self-hosted automatic update helpers.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
import { Updater } from '@deskforge/updater'
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
- @deskforge/payments
|
|
275
|
+
- Unified payment wrapper with failover support for common providers.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { Pay } from '@deskforge/payments'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
- @deskforge/i18n
|
|
282
|
+
- Localization helpers with African language support.
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
import { t } from '@deskforge/i18n'
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
- @deskforge/logger
|
|
289
|
+
- Structured logging helpers for the framework and app code.
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
import { logger } from '@deskforge/logger'
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
- @deskforge/bridge
|
|
296
|
+
- Language bridge for calling code written in Python, Go, Rust, PHP, C, Kotlin, or Swift.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
import { callPython } from '@deskforge/bridge'
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
- @deskforge/cli
|
|
303
|
+
- Command-line tools for scaffolding and app management.
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
npx create-deskforge-app my-app
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## 5. Quick start: File-based routing
|
|
310
|
+
|
|
311
|
+
DeskForge now includes a file-based router similar to **Expo Router** and **Next.js**. Routes are discovered automatically from your screen files, so you do not manually register them. Your App.ts file acts as the landing page and app shell for the discovered screens:
|
|
87
312
|
|
|
88
313
|
```ts
|
|
89
314
|
import { FileRouter, ManifestBuilder, Screen } from '@deskforge/router'
|
|
@@ -171,7 +396,7 @@ await renderer.saveAs('./dist/output.png')
|
|
|
171
396
|
|
|
172
397
|
### 5.3 Screens and routes
|
|
173
398
|
|
|
174
|
-
DeskForge uses
|
|
399
|
+
DeskForge uses automatic route discovery from a screen folder structure. A screen is simply a function that returns a node tree, and it can also carry metadata such as a title and layout. The App.ts entry file becomes the landing page that hosts the app shell and initial screen.
|
|
175
400
|
|
|
176
401
|
```ts
|
|
177
402
|
import { Screen } from '@deskforge/router'
|
|
@@ -185,14 +410,12 @@ function HomeScreen() {
|
|
|
185
410
|
const HomeRoute = Screen(HomeScreen, { title: 'Home', layout: 'app' })
|
|
186
411
|
```
|
|
187
412
|
|
|
188
|
-
|
|
413
|
+
The router discovers screens automatically from the file structure:
|
|
189
414
|
|
|
190
415
|
```ts
|
|
191
416
|
import { Router } from '@deskforge/router'
|
|
192
417
|
|
|
193
|
-
Router(
|
|
194
|
-
home: HomeRoute,
|
|
195
|
-
})
|
|
418
|
+
Router.start()
|
|
196
419
|
```
|
|
197
420
|
|
|
198
421
|
And navigate with:
|
|
@@ -207,8 +430,8 @@ Router.go('home')
|
|
|
207
430
|
|
|
208
431
|
The simplest app has three parts:
|
|
209
432
|
|
|
210
|
-
1. an entry point file, usually `App.ts
|
|
211
|
-
2. one or more screen files
|
|
433
|
+
1. an entry point file, usually `App.ts`, which acts as the landing page and app shell
|
|
434
|
+
2. one or more screen files discovered automatically by the router
|
|
212
435
|
3. a small UI helper layer for creating views and text blocks
|
|
213
436
|
|
|
214
437
|
The example app in `examples/deskforge-app` follows this pattern.
|
|
@@ -223,9 +446,7 @@ import { Renderer } from '@deskforge/renderer'
|
|
|
223
446
|
import { Router } from '@deskforge/router'
|
|
224
447
|
import { HomeScreen } from './src/screens'
|
|
225
448
|
|
|
226
|
-
Router(
|
|
227
|
-
home: HomeScreen,
|
|
228
|
-
})
|
|
449
|
+
Router.start()
|
|
229
450
|
|
|
230
451
|
function createRoot() {
|
|
231
452
|
return createNode('view', {
|
|
@@ -269,18 +490,14 @@ export default function HomeScreen(params: ScreenParams = {}) {
|
|
|
269
490
|
}
|
|
270
491
|
```
|
|
271
492
|
|
|
272
|
-
### 6.3
|
|
493
|
+
### 6.3 App entry and automatic screen discovery
|
|
273
494
|
|
|
274
|
-
|
|
495
|
+
The App.ts entry file serves as the landing page and initial app shell. Screen files under the app structure are discovered automatically and exposed by the router.
|
|
275
496
|
|
|
276
497
|
```ts
|
|
277
498
|
import { Router } from '@deskforge/router'
|
|
278
|
-
import { HomeScreen, DetailsScreen } from './src/screens'
|
|
279
499
|
|
|
280
|
-
Router(
|
|
281
|
-
home: HomeRoute,
|
|
282
|
-
details: DetailsRoute,
|
|
283
|
-
})
|
|
500
|
+
Router.start()
|
|
284
501
|
```
|
|
285
502
|
|
|
286
503
|
### 6.4 Navigate between screens
|
|
@@ -296,6 +513,9 @@ The current router stores navigation history and exposes helpers such as:
|
|
|
296
513
|
- `Router.forward()`
|
|
297
514
|
- `Router.params()`
|
|
298
515
|
- `Router.currentRoute()`
|
|
516
|
+
- `Router.start()`
|
|
517
|
+
|
|
518
|
+
For a React Navigation-like experience, DeskForge also supports a stack-style navigation model with screen components, route params, and a shared app shell defined in App.ts.
|
|
299
519
|
|
|
300
520
|
---
|
|
301
521
|
|
|
@@ -424,10 +644,10 @@ my-app/
|
|
|
424
644
|
|
|
425
645
|
### Suggested workflow
|
|
426
646
|
|
|
427
|
-
1. Create a main `App.ts` file.
|
|
647
|
+
1. Create a main `App.ts` file as the landing page and app shell.
|
|
428
648
|
2. Create one file per screen.
|
|
429
649
|
3. Create helper modules for common UI primitives.
|
|
430
|
-
4.
|
|
650
|
+
4. Let the router discover screens automatically.
|
|
431
651
|
5. Render the current screen through the renderer.
|
|
432
652
|
|
|
433
653
|
---
|
|
@@ -460,15 +680,7 @@ import { Renderer } from '@deskforge/renderer'
|
|
|
460
680
|
import { Router, Screen } from '@deskforge/router'
|
|
461
681
|
import { Text, View, Window } from './src/ui/Responsive'
|
|
462
682
|
|
|
463
|
-
Router(
|
|
464
|
-
home: () => Screen({ style: { background: '#f8fafc', padding: 24 } })
|
|
465
|
-
.add(
|
|
466
|
-
View({ style: { background: '#ffffff', borderRadius: 24, padding: 24 } }),
|
|
467
|
-
Text('DeskForge App', { style: { fontSize: 24, fontWeight: '700' } }),
|
|
468
|
-
Text('This is a simple DeskForge screen.', { style: { color: '#4b5563', fontSize: 16 } }),
|
|
469
|
-
)
|
|
470
|
-
.build(),
|
|
471
|
-
})
|
|
683
|
+
Router.start()
|
|
472
684
|
|
|
473
685
|
function createRoot() {
|
|
474
686
|
return Window({ style: { background: '#f7f8fb', padding: 24 } })
|
|
@@ -506,6 +718,8 @@ main().catch(console.error)
|
|
|
506
718
|
- Use helper functions to hide repetitive node creation.
|
|
507
719
|
- Keep route names stable and descriptive.
|
|
508
720
|
- Keep rendering logic separate from navigation logic.
|
|
721
|
+
- Use App.ts as the shared landing page and shell for the app.
|
|
722
|
+
- Let the router discover screens automatically instead of manually registering them.
|
|
509
723
|
- Use `dist/` for generated assets so your source stays clean.
|
|
510
724
|
|
|
511
725
|
---
|