@stacksjs/desktop 0.2.3

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.
@@ -0,0 +1,201 @@
1
+ import type { ModalOptions, ModalResult } from './types';
2
+ /**
3
+ * Show a native modal dialog
4
+ *
5
+ * @param options - Modal configuration options
6
+ * @returns Promise resolving to the modal result
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const result = await showModal({
11
+ * title: 'Confirm Action',
12
+ * message: 'Are you sure you want to proceed?',
13
+ * type: 'question',
14
+ * buttons: [
15
+ * { label: 'Cancel', style: 'default' },
16
+ * { label: 'Confirm', style: 'primary' },
17
+ * ],
18
+ * })
19
+ *
20
+ * if (result.buttonIndex === 1) {
21
+ * // User clicked Confirm
22
+ * }
23
+ * ```
24
+ */
25
+ export declare function showModal(options: ModalOptions): Promise<ModalResult>;
26
+ /**
27
+ * Show an info modal
28
+ */
29
+ export declare function showInfoModal(title: string, message: string): Promise<ModalResult>;
30
+ /**
31
+ * Show a warning modal
32
+ */
33
+ export declare function showWarningModal(title: string, message: string): Promise<ModalResult>;
34
+ /**
35
+ * Show an error modal
36
+ */
37
+ export declare function showErrorModal(title: string, message: string): Promise<ModalResult>;
38
+ /**
39
+ * Show a success modal
40
+ */
41
+ export declare function showSuccessModal(title: string, message: string): Promise<ModalResult>;
42
+ /**
43
+ * Show a question/confirmation modal
44
+ */
45
+ export declare function showQuestionModal(title: string, message: string): Promise<ModalResult>;
46
+ /**
47
+ * Show a confirm dialog (alias for showQuestionModal)
48
+ */
49
+ export declare function confirm(message: string, title?: string): Promise<boolean>;
50
+ /**
51
+ * Show an alert dialog (single OK button)
52
+ */
53
+ export declare function alert(message: string, title?: string): Promise<void>;
54
+ /**
55
+ * Show a prompt dialog with input field
56
+ */
57
+ export declare function prompt(message: string, defaultValue?: string, title?: string): Promise<string | null>;
58
+ /**
59
+ * Get number of active modals
60
+ */
61
+ export declare function getActiveModalCount(): number;
62
+ /**
63
+ * Close all active modals
64
+ */
65
+ export declare function closeAllModals(): void;
66
+ /**
67
+ * CSS styles for web-based modals
68
+ */
69
+ export declare const MODAL_STYLES: `
70
+ .stx-modal-overlay {
71
+ position: fixed;
72
+ inset: 0;
73
+ background: rgba(0, 0, 0, 0.5);
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ z-index: 10000;
78
+ animation: stx-modal-fade-in 0.15s ease-out;
79
+ }
80
+
81
+ @keyframes stx-modal-fade-in {
82
+ from { opacity: 0; }
83
+ to { opacity: 1; }
84
+ }
85
+
86
+ .stx-modal {
87
+ background: #fff;
88
+ border-radius: 12px;
89
+ padding: 24px;
90
+ max-width: 400px;
91
+ width: 90%;
92
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
93
+ animation: stx-modal-slide-up 0.2s ease-out;
94
+ }
95
+
96
+ @keyframes stx-modal-slide-up {
97
+ from { transform: translateY(20px); opacity: 0; }
98
+ to { transform: translateY(0); opacity: 1; }
99
+ }
100
+
101
+ @media (prefers-color-scheme: dark) {
102
+ .stx-modal {
103
+ background: #2d2d2d;
104
+ color: #fff;
105
+ }
106
+ }
107
+
108
+ .stx-modal-icon {
109
+ font-size: 48px;
110
+ text-align: center;
111
+ margin-bottom: 16px;
112
+ }
113
+
114
+ .stx-modal.info .stx-modal-icon { color: #3498db; }
115
+ .stx-modal.warning .stx-modal-icon { color: #f39c12; }
116
+ .stx-modal.error .stx-modal-icon { color: #e74c3c; }
117
+ .stx-modal.success .stx-modal-icon { color: #27ae60; }
118
+ .stx-modal.question .stx-modal-icon { color: #9b59b6; }
119
+
120
+ .stx-modal-content {
121
+ text-align: center;
122
+ margin-bottom: 24px;
123
+ }
124
+
125
+ .stx-modal-title {
126
+ margin: 0 0 8px;
127
+ font-size: 20px;
128
+ font-weight: 600;
129
+ }
130
+
131
+ .stx-modal-message {
132
+ margin: 0;
133
+ color: #666;
134
+ line-height: 1.5;
135
+ }
136
+
137
+ @media (prefers-color-scheme: dark) {
138
+ .stx-modal-message { color: #aaa; }
139
+ }
140
+
141
+ .stx-modal-buttons {
142
+ display: flex;
143
+ gap: 8px;
144
+ justify-content: center;
145
+ }
146
+
147
+ .stx-modal-btn {
148
+ padding: 10px 24px;
149
+ border-radius: 6px;
150
+ font-size: 14px;
151
+ font-weight: 500;
152
+ cursor: pointer;
153
+ border: none;
154
+ transition: background 0.15s, transform 0.1s;
155
+ }
156
+
157
+ .stx-modal-btn:hover {
158
+ transform: translateY(-1px);
159
+ }
160
+
161
+ .stx-modal-btn:active {
162
+ transform: translateY(0);
163
+ }
164
+
165
+ .stx-modal-btn.default {
166
+ background: #e0e0e0;
167
+ color: #333;
168
+ }
169
+
170
+ .stx-modal-btn.default:hover {
171
+ background: #d0d0d0;
172
+ }
173
+
174
+ .stx-modal-btn.primary {
175
+ background: #3498db;
176
+ color: #fff;
177
+ }
178
+
179
+ .stx-modal-btn.primary:hover {
180
+ background: #2980b9;
181
+ }
182
+
183
+ .stx-modal-btn.destructive {
184
+ background: #e74c3c;
185
+ color: #fff;
186
+ }
187
+
188
+ .stx-modal-btn.destructive:hover {
189
+ background: #c0392b;
190
+ }
191
+
192
+ @media (prefers-color-scheme: dark) {
193
+ .stx-modal-btn.default {
194
+ background: #444;
195
+ color: #fff;
196
+ }
197
+ .stx-modal-btn.default:hover {
198
+ background: #555;
199
+ }
200
+ }
201
+ `;
@@ -0,0 +1,121 @@
1
+ import type { SystemTrayInstance, SystemTrayOptions } from './types';
2
+ /**
3
+ * Create a system tray/menubar application
4
+ *
5
+ * When running inside a Craft native window, this creates a real native tray.
6
+ * Otherwise, it creates a simulated tray for development purposes.
7
+ *
8
+ * @param options - Tray configuration options
9
+ * @returns System tray instance
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const tray = await createSystemTray({
14
+ * icon: './icon.png',
15
+ * tooltip: 'My App',
16
+ * menu: [
17
+ * { label: 'Show Window', onClick: () => stxWindow.show() },
18
+ * { type: 'separator' },
19
+ * { label: 'Quit', onClick: () => stxWindow.quit() },
20
+ * ],
21
+ * })
22
+ * ```
23
+ */
24
+ export declare function createSystemTray(options?: SystemTrayOptions): Promise<SystemTrayInstance>;
25
+ /**
26
+ * Get all active tray instances
27
+ */
28
+ export declare function getActiveTrayInstances(): string[];
29
+ /**
30
+ * Get a tray instance by ID
31
+ */
32
+ export declare function getTrayInstance(id: string): SystemTrayInstance | null;
33
+ /**
34
+ * Trigger a menu item action by label
35
+ * Useful for testing and programmatic control
36
+ */
37
+ export declare function triggerTrayAction(trayId: string, actionLabel: string): boolean;
38
+ /**
39
+ * Get the HTML for a simulated tray menu
40
+ * Useful for web-based testing and development
41
+ */
42
+ export declare function getSimulatedTrayHTML(trayId: string): string | null;
43
+ /**
44
+ * Generate a JavaScript snippet for tray control from inside a webview.
45
+ * This provides convenient wrappers around the Craft tray bridge.
46
+ */
47
+ export declare function getTrayBridgeScript(): string;
48
+ /**
49
+ * Create a menubar application (alias for createSystemTray)
50
+ */
51
+ export declare const createMenubar: typeof createSystemTray;
52
+ /**
53
+ * CSS styles for the simulated tray menu
54
+ */
55
+ export declare const TRAY_MENU_STYLES: `
56
+ .stx-tray-menu {
57
+ background: #2d2d2d;
58
+ border-radius: 8px;
59
+ padding: 4px 0;
60
+ min-width: 200px;
61
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
62
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
63
+ font-size: 13px;
64
+ color: #fff;
65
+ }
66
+
67
+ .stx-tray-item {
68
+ padding: 6px 12px;
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: space-between;
72
+ cursor: pointer;
73
+ position: relative;
74
+ }
75
+
76
+ .stx-tray-item:hover {
77
+ background: #3d3d3d;
78
+ }
79
+
80
+ .stx-tray-item.disabled {
81
+ opacity: 0.5;
82
+ cursor: not-allowed;
83
+ }
84
+
85
+ .stx-tray-item .label {
86
+ flex: 1;
87
+ }
88
+
89
+ .stx-tray-item .accelerator {
90
+ margin-left: 20px;
91
+ opacity: 0.6;
92
+ font-size: 12px;
93
+ }
94
+
95
+ .stx-tray-item .arrow {
96
+ margin-left: 8px;
97
+ font-size: 10px;
98
+ }
99
+
100
+ .stx-tray-separator {
101
+ margin: 4px 0;
102
+ border: none;
103
+ border-top: 1px solid #444;
104
+ }
105
+
106
+ .stx-tray-submenu {
107
+ position: absolute;
108
+ left: 100%;
109
+ top: 0;
110
+ background: #2d2d2d;
111
+ border-radius: 8px;
112
+ padding: 4px 0;
113
+ min-width: 150px;
114
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
115
+ display: none;
116
+ }
117
+
118
+ .stx-tray-item:hover > .stx-tray-submenu {
119
+ display: block;
120
+ }
121
+ `;
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Desktop Application Types
3
+ */
4
+ /**
5
+ * Sidebar item configuration
6
+ */
7
+ export declare interface SidebarItem {
8
+ id: string
9
+ label: string
10
+ icon?: string
11
+ badge?: string | number
12
+ tintColor?: string
13
+ selected?: boolean
14
+ disabled?: boolean
15
+ children?: SidebarItem[]
16
+ data?: Record<string, unknown>
17
+ }
18
+ /**
19
+ * Sidebar section with header
20
+ */
21
+ export declare interface SidebarSection {
22
+ id: string
23
+ title: string
24
+ collapsible?: boolean
25
+ collapsed?: boolean
26
+ items: SidebarItem[]
27
+ }
28
+ /**
29
+ * Native sidebar configuration
30
+ */
31
+ export declare interface SidebarConfig {
32
+ sections: SidebarSection[]
33
+ minWidth?: number
34
+ maxWidth?: number
35
+ canCollapse?: boolean
36
+ searchPlaceholder?: string
37
+ header?: {
38
+ title?: string
39
+ subtitle?: string
40
+ icon?: string
41
+ }
42
+ }
43
+ /**
44
+ * Window configuration options
45
+ */
46
+ export declare interface WindowOptions {
47
+ title?: string
48
+ width?: number
49
+ height?: number
50
+ darkMode?: boolean
51
+ hotReload?: boolean
52
+ resizable?: boolean
53
+ minimizable?: boolean
54
+ maximizable?: boolean
55
+ closable?: boolean
56
+ alwaysOnTop?: boolean
57
+ frameless?: boolean
58
+ backgroundColor?: string
59
+ nativeSidebar?: boolean
60
+ sidebarWidth?: number
61
+ sidebarConfig?: SidebarConfig
62
+ }
63
+ /**
64
+ * System tray/menubar configuration options
65
+ */
66
+ export declare interface SystemTrayOptions {
67
+ icon?: string
68
+ tooltip?: string
69
+ menu?: SystemTrayMenuItem[]
70
+ }
71
+ /**
72
+ * Modal dialog options
73
+ */
74
+ export declare interface ModalOptions {
75
+ title?: string
76
+ message: string
77
+ type?: 'info' | 'warning' | 'error' | 'success' | 'question'
78
+ buttons?: ModalButton[]
79
+ defaultButton?: number
80
+ cancelButton?: number
81
+ }
82
+ /**
83
+ * Modal button configuration
84
+ */
85
+ export declare interface ModalButton {
86
+ label: string
87
+ action?: () => void
88
+ style?: 'default' | 'primary' | 'destructive'
89
+ }
90
+ /**
91
+ * Alert/notification options
92
+ */
93
+ export declare interface AlertOptions {
94
+ title?: string
95
+ message: string
96
+ type?: 'info' | 'success' | 'warning' | 'error'
97
+ duration?: number
98
+ position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
99
+ theme?: 'light' | 'dark' | 'auto'
100
+ onClick?: () => void
101
+ }
102
+ /**
103
+ * Component base properties
104
+ */
105
+ export declare interface ComponentProps {
106
+ id?: string
107
+ className?: string
108
+ style?: Record<string, string>
109
+ visible?: boolean
110
+ enabled?: boolean
111
+ }
112
+ /**
113
+ * Window instance
114
+ */
115
+ export declare interface WindowInstance {
116
+ id: string
117
+ show: () => void
118
+ hide: () => void
119
+ close: () => void
120
+ focus: () => void
121
+ minimize: () => void
122
+ maximize: () => void
123
+ restore: () => void
124
+ setTitle: (title: string) => void
125
+ loadURL: (url: string) => void
126
+ reload: () => void
127
+ }
128
+ /**
129
+ * System tray instance
130
+ */
131
+ export declare interface SystemTrayInstance {
132
+ id: string
133
+ setIcon: (icon: string) => void
134
+ setTooltip: (tooltip: string) => void
135
+ setMenu: (menu: SystemTrayMenuItem[]) => void
136
+ destroy: () => void
137
+ }
138
+ /**
139
+ * Result of modal dialog
140
+ */
141
+ export declare interface ModalResult {
142
+ buttonIndex: number
143
+ cancelled: boolean
144
+ }
145
+ /**
146
+ * System tray menu item
147
+ */
148
+ export type SystemTrayMenuItem = | {
149
+ /** Menu item label */
150
+ label: string
151
+ /** Click handler */
152
+ onClick?: () => void
153
+ /** Keyboard shortcut */
154
+ accelerator?: string
155
+ /** Menu item type */
156
+ type?: 'normal' | 'checkbox' | 'submenu'
157
+ /** Submenu items (if type is 'submenu') */
158
+ submenu?: SystemTrayMenuItem[]
159
+ /** Is checkbox checked (if type is 'checkbox') */
160
+ checked?: boolean
161
+ /** Is menu item enabled */
162
+ enabled?: boolean
163
+ }
164
+ | {
165
+ /** Menu item type */
166
+ type: 'separator'
167
+ }
168
+ /**
169
+ * Toast notification options (alias for AlertOptions)
170
+ */
171
+ export type ToastOptions = AlertOptions
@@ -0,0 +1,111 @@
1
+ import type { WindowInstance, WindowOptions } from './types';
2
+ /**
3
+ * Configure desktop window settings
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * setDesktopConfig({
8
+ * craftBinaryPath: '/custom/path/to/craft',
9
+ * maxRetries: 3,
10
+ * retryDelay: 2000
11
+ * })
12
+ * ```
13
+ */
14
+ export declare function setDesktopConfig(config: Partial<DesktopConfig>): void;
15
+ /**
16
+ * Get current desktop configuration
17
+ */
18
+ export declare function getDesktopConfig(): DesktopConfig;
19
+ /**
20
+ * Reset desktop configuration to defaults
21
+ */
22
+ export declare function resetDesktopConfig(): void;
23
+ /**
24
+ * Get all active window IDs
25
+ */
26
+ export declare function getActiveWindowIds(): string[];
27
+ /**
28
+ * Get a window by ID
29
+ */
30
+ export declare function getWindow(id: string): WindowInstance | null;
31
+ /**
32
+ * Close all active windows
33
+ */
34
+ export declare function closeAllWindows(): void;
35
+ /**
36
+ * Create a native window with URL
37
+ *
38
+ * Uses ts-craft to create native desktop windows. Falls back to returning null
39
+ * if ts-craft is not available.
40
+ *
41
+ * ## Window Control
42
+ *
43
+ * The CraftApp spawns a native webview process. Window control methods like
44
+ * hide(), minimize(), setTitle() etc. are available via the `window.craft`
45
+ * bridge **inside** the webview context:
46
+ *
47
+ * ```javascript
48
+ * // Inside your HTML/JS running in the webview:
49
+ * window.craft.window.hide()
50
+ * window.craft.window.minimize()
51
+ * window.craft.window.setTitle({ title: 'New Title' })
52
+ * window.craft.window.center()
53
+ * ```
54
+ *
55
+ * The returned WindowInstance provides the `close()` method which terminates
56
+ * the native process from the Node.js side.
57
+ *
58
+ * @param url - URL to load in the window
59
+ * @param options - Window configuration options
60
+ * @returns WindowInstance if successful, null if ts-craft unavailable
61
+ */
62
+ export declare function createWindow(url: string, options?: WindowOptions): Promise<WindowInstance | null>;
63
+ /**
64
+ * Open a development server window
65
+ * This is specifically for the stx dev server --native flag
66
+ *
67
+ * Uses ts-craft to create a native window, falls back to browser if unavailable.
68
+ */
69
+ export declare function openDevWindow(port: number, options?: WindowOptions): Promise<boolean>;
70
+ /**
71
+ * Create a window with HTML content
72
+ *
73
+ * Uses ts-craft to display HTML content in a native window.
74
+ */
75
+ export declare function createWindowWithHTML(html: string, options?: WindowOptions): Promise<WindowInstance | null>;
76
+ /**
77
+ * Helper to check if webview implementation is available
78
+ */
79
+ export declare function isWebviewAvailable(): boolean;
80
+ /**
81
+ * Generate a JavaScript snippet to inject into HTML that provides
82
+ * helper functions for common window operations.
83
+ *
84
+ * This can be injected into your HTML to provide easier access to Craft APIs.
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const html = `
89
+ * <html>
90
+ * <head>
91
+ * <script>${getWindowBridgeScript()}</script>
92
+ * </head>
93
+ * <body>
94
+ * <button onclick="stxWindow.minimize()">Minimize</button>
95
+ * </body>
96
+ * </html>
97
+ * `
98
+ * await createWindowWithHTML(html)
99
+ * ```
100
+ */
101
+ export declare function getWindowBridgeScript(): string;
102
+ /**
103
+ * Desktop window configuration.
104
+ * Can be set via environment variables or setDesktopConfig().
105
+ */
106
+ export declare interface DesktopConfig {
107
+ craftBinaryPath?: string
108
+ additionalSearchPaths?: string[]
109
+ maxRetries?: number
110
+ retryDelay?: number
111
+ }
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@stacksjs/desktop",
3
+ "type": "module",
4
+ "version": "0.2.3",
5
+ "description": "Native desktop application framework for stx (powered by Craft)",
6
+ "author": "Chris Breuer <chris@stacksjs.org>",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/stacksjs/stx#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/stacksjs/stx.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/stacksjs/stx/issues"
15
+ },
16
+ "keywords": [
17
+ "desktop",
18
+ "native",
19
+ "window",
20
+ "craft",
21
+ "electron-alternative",
22
+ "webview",
23
+ "cross-platform",
24
+ "stx"
25
+ ],
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ },
31
+ "./*": {
32
+ "import": "./dist/*"
33
+ }
34
+ },
35
+ "module": "./dist/index.js",
36
+ "types": "./dist/index.d.ts",
37
+ "files": [
38
+ "LICENSE.md",
39
+ "README.md",
40
+ "dist"
41
+ ],
42
+ "scripts": {
43
+ "build": "bun --bun build.ts",
44
+ "lint": "bunx --bun pickier lint",
45
+ "lint:fix": "bunx --bun pickier lint --fix",
46
+ "fresh": "bunx rimraf node_modules/ bun.lock && bun i",
47
+ "prepublishOnly": "bun run build",
48
+ "test": "bun test --preload ../../test-utils/happy-dom.ts",
49
+ "test:watch": "bun test --watch --preload ../../test-utils/happy-dom.ts",
50
+ "test:coverage": "bun test --coverage --preload ../../test-utils/happy-dom.ts",
51
+ "typecheck": "bun tsc --noEmit"
52
+ },
53
+ "peerDependencies": {
54
+ "craft": "*"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "craft": {
58
+ "optional": true
59
+ }
60
+ },
61
+ "dependencies": {},
62
+ "devDependencies": {}
63
+ }