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,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
|
-
//
|
|
51
|
-
// props
|
|
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
|
-
|
|
54
|
-
|
|
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
|
+
}
|