@flightdev/desktop 0.2.0

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,217 @@
1
+ import { ref, onMounted } from 'vue';
2
+
3
+ // src/vue/index.ts
4
+
5
+ // src/index.ts
6
+ function getTauri() {
7
+ try {
8
+ return globalThis.__TAURI__;
9
+ } catch {
10
+ return null;
11
+ }
12
+ }
13
+ function isTauri() {
14
+ return getTauri() !== null;
15
+ }
16
+ function getPlatform() {
17
+ const tauri = getTauri();
18
+ if (!tauri) {
19
+ return {
20
+ platform: "web",
21
+ isDesktop: false,
22
+ isWindows: false,
23
+ isMac: false,
24
+ isLinux: false,
25
+ isWeb: true,
26
+ hasTauri: false
27
+ };
28
+ }
29
+ const userAgent = navigator.userAgent.toLowerCase();
30
+ let platform = "web";
31
+ if (userAgent.includes("win")) {
32
+ platform = "windows";
33
+ } else if (userAgent.includes("mac")) {
34
+ platform = "macos";
35
+ } else if (userAgent.includes("linux")) {
36
+ platform = "linux";
37
+ }
38
+ return {
39
+ platform,
40
+ isDesktop: true,
41
+ isWindows: platform === "windows",
42
+ isMac: platform === "macos",
43
+ isLinux: platform === "linux",
44
+ isWeb: false,
45
+ hasTauri: true
46
+ };
47
+ }
48
+
49
+ // src/vue/index.ts
50
+ function usePlatform() {
51
+ return getPlatform();
52
+ }
53
+ function useWindow() {
54
+ const isMaximized = ref(false);
55
+ const available = isTauri();
56
+ onMounted(async () => {
57
+ if (!available) return;
58
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
59
+ isMaximized.value = await getCurrentWindow().isMaximized();
60
+ });
61
+ const minimize = async () => {
62
+ if (!available) return;
63
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
64
+ await getCurrentWindow().minimize();
65
+ };
66
+ const maximize = async () => {
67
+ if (!available) return;
68
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
69
+ await getCurrentWindow().toggleMaximize();
70
+ isMaximized.value = await getCurrentWindow().isMaximized();
71
+ };
72
+ const close = async () => {
73
+ if (!available) return;
74
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
75
+ await getCurrentWindow().close();
76
+ };
77
+ const setTitle = async (title) => {
78
+ if (!available) {
79
+ document.title = title;
80
+ return;
81
+ }
82
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
83
+ await getCurrentWindow().setTitle(title);
84
+ };
85
+ return { minimize, maximize, close, setTitle, isMaximized, available };
86
+ }
87
+ function useFileSystem() {
88
+ const available = isTauri();
89
+ const readFile = async (path) => {
90
+ if (!available) return null;
91
+ try {
92
+ const { readTextFile } = await import('@tauri-apps/plugin-fs');
93
+ return await readTextFile(path);
94
+ } catch {
95
+ return null;
96
+ }
97
+ };
98
+ const writeFile = async (path, content) => {
99
+ if (!available) return false;
100
+ try {
101
+ const { writeTextFile } = await import('@tauri-apps/plugin-fs');
102
+ await writeTextFile(path, content);
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
+ };
108
+ const exists = async (path) => {
109
+ if (!available) return false;
110
+ try {
111
+ const fs = await import('@tauri-apps/plugin-fs');
112
+ return await fs.exists(path);
113
+ } catch {
114
+ return false;
115
+ }
116
+ };
117
+ return { readFile, writeFile, exists, available };
118
+ }
119
+ function useDialog() {
120
+ const available = isTauri();
121
+ const selectFile = async (options) => {
122
+ if (!available) return null;
123
+ try {
124
+ const { open } = await import('@tauri-apps/plugin-dialog');
125
+ return await open({ multiple: options?.multiple ?? false });
126
+ } catch {
127
+ return null;
128
+ }
129
+ };
130
+ const selectFolder = async () => {
131
+ if (!available) return null;
132
+ try {
133
+ const { open } = await import('@tauri-apps/plugin-dialog');
134
+ return await open({ directory: true });
135
+ } catch {
136
+ return null;
137
+ }
138
+ };
139
+ const message = async (msg) => {
140
+ if (!available) {
141
+ alert(msg);
142
+ return;
143
+ }
144
+ try {
145
+ const dialog = await import('@tauri-apps/plugin-dialog');
146
+ await dialog.message(msg);
147
+ } catch {
148
+ alert(msg);
149
+ }
150
+ };
151
+ const confirm = async (msg) => {
152
+ if (!available) return window.confirm(msg);
153
+ try {
154
+ const dialog = await import('@tauri-apps/plugin-dialog');
155
+ return await dialog.confirm(msg);
156
+ } catch {
157
+ return window.confirm(msg);
158
+ }
159
+ };
160
+ return { selectFile, selectFolder, message, confirm, available };
161
+ }
162
+ function useClipboard() {
163
+ const available = isTauri();
164
+ const read = async () => {
165
+ if (!available) {
166
+ try {
167
+ return await navigator.clipboard.readText();
168
+ } catch {
169
+ return null;
170
+ }
171
+ }
172
+ try {
173
+ const { readText } = await import('@tauri-apps/plugin-clipboard-manager');
174
+ return await readText();
175
+ } catch {
176
+ return null;
177
+ }
178
+ };
179
+ const write = async (text) => {
180
+ if (!available) {
181
+ try {
182
+ await navigator.clipboard.writeText(text);
183
+ return true;
184
+ } catch {
185
+ return false;
186
+ }
187
+ }
188
+ try {
189
+ const { writeText } = await import('@tauri-apps/plugin-clipboard-manager');
190
+ await writeText(text);
191
+ return true;
192
+ } catch {
193
+ return false;
194
+ }
195
+ };
196
+ return { read, write, available };
197
+ }
198
+ function useShell() {
199
+ const available = isTauri();
200
+ const openUrl = async (url) => {
201
+ if (!available) {
202
+ window.open(url, "_blank");
203
+ return;
204
+ }
205
+ try {
206
+ const { open } = await import('@tauri-apps/plugin-shell');
207
+ await open(url);
208
+ } catch {
209
+ window.open(url, "_blank");
210
+ }
211
+ };
212
+ return { openUrl, available };
213
+ }
214
+
215
+ export { useClipboard, useDialog, useFileSystem, usePlatform, useShell, useWindow };
216
+ //# sourceMappingURL=index.js.map
217
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/index.ts","../../src/vue/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flightdev/desktop\r\n * \r\n * Desktop app support for Flight Framework via Tauri.\r\n * Build Windows, macOS, and Linux apps with the same codebase.\r\n * \r\n * Philosophy: Flight doesn't impose - install only the Tauri plugins you need.\r\n * All plugins are optional peer dependencies.\r\n * \r\n * @example\r\n * ```typescript\r\n * import { usePlatform, useWindow, useFileSystem } from '@flightdev/desktop/react';\r\n * \r\n * function App() {\r\n * const { isDesktop, isMac, isWindows } = usePlatform();\r\n * const { minimize, maximize, close } = useWindow();\r\n * const { readFile, writeFile, selectFile } = useFileSystem();\r\n * \r\n * return isDesktop ? <DesktopApp /> : <WebApp />;\r\n * }\r\n * ```\r\n */\r\n\r\n// =============================================================================\r\n// Types\r\n// =============================================================================\r\n\r\nexport type Platform = 'windows' | 'macos' | 'linux' | 'web';\r\n\r\nexport interface DesktopPlatformInfo {\r\n /** Current platform */\r\n platform: Platform;\r\n /** True if running as desktop app */\r\n isDesktop: boolean;\r\n /** True if running on Windows */\r\n isWindows: boolean;\r\n /** True if running on macOS */\r\n isMac: boolean;\r\n /** True if running on Linux */\r\n isLinux: boolean;\r\n /** True if running as web app */\r\n isWeb: boolean;\r\n /** True if Tauri is available */\r\n hasTauri: boolean;\r\n}\r\n\r\n// =============================================================================\r\n// Detection\r\n// =============================================================================\r\n\r\n/**\r\n * Check if Tauri is available.\r\n */\r\nfunction getTauri(): any {\r\n try {\r\n return (globalThis as any).__TAURI__;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Check if running in Tauri desktop environment.\r\n */\r\nexport function isTauri(): boolean {\r\n return getTauri() !== null;\r\n}\r\n\r\n/**\r\n * Get current desktop platform.\r\n */\r\nexport function getPlatform(): DesktopPlatformInfo {\r\n const tauri = getTauri();\r\n\r\n if (!tauri) {\r\n return {\r\n platform: 'web',\r\n isDesktop: false,\r\n isWindows: false,\r\n isMac: false,\r\n isLinux: false,\r\n isWeb: true,\r\n hasTauri: false,\r\n };\r\n }\r\n\r\n // Detect OS from navigator\r\n const userAgent = navigator.userAgent.toLowerCase();\r\n let platform: Platform = 'web';\r\n\r\n if (userAgent.includes('win')) {\r\n platform = 'windows';\r\n } else if (userAgent.includes('mac')) {\r\n platform = 'macos';\r\n } else if (userAgent.includes('linux')) {\r\n platform = 'linux';\r\n }\r\n\r\n return {\r\n platform,\r\n isDesktop: true,\r\n isWindows: platform === 'windows',\r\n isMac: platform === 'macos',\r\n isLinux: platform === 'linux',\r\n isWeb: false,\r\n hasTauri: true,\r\n };\r\n}\r\n\r\n/**\r\n * Check if a Tauri plugin is available.\r\n */\r\nexport function isPluginAvailable(pluginName: string): boolean {\r\n const tauri = getTauri();\r\n return tauri && typeof tauri[pluginName] !== 'undefined';\r\n}\r\n\r\n// =============================================================================\r\n// Re-exports\r\n// =============================================================================\r\n\r\nexport * from './config';\r\n","/**\r\n * Vue composables for @flightdev/desktop\r\n */\r\n\r\nimport { ref, onMounted, onUnmounted, type Ref } from 'vue';\r\nimport { getPlatform, isTauri, type DesktopPlatformInfo } from '../index';\r\n\r\n// =============================================================================\r\n// Platform Composable\r\n// =============================================================================\r\n\r\nexport function usePlatform(): DesktopPlatformInfo {\r\n return getPlatform();\r\n}\r\n\r\n// =============================================================================\r\n// Window Composable\r\n// =============================================================================\r\n\r\ninterface UseWindowReturn {\r\n minimize: () => Promise<void>;\r\n maximize: () => Promise<void>;\r\n close: () => Promise<void>;\r\n setTitle: (title: string) => Promise<void>;\r\n isMaximized: Ref<boolean>;\r\n available: boolean;\r\n}\r\n\r\nexport function useWindow(): UseWindowReturn {\r\n const isMaximized = ref(false);\r\n const available = isTauri();\r\n\r\n onMounted(async () => {\r\n if (!available) return;\r\n\r\n const { getCurrentWindow } = await import('@tauri-apps/api/window');\r\n isMaximized.value = await getCurrentWindow().isMaximized();\r\n });\r\n\r\n const minimize = async () => {\r\n if (!available) return;\r\n const { getCurrentWindow } = await import('@tauri-apps/api/window');\r\n await getCurrentWindow().minimize();\r\n };\r\n\r\n const maximize = async () => {\r\n if (!available) return;\r\n const { getCurrentWindow } = await import('@tauri-apps/api/window');\r\n await getCurrentWindow().toggleMaximize();\r\n isMaximized.value = await getCurrentWindow().isMaximized();\r\n };\r\n\r\n const close = async () => {\r\n if (!available) return;\r\n const { getCurrentWindow } = await import('@tauri-apps/api/window');\r\n await getCurrentWindow().close();\r\n };\r\n\r\n const setTitle = async (title: string) => {\r\n if (!available) {\r\n document.title = title;\r\n return;\r\n }\r\n const { getCurrentWindow } = await import('@tauri-apps/api/window');\r\n await getCurrentWindow().setTitle(title);\r\n };\r\n\r\n return { minimize, maximize, close, setTitle, isMaximized, available };\r\n}\r\n\r\n// =============================================================================\r\n// File System Composable\r\n// =============================================================================\r\n\r\ninterface UseFileSystemReturn {\r\n readFile: (path: string) => Promise<string | null>;\r\n writeFile: (path: string, content: string) => Promise<boolean>;\r\n exists: (path: string) => Promise<boolean>;\r\n available: boolean;\r\n}\r\n\r\nexport function useFileSystem(): UseFileSystemReturn {\r\n const available = isTauri();\r\n\r\n const readFile = async (path: string): Promise<string | null> => {\r\n if (!available) return null;\r\n try {\r\n const { readTextFile } = await import('@tauri-apps/plugin-fs');\r\n return await readTextFile(path);\r\n } catch {\r\n return null;\r\n }\r\n };\r\n\r\n const writeFile = async (path: string, content: string): Promise<boolean> => {\r\n if (!available) return false;\r\n try {\r\n const { writeTextFile } = await import('@tauri-apps/plugin-fs');\r\n await writeTextFile(path, content);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n const exists = async (path: string): Promise<boolean> => {\r\n if (!available) return false;\r\n try {\r\n const fs = await import('@tauri-apps/plugin-fs');\r\n return await fs.exists(path);\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n return { readFile, writeFile, exists, available };\r\n}\r\n\r\n// =============================================================================\r\n// Dialog Composable\r\n// =============================================================================\r\n\r\ninterface UseDialogReturn {\r\n selectFile: (options?: { multiple?: boolean }) => Promise<string | string[] | null>;\r\n selectFolder: () => Promise<string | null>;\r\n message: (msg: string) => Promise<void>;\r\n confirm: (msg: string) => Promise<boolean>;\r\n available: boolean;\r\n}\r\n\r\nexport function useDialog(): UseDialogReturn {\r\n const available = isTauri();\r\n\r\n const selectFile = async (options?: { multiple?: boolean }) => {\r\n if (!available) return null;\r\n try {\r\n const { open } = await import('@tauri-apps/plugin-dialog');\r\n return await open({ multiple: options?.multiple ?? false });\r\n } catch {\r\n return null;\r\n }\r\n };\r\n\r\n const selectFolder = async () => {\r\n if (!available) return null;\r\n try {\r\n const { open } = await import('@tauri-apps/plugin-dialog');\r\n return await open({ directory: true }) as string | null;\r\n } catch {\r\n return null;\r\n }\r\n };\r\n\r\n const message = async (msg: string) => {\r\n if (!available) {\r\n alert(msg);\r\n return;\r\n }\r\n try {\r\n const dialog = await import('@tauri-apps/plugin-dialog');\r\n await dialog.message(msg);\r\n } catch {\r\n alert(msg);\r\n }\r\n };\r\n\r\n const confirm = async (msg: string): Promise<boolean> => {\r\n if (!available) return window.confirm(msg);\r\n try {\r\n const dialog = await import('@tauri-apps/plugin-dialog');\r\n return await dialog.confirm(msg);\r\n } catch {\r\n return window.confirm(msg);\r\n }\r\n };\r\n\r\n return { selectFile, selectFolder, message, confirm, available };\r\n}\r\n\r\n// =============================================================================\r\n// Clipboard Composable\r\n// =============================================================================\r\n\r\ninterface UseClipboardReturn {\r\n read: () => Promise<string | null>;\r\n write: (text: string) => Promise<boolean>;\r\n available: boolean;\r\n}\r\n\r\nexport function useClipboard(): UseClipboardReturn {\r\n const available = isTauri();\r\n\r\n const read = async (): Promise<string | null> => {\r\n if (!available) {\r\n try { return await navigator.clipboard.readText(); } catch { return null; }\r\n }\r\n try {\r\n const { readText } = await import('@tauri-apps/plugin-clipboard-manager');\r\n return await readText();\r\n } catch {\r\n return null;\r\n }\r\n };\r\n\r\n const write = async (text: string): Promise<boolean> => {\r\n if (!available) {\r\n try { await navigator.clipboard.writeText(text); return true; } catch { return false; }\r\n }\r\n try {\r\n const { writeText } = await import('@tauri-apps/plugin-clipboard-manager');\r\n await writeText(text);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n return { read, write, available };\r\n}\r\n\r\n// =============================================================================\r\n// Shell Composable\r\n// =============================================================================\r\n\r\ninterface UseShellReturn {\r\n openUrl: (url: string) => Promise<void>;\r\n available: boolean;\r\n}\r\n\r\nexport function useShell(): UseShellReturn {\r\n const available = isTauri();\r\n\r\n const openUrl = async (url: string) => {\r\n if (!available) {\r\n window.open(url, '_blank');\r\n return;\r\n }\r\n try {\r\n const { open } = await import('@tauri-apps/plugin-shell');\r\n await open(url);\r\n } catch {\r\n window.open(url, '_blank');\r\n }\r\n };\r\n\r\n return { openUrl, available };\r\n}\r\n"]}
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@flightdev/desktop",
3
+ "version": "0.2.0",
4
+ "description": "Desktop app support for Flight Framework via Tauri - Windows, macOS, Linux",
5
+ "keywords": [
6
+ "flight",
7
+ "desktop",
8
+ "tauri",
9
+ "electron",
10
+ "windows",
11
+ "macos",
12
+ "linux"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "Flight Contributors",
16
+ "type": "module",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ },
22
+ "./react": {
23
+ "types": "./dist/react/index.d.ts",
24
+ "import": "./dist/react/index.js"
25
+ },
26
+ "./vue": {
27
+ "types": "./dist/vue/index.d.ts",
28
+ "import": "./dist/vue/index.js"
29
+ },
30
+ "./config": {
31
+ "types": "./dist/config.d.ts",
32
+ "import": "./dist/config.js"
33
+ }
34
+ },
35
+ "main": "./dist/index.js",
36
+ "types": "./dist/index.d.ts",
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "devDependencies": {
41
+ "@types/node": "^22.0.0",
42
+ "@types/react": "^19.0.0",
43
+ "react": "^19.0.0",
44
+ "rimraf": "^6.0.0",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^5.7.0",
47
+ "vitest": "^2.0.0",
48
+ "vue": "^3.5.0"
49
+ },
50
+ "peerDependencies": {
51
+ "@tauri-apps/api": "^2.0.0",
52
+ "@tauri-apps/plugin-dialog": "^2.0.0",
53
+ "@tauri-apps/plugin-fs": "^2.0.0",
54
+ "@tauri-apps/plugin-shell": "^2.0.0",
55
+ "@tauri-apps/plugin-clipboard-manager": "^2.0.0",
56
+ "react": "^18.0.0 || ^19.0.0",
57
+ "vue": "^3.0.0"
58
+ },
59
+ "peerDependenciesMeta": {
60
+ "@tauri-apps/api": {
61
+ "optional": true
62
+ },
63
+ "@tauri-apps/plugin-dialog": {
64
+ "optional": true
65
+ },
66
+ "@tauri-apps/plugin-fs": {
67
+ "optional": true
68
+ },
69
+ "@tauri-apps/plugin-shell": {
70
+ "optional": true
71
+ },
72
+ "@tauri-apps/plugin-clipboard-manager": {
73
+ "optional": true
74
+ },
75
+ "react": {
76
+ "optional": true
77
+ },
78
+ "vue": {
79
+ "optional": true
80
+ }
81
+ },
82
+ "scripts": {
83
+ "build": "tsup",
84
+ "dev": "tsup --watch",
85
+ "test": "vitest run",
86
+ "test:watch": "vitest",
87
+ "lint": "eslint src/",
88
+ "clean": "rimraf dist",
89
+ "typecheck": "tsc --noEmit"
90
+ }
91
+ }