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,80 @@
1
+ /**
2
+ * ScrollView Component
3
+ *
4
+ * Scrollable container for content that exceeds viewport.
5
+ * Accepts style and children array. Returns DFNode.
6
+ *
7
+ * No JSX. No HTML. No XML. Pure functional TypeScript.
8
+ */
9
+
10
+ import { createNode } from '@deskforge/core'
11
+ import type { DFNode, StyleObject } from '@deskforge/core'
12
+
13
+ /**
14
+ * ScrollView configuration properties
15
+ */
16
+ export interface ScrollViewProps {
17
+ /** Scroll in horizontal direction */
18
+ horizontal?: boolean
19
+ /** Show scroll indicator */
20
+ showsVerticalScrollIndicator?: boolean
21
+ /** Show horizontal scroll indicator */
22
+ showsHorizontalScrollIndicator?: boolean
23
+ /** Bounce effect on iOS */
24
+ bounces?: boolean
25
+ /** Scroll with deceleration */
26
+ decelerationRate?: number | 'fast' | 'normal'
27
+ /** Enable paging */
28
+ pagingEnabled?: boolean
29
+ /** Scroll event callback */
30
+ onScroll?: (offset: { x: number; y: number }) => void
31
+ }
32
+
33
+ /**
34
+ * ScrollView - Scrollable container component
35
+ *
36
+ * Renders a scrollable container for content overflow scenarios. Supports
37
+ * vertical and horizontal scrolling with configurable behavior.
38
+ *
39
+ * @param style - StyleObject for sizing and appearance
40
+ * @param children - Array of DFNode children to render inside
41
+ * @param props - Optional ScrollViewProps configuration
42
+ * @returns DFNode object with type 'ScrollView'
43
+ *
44
+ * @example
45
+ * ScrollView({ flex: 1 }, [
46
+ * Text('Item 1', { padding: 16 }),
47
+ * Text('Item 2', { padding: 16 }),
48
+ * Text('Item 3', { padding: 16 })
49
+ * ])
50
+ *
51
+ * ScrollView({ flex: 1 }, [
52
+ * View({ height: 200, backgroundColor: '#f0f0f0' }, [])
53
+ * ], {
54
+ * horizontal: true,
55
+ * showsHorizontalScrollIndicator: false,
56
+ * pagingEnabled: true
57
+ * })
58
+ */
59
+ export function ScrollView(
60
+ style: StyleObject,
61
+ children: DFNode[] = [],
62
+ props: ScrollViewProps = {}
63
+ ): DFNode {
64
+ return createNode(
65
+ 'ScrollView',
66
+ {
67
+ style,
68
+ horizontal: props.horizontal ?? false,
69
+ showsVerticalScrollIndicator: props.showsVerticalScrollIndicator ?? true,
70
+ showsHorizontalScrollIndicator: props.showsHorizontalScrollIndicator ?? true,
71
+ bounces: props.bounces ?? true,
72
+ decelerationRate: props.decelerationRate ?? 'normal',
73
+ pagingEnabled: props.pagingEnabled ?? false,
74
+ onScroll: props.onScroll,
75
+ } as Record<string, unknown>,
76
+ children
77
+ )
78
+ }
79
+
80
+ export type { StyleObject }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * SectionList Component
3
+ *
4
+ * Grouped/sectioned list renderer with section headers.
5
+ * Optimized for displaying categorized data.
6
+ *
7
+ * No JSX. No HTML. No XML. Pure functional TypeScript.
8
+ */
9
+
10
+ import { createNode } from '@deskforge/core'
11
+ import type { DFNode, StyleObject } from '@deskforge/core'
12
+
13
+ /**
14
+ * Section configuration for SectionList
15
+ */
16
+ export interface Section<T> {
17
+ /** Section title/key */
18
+ title: string
19
+ /** Items in this section */
20
+ data: T[]
21
+ }
22
+
23
+ /**
24
+ * SectionList configuration properties
25
+ */
26
+ export interface SectionListProps {
27
+ /** Item separator component renderer */
28
+ ItemSeparatorComponent?: () => DFNode
29
+ /** Section separator component */
30
+ SectionSeparatorComponent?: () => DFNode
31
+ /** Rendered at start of list */
32
+ ListHeaderComponent?: DFNode
33
+ /** Rendered at end of list */
34
+ ListFooterComponent?: DFNode
35
+ /** Rendered when list is empty */
36
+ ListEmptyComponent?: DFNode
37
+ /** Number of items to render at once */
38
+ initialNumToRender?: number
39
+ /** Scroll callback */
40
+ onScroll?: (offset: { x: number; y: number }) => void
41
+ /** Bounce effect */
42
+ bounces?: boolean
43
+ /** Show scroll indicators */
44
+ showsVerticalScrollIndicator?: boolean
45
+ }
46
+
47
+ /**
48
+ * SectionList - Grouped list renderer component
49
+ *
50
+ * High-performance list with section support. Groups related items under
51
+ * section headers. Generic over item type.
52
+ *
53
+ * @param sections - Array of Section objects containing title and data
54
+ * @param renderItem - Function that renders each item
55
+ * @param renderSectionHeader - Function that renders section headers
56
+ * @param style - Optional StyleObject for sizing
57
+ * @param props - Optional SectionListProps configuration
58
+ * @returns DFNode object with type 'SectionList'
59
+ *
60
+ * @example
61
+ * SectionList(
62
+ * [
63
+ * { title: 'Fruits', data: ['Apple', 'Banana'] },
64
+ * { title: 'Vegetables', data: ['Carrot', 'Lettuce'] }
65
+ * ],
66
+ * (item) => Text(item, { padding: 12 }),
67
+ * (title) => Text(title, { fontSize: 18, fontWeight: 'bold', padding: 8 }),
68
+ * { flex: 1 }
69
+ * )
70
+ *
71
+ * SectionList(
72
+ * groupedContacts,
73
+ * (contact) => Pressable(
74
+ * { padding: 12 },
75
+ * { onPress: () => openContact(contact.id) },
76
+ * [Text(contact.name)]
77
+ * ),
78
+ * (letter) => Text(letter, { fontSize: 16, fontWeight: 'bold', backgroundColor: '#f0f0f0', padding: 8 }),
79
+ * { flex: 1 },
80
+ * { ItemSeparatorComponent: () => View({ height: 1, backgroundColor: '#eee' }, []) }
81
+ * )
82
+ */
83
+ export function SectionList<T>(
84
+ sections: Section<T>[],
85
+ renderItem: (item: T) => DFNode,
86
+ renderSectionHeader: (title: string) => DFNode,
87
+ style?: StyleObject,
88
+ props: SectionListProps = {}
89
+ ): DFNode {
90
+ const items: DFNode[] = []
91
+
92
+ for (const section of sections) {
93
+ items.push(renderSectionHeader(section.title))
94
+ for (const item of section.data) {
95
+ items.push(renderItem(item))
96
+ }
97
+ }
98
+
99
+ return createNode(
100
+ 'SectionList',
101
+ {
102
+ style: style ?? {},
103
+ sections,
104
+ renderItem,
105
+ renderSectionHeader,
106
+ ItemSeparatorComponent: props.ItemSeparatorComponent,
107
+ SectionSeparatorComponent: props.SectionSeparatorComponent,
108
+ ListHeaderComponent: props.ListHeaderComponent,
109
+ ListFooterComponent: props.ListFooterComponent,
110
+ ListEmptyComponent: props.ListEmptyComponent,
111
+ initialNumToRender: props.initialNumToRender ?? 10,
112
+ onScroll: props.onScroll,
113
+ bounces: props.bounces ?? true,
114
+ showsVerticalScrollIndicator: props.showsVerticalScrollIndicator ?? true,
115
+ } as Record<string, unknown>,
116
+ items
117
+ )
118
+ }
119
+
120
+ export type { StyleObject, Section }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * ActivityIndicator Component
3
+ *
4
+ * Spinning loading indicator showing progress/loading state.
5
+ * Animated automatically, no manual control needed.
6
+ *
7
+ * No JSX. No HTML. No XML. Pure functional TypeScript.
8
+ */
9
+
10
+ import { createNode } from '@deskforge/core'
11
+ import type { DFNode, StyleObject } from '@deskforge/core'
12
+
13
+ /**
14
+ * ActivityIndicator configuration properties
15
+ */
16
+ export interface ActivityIndicatorProps {
17
+ /** Indicator color */
18
+ color?: string
19
+ /** Size: 'small' | 'large' | number */
20
+ size?: 'small' | 'large' | number
21
+ /** Hide indicator when not animating */
22
+ hidesWhenStopped?: boolean
23
+ /** Animation running state */
24
+ animating?: boolean
25
+ }
26
+
27
+ /**
28
+ * ActivityIndicator - Loading spinner component
29
+ *
30
+ * Displays an animated loading spinner. Automatically animates when mounted.
31
+ * Useful for showing loading states during async operations.
32
+ *
33
+ * @param style - Optional StyleObject for sizing and positioning
34
+ * @param props - Optional ActivityIndicatorProps configuration
35
+ * @returns DFNode object with type 'ActivityIndicator'
36
+ *
37
+ * @example
38
+ * ActivityIndicator({ margin: 20 }, {
39
+ * color: '#0077ff',
40
+ * size: 'large'
41
+ * })
42
+ *
43
+ * ActivityIndicator({
44
+ * flex: 1,
45
+ * justifyContent: 'center',
46
+ * alignItems: 'center'
47
+ * }, {
48
+ * animating: isLoading,
49
+ * hidesWhenStopped: true,
50
+ * size: 40
51
+ * })
52
+ */
53
+ export function ActivityIndicator(
54
+ style?: StyleObject,
55
+ props: ActivityIndicatorProps = {}
56
+ ): DFNode {
57
+ return createNode(
58
+ 'ActivityIndicator',
59
+ {
60
+ style: style ?? {},
61
+ color: props.color ?? '#0077ff',
62
+ size: props.size ?? 'large',
63
+ hidesWhenStopped: props.hidesWhenStopped ?? true,
64
+ animating: props.animating ?? true,
65
+ } as Record<string, unknown>,
66
+ []
67
+ )
68
+ }
69
+
70
+ export type { StyleObject }
@@ -47,12 +47,36 @@ interface ModalProps {
47
47
  }
48
48
 
49
49
  // Creates a modal dialog overlay node
50
- // children content displayed inside modal
51
- // props modal configuration
50
+ // Accepts multiple parameter combinations for flexibility
51
+ // Modal(children, props) - new API
52
+ // Modal(visible, onClose, style, children) - backward compatible
52
53
  function Modal(
53
- children: DFNode[],
54
- props: ModalProps
54
+ childrenOrVisible?: DFNode[] | boolean,
55
+ propsOrOnClose?: ModalProps | (() => void),
56
+ styleOrUndefined?: any,
57
+ childrenFallback?: DFNode[]
55
58
  ): DFNode {
59
+ let children: DFNode[] = []
60
+ let props: ModalProps = { open: false, onClose: () => {} }
61
+
62
+ // New API: Modal(children, props)
63
+ if (Array.isArray(childrenOrVisible)) {
64
+ children = childrenOrVisible
65
+ if (propsOrOnClose && typeof propsOrOnClose === 'object' && !Array.isArray(propsOrOnClose)) {
66
+ props = { ...props, ...propsOrOnClose as ModalProps }
67
+ }
68
+ }
69
+ // Old API: Modal(visible, onClose, style, children)
70
+ else if (typeof childrenOrVisible === 'boolean') {
71
+ props.open = childrenOrVisible
72
+ if (typeof propsOrOnClose === 'function') {
73
+ props.onClose = propsOrOnClose
74
+ }
75
+ if (Array.isArray(childrenFallback)) {
76
+ children = childrenFallback
77
+ }
78
+ }
79
+
56
80
  return createNode('Modal', {
57
81
  open: props.open,
58
82
  onClose: props.onClose,
@@ -66,8 +90,6 @@ function Modal(
66
90
  closeOnBackdrop: props.closeOnBackdrop ?? true,
67
91
  closeOnEscape: props.closeOnEscape ?? true,
68
92
  padding: props.padding ?? 24,
69
-
70
- // Scale in animation from center
71
93
  animationType: 'scaleIn',
72
94
  } as Record<string, unknown>, children)
73
95
  }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Platform Module
3
+ *
4
+ * Cross-platform utilities for OS detection and platform-specific components.
5
+ * Provides OS constant and selection utilities.
6
+ *
7
+ * No JSX. No HTML. No XML. Pure functional TypeScript.
8
+ */
9
+
10
+ import type { DFNode } from '@deskforge/core'
11
+
12
+ /**
13
+ * Supported platform OS types
14
+ */
15
+ export type PlatformOS = 'windows' | 'macos' | 'linux' | 'ios' | 'android'
16
+
17
+ /**
18
+ * Platform configuration options for select()
19
+ */
20
+ export interface PlatformSelectOptions<T> {
21
+ ios?: T
22
+ android?: T
23
+ windows?: T
24
+ macos?: T
25
+ linux?: T
26
+ web?: T
27
+ native?: T
28
+ default?: T
29
+ }
30
+
31
+ /**
32
+ * Platform - Cross-platform utilities
33
+ *
34
+ * Provides OS detection and platform-specific component/value selection.
35
+ * Enables building truly universal apps with single codebase.
36
+ */
37
+ export const Platform = {
38
+ /**
39
+ * Get current operating system
40
+ *
41
+ * @returns Current platform OS: 'windows' | 'macos' | 'linux' | 'ios' | 'android'
42
+ */
43
+ get OS(): PlatformOS {
44
+ if (typeof globalThis !== 'undefined') {
45
+ if (globalThis.navigator?.userAgent?.includes('iPhone')) return 'ios'
46
+ if (globalThis.navigator?.userAgent?.includes('Android')) return 'android'
47
+ if (globalThis.navigator?.userAgent?.includes('Windows')) return 'windows'
48
+ if (globalThis.navigator?.userAgent?.includes('Macintosh')) return 'macos'
49
+ if (globalThis.navigator?.userAgent?.includes('Linux')) return 'linux'
50
+ }
51
+ return 'linux' // default fallback
52
+ },
53
+
54
+ /**
55
+ * Select value based on platform
56
+ *
57
+ * @param options - Object with platform keys and values
58
+ * @returns Value for current platform
59
+ *
60
+ * @example
61
+ * Platform.select({
62
+ * ios: 'padding',
63
+ * android: 'height',
64
+ * default: 'padding'
65
+ * })
66
+ */
67
+ select<T>(options: PlatformSelectOptions<T>): T {
68
+ const os = Platform.OS
69
+
70
+ if (os === 'ios' && options.ios !== undefined) return options.ios
71
+ if (os === 'android' && options.android !== undefined) return options.android
72
+ if (os === 'windows' && options.windows !== undefined) return options.windows
73
+ if (os === 'macos' && options.macos !== undefined) return options.macos
74
+ if (os === 'linux' && options.linux !== undefined) return options.linux
75
+
76
+ if (options.native !== undefined) return options.native
77
+ if (options.default !== undefined) return options.default
78
+
79
+ throw new Error(`No value provided for platform: ${os}`)
80
+ },
81
+
82
+ /**
83
+ * Render component on desktop platforms only (Windows, macOS, Linux)
84
+ *
85
+ * @param node - DFNode to render on desktop
86
+ * @returns Node if on desktop, null otherwise
87
+ */
88
+ desktop(node: DFNode): DFNode | null {
89
+ const os = Platform.OS
90
+ if (os === 'windows' || os === 'macos' || os === 'linux') {
91
+ return node
92
+ }
93
+ return null
94
+ },
95
+
96
+ /**
97
+ * Render component on mobile platforms only (iOS, Android)
98
+ *
99
+ * @param node - DFNode to render on mobile
100
+ * @returns Node if on mobile, null otherwise
101
+ */
102
+ mobile(node: DFNode): DFNode | null {
103
+ const os = Platform.OS
104
+ if (os === 'ios' || os === 'android') {
105
+ return node
106
+ }
107
+ return null
108
+ },
109
+
110
+ /**
111
+ * Render component on any platform
112
+ *
113
+ * @param node - DFNode to always render
114
+ * @returns Node (always)
115
+ */
116
+ any(node: DFNode): DFNode {
117
+ return node
118
+ },
119
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * StatusBar Component
3
+ *
4
+ * Controls platform status bar (mobile) styling and visibility.
5
+ * Platform-specific implementation handled by runtime.
6
+ *
7
+ * No JSX. No HTML. No XML. Pure functional TypeScript.
8
+ */
9
+
10
+ import { createNode } from '@deskforge/core'
11
+ import type { DFNode } from '@deskforge/core'
12
+
13
+ /**
14
+ * StatusBar configuration properties
15
+ */
16
+ export interface StatusBarProps {
17
+ /** Status bar background color */
18
+ backgroundColor?: string
19
+ /** Status bar icon/text color: 'light-content' | 'dark-content' */
20
+ barStyle?: 'light-content' | 'dark-content'
21
+ /** Hidden state */
22
+ hidden?: boolean
23
+ /** Translucent (iOS) */
24
+ translucent?: boolean
25
+ /** Network activity indicator visible (iOS) */
26
+ networkActivityIndicatorVisible?: boolean
27
+ }
28
+
29
+ /**
30
+ * StatusBar - Platform status bar component
31
+ *
32
+ * Configures the system status bar appearance. Platform-specific
33
+ * implementation on iOS and Android. Has no visual output on desktop.
34
+ *
35
+ * @param props - StatusBarProps configuration
36
+ * @returns DFNode object with type 'StatusBar'
37
+ *
38
+ * @example
39
+ * StatusBar({
40
+ * backgroundColor: '#0077ff',
41
+ * barStyle: 'light-content',
42
+ * hidden: false
43
+ * })
44
+ *
45
+ * StatusBar({
46
+ * backgroundColor: '#fff',
47
+ * barStyle: 'dark-content',
48
+ * translucent: true
49
+ * })
50
+ */
51
+ export function StatusBar(props: StatusBarProps = {}): DFNode {
52
+ return createNode(
53
+ 'StatusBar',
54
+ {
55
+ backgroundColor: props.backgroundColor ?? '#000',
56
+ barStyle: props.barStyle ?? 'light-content',
57
+ hidden: props.hidden ?? false,
58
+ translucent: props.translucent ?? false,
59
+ networkActivityIndicatorVisible: props.networkActivityIndicatorVisible ?? false,
60
+ } as Record<string, unknown>,
61
+ []
62
+ )
63
+ }