@legendapp/spark 0.0.1-next.2 → 0.0.1-next.4
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/LICENSE +21 -0
- package/README.md +10 -4
- package/ai-codex.ts +1 -0
- package/ai.ts +1 -0
- package/app-documents.ts +1 -0
- package/camera.ts +13 -0
- package/config-plugin.d.cts +2 -0
- package/contracts.ts +2 -0
- package/diagnostics.ts +1 -0
- package/expo-config.d.cts +1 -0
- package/metro.cjs +4 -1
- package/metro.d.cts +12 -0
- package/native.cjs +3 -1
- package/native.d.cts +6 -0
- package/package.json +93 -15
- package/patches/camera/react-native-nitro-image.patch +320 -0
- package/patches/camera/react-native-nitro-modules.patch +50 -0
- package/patches/camera/react-native-vision-camera.patch +2662 -0
- package/patches/camera/upstream.json +22 -0
- package/patches/dependencies.json +8 -0
- package/patches/react-native-enriched-markdown@1.0.2.patch +8684 -0
- package/postinstall.cjs +1 -0
- package/schema.json +276 -58
- package/settings-observable.ts +1 -0
- package/settings-window.ts +1 -0
- package/shortcuts-commands.ts +1 -0
- package/shortcuts-keyboard.ts +3 -0
- package/ui-classnames.ts +1 -0
- package/ui-glass.ts +1 -0
- package/ui-search.ts +1 -0
- package/ui-sidebar.ts +1 -0
- package/ui-split-view.ts +1 -0
- package/ui-swipe.ts +1 -0
- package/ui-symbol.ts +1 -0
- package/vendor/node_modules/@legendapp/spark-ai/package.json +19 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/availability.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/index.ts +15 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/invocations.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/output.ts +62 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/run.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/types.ts +16 -0
- package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.h +2 -1
- package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.mm +126 -24
- package/vendor/node_modules/@legendapp/spark-audio/package.json +5 -2
- package/vendor/node_modules/@legendapp/spark-audio/src/NativeSparkAudio.ts +5 -1
- package/vendor/node_modules/@legendapp/spark-audio/src/desktop.ts +36 -32
- package/vendor/node_modules/@legendapp/spark-audio/src/events.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/hooks.ts +65 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/index.web.ts +92 -33
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session-unavailable.ts +6 -4
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session.ts +52 -19
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session.web.ts +18 -10
- package/vendor/node_modules/@legendapp/spark-audio/src/media-types.ts +40 -13
- package/vendor/node_modules/@legendapp/spark-audio/src/mobile.ts +40 -32
- package/vendor/node_modules/@legendapp/spark-audio/src/player.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/status-listeners.ts +21 -15
- package/vendor/node_modules/@legendapp/spark-audio/src/types.ts +9 -4
- package/vendor/node_modules/@legendapp/spark-audio/windows/SparkAudio/SparkAudio.h +67 -20
- package/vendor/node_modules/@legendapp/spark-auth-session/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-auth-session/src/core.ts +60 -42
- package/vendor/node_modules/@legendapp/spark-auth-session/src/index.ts +28 -12
- package/vendor/node_modules/@legendapp/spark-auth-session/src/mobile.ts +97 -41
- package/vendor/node_modules/@legendapp/spark-auth-session/src/types.ts +20 -9
- package/vendor/node_modules/@legendapp/spark-cli/dist/add-desktop.js +50 -7
- package/vendor/node_modules/@legendapp/spark-cli/dist/build-mode.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/build.js +145 -59
- package/vendor/node_modules/@legendapp/spark-cli/dist/cli-arguments.js +61 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/commands.js +10 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/create.js +37 -8
- package/vendor/node_modules/@legendapp/spark-cli/dist/credentials.js +86 -25
- package/vendor/node_modules/@legendapp/spark-cli/dist/dependency-pins.js +132 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/dev-command.js +13 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/dev.js +13 -10
- package/vendor/node_modules/@legendapp/spark-cli/dist/errors.js +100 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/examples.js +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-dev-patch.cjs +4 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-metro.cjs +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-native.cjs +5 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-node.js +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/dist/helpers.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/index.js +52 -44
- package/vendor/node_modules/@legendapp/spark-cli/dist/json.js +16 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/local.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/metro.cjs +26 -5
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-metadata.js +26 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-patch-preflight.js +86 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-preparation.js +88 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/notary-profiles.js +75 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/package.js +4 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/platform.js +16 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/process.js +7 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/project.js +90 -32
- package/vendor/node_modules/@legendapp/spark-cli/dist/release.js +86 -5
- package/vendor/node_modules/@legendapp/spark-cli/dist/release.json +23 -18
- package/vendor/node_modules/@legendapp/spark-cli/dist/runner-install.js +145 -31
- package/vendor/node_modules/@legendapp/spark-cli/dist/signing.js +4 -3
- package/vendor/node_modules/@legendapp/spark-cli/dist/universal.cjs +2 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/updates.js +41 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/windows.js +5 -9
- package/vendor/node_modules/@legendapp/spark-cli/package.json +7 -6
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/App.tsx +6 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/desktop.config.json +5 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/package.json +12 -10
- package/vendor/node_modules/@legendapp/spark-cli/templates/diff-lite/Git.macos.tsx +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.macos.tsx +23 -21
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.windows.tsx +23 -21
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.desktop.ts +11 -8
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.macos.ts +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/Lifecycle.desktop.tsx +8 -14
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/OpenFiles.desktop.tsx +5 -10
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.desktop.ts +11 -8
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.macos.ts +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/music-lite/assets.desktop.ts +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Activation.desktop.tsx +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Desktop.desktop.ts +37 -15
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/session.ts +5 -6
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/window-session.ts +5 -4
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/desktop.config.json +5 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/metro.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/package.json +14 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/react-native.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/templates/windows/package.json +14 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/windows/react-native.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-clipboard/macos/RNDesktopClipboard.mm +10 -16
- package/vendor/node_modules/@legendapp/spark-clipboard/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-clipboard/src/NativeDesktopClipboard.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-clipboard/src/desktop.ts +55 -31
- package/vendor/node_modules/@legendapp/spark-clipboard/src/expo.ts +21 -11
- package/vendor/node_modules/@legendapp/spark-clipboard/src/options.ts +8 -0
- package/vendor/node_modules/@legendapp/spark-clipboard/src/types.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.h +38 -15
- package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-codex/RNCodex.podspec +22 -0
- package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.hpp +23 -0
- package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.mm +1529 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitro.json +21 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/.gitattributes +1 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex+autolinking.rb +62 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.cpp +17 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.hpp +27 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Umbrella.hpp +38 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.mm +35 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.swift +16 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexAvailability.hpp +95 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexRunResult.hpp +99 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.cpp +24 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.hpp +71 -0
- package/vendor/node_modules/@legendapp/spark-codex/package.json +35 -0
- package/vendor/node_modules/@legendapp/spark-codex/react-native.config.js +11 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/Codex.nitro.ts +30 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/index.ts +65 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/native.ts +6 -0
- package/vendor/node_modules/@legendapp/spark-commands/package.json +21 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/bindings.ts +90 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/index.tsx +400 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/router.ts +138 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/storage.ts +20 -0
- package/vendor/node_modules/@legendapp/spark-context-menu/macos/RNContextMenu.mm +7 -8
- package/vendor/node_modules/@legendapp/spark-context-menu/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-context-menu/src/NativeContextMenu.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-context-menu/src/index.ts +26 -26
- package/vendor/node_modules/@legendapp/spark-context-menu/windows/SparkContextMenu/SparkContextMenu.h +3 -2
- package/vendor/node_modules/@legendapp/spark-desktop-app/RNDesktopApp.podspec +2 -1
- package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryJSI.hpp +89 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryWindows.hpp +22 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/RNDesktopApp.mm +13 -7
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkBinaryJSI.h +48 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.h +4 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.mm +33 -33
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktopError.h +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.h +26 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.mm +49 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.h +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.mm +70 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkWindow.mm +9 -6
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/recent-documents/RNRecentDocumentController.mm +55 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/package.json +5 -3
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/NativeDesktopApp.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/api.ts +86 -40
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/accelerator.ts +40 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/index.ts +56 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/menu.ts +116 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/native-buffer.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/path.ts +24 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/events.ts +75 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.ts +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.windows.ts +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/open-requests.ts +43 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/restoration.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/transport.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.cjs +10 -5
- package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.d.cts +3 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/autolinking.cjs +35 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/config.cjs +18 -3
- package/vendor/node_modules/@legendapp/spark-desktop-config/config.d.cts +89 -9
- package/vendor/node_modules/@legendapp/spark-desktop-config/expo.cjs +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/expo.d.cts +3 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/identity.cjs +3 -2
- package/vendor/node_modules/@legendapp/spark-desktop-config/lifecycle.cjs +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.cjs +106 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.d.cts +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/package.json +7 -5
- package/vendor/node_modules/@legendapp/spark-desktop-config/schema.json +276 -58
- package/vendor/node_modules/@legendapp/spark-desktop-config/updates.cjs +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/validation.cjs +35 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/windows.plugin.cjs +2 -1
- package/vendor/node_modules/@legendapp/spark-desktop-host/AppDelegate.mm +129 -11
- package/vendor/node_modules/@legendapp/spark-desktop-host/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-desktop-host/windows/application.inc +277 -121
- package/vendor/node_modules/@legendapp/spark-desktop-links/common/AuthLoopback.h +5 -7
- package/vendor/node_modules/@legendapp/spark-desktop-links/macos/RNDesktopLinks.mm +10 -9
- package/vendor/node_modules/@legendapp/spark-desktop-links/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/NativeDesktopLinks.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/api.ts +27 -33
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/expo.ts +3 -4
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/native.ts +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-links/windows/SparkLinks/SparkLinks.h +22 -22
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/RNDesktopShortcuts.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/RNDesktopShortcuts.mm +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.h +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.mm +307 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/package.json +8 -5
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/NativeDesktopShortcuts.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/api.ts +39 -14
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/NativeKeyboardManager.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/codes.ts +108 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/index.ts +99 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/RNDesktopWindows.podspec +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/RNDesktopWindows.mm +229 -103
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/SparkWindowGeometry.h +63 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.h +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.mm +27 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.h +12 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.mm +3169 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManagerStartup.mm +31 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/SidebarStartupFallbacks.mm +14 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/package.json +10 -6
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/NativeDesktopWindowManager.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/api.ts +146 -70
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/diagnostics.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.windows.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos-adapter.ts +53 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos.ts +51 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/transport.ts +41 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/types.ts +140 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/validation.ts +162 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/window-manager/NativeWindowManager.ts +28 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/WindowProvider.tsx +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/createWindowsNavigator.tsx +78 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/index.ts +6 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/types.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/usePrimaryWindowLifecycle.ts +18 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/useWindowFocusEffect.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-documents/package.json +22 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/controller.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/documentTransition.ts +13 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/hooks.ts +139 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/index.tsx +50 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/reload.ts +39 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/requests.ts +15 -0
- package/vendor/node_modules/@legendapp/spark-drag-drop/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/contracts.ts +73 -18
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/index.tsx +58 -15
- package/vendor/node_modules/@legendapp/spark-drag-drop/windows/SparkDragDrop/SparkDragDrop.h +14 -8
- package/vendor/node_modules/@legendapp/spark-file-dialog/ios/RNFileDialog.mm +34 -121
- package/vendor/node_modules/@legendapp/spark-file-dialog/package.json +12 -5
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/NativeFileDialog.ts +1 -5
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.ts +19 -84
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/native.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/options.ts +34 -14
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/types.ts +26 -0
- package/vendor/node_modules/@legendapp/spark-file-dialog/windows/SparkFileDialog/SparkFileDialog.h +42 -58
- package/vendor/node_modules/@legendapp/spark-file-system/RNDesktopFileSystem.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/RNDesktopFileSystem.mm +32 -21
- package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.h +24 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.mm +215 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.h +9 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.mm +82 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.h +47 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm +306 -0
- package/vendor/node_modules/@legendapp/spark-file-system/package.json +8 -6
- package/vendor/node_modules/@legendapp/spark-file-system/src/NativeDesktopFileSystem.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/index.ts +93 -0
- package/vendor/node_modules/@legendapp/spark-file-system/src/handles.ts +48 -14
- package/vendor/node_modules/@legendapp/spark-file-system/src/index.ts +134 -45
- package/vendor/node_modules/@legendapp/spark-file-system/src/path.ts +1 -9
- package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.h +102 -26
- package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/RNDesktopGlobalShortcuts.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/macos/RNDesktopGlobalShortcuts.mm +7 -4
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/NativeDesktopGlobalShortcuts.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/index.ts +39 -10
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/windows/SparkGlobalShortcuts/SparkGlobalShortcuts.h +5 -4
- package/vendor/node_modules/@legendapp/spark-message-dialog/macos/RNDesktopMessageDialog.mm +2 -2
- package/vendor/node_modules/@legendapp/spark-message-dialog/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-message-dialog/src/NativeDesktopMessageDialog.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-message-dialog/src/index.ts +48 -11
- package/vendor/node_modules/@legendapp/spark-native-menu/ios/RNNativeMenu.mm +141 -609
- package/vendor/node_modules/@legendapp/spark-native-menu/package.json +9 -4
- package/vendor/node_modules/@legendapp/spark-native-menu/src/NativeMenu.ts +2 -7
- package/vendor/node_modules/@legendapp/spark-native-menu/src/api.ts +76 -121
- package/vendor/node_modules/@legendapp/spark-native-menu/src/hooks.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-native-menu/src/windows-menus.ts +43 -37
- package/vendor/node_modules/@legendapp/spark-notifications/macos/RNDesktopNotifications.mm +75 -30
- package/vendor/node_modules/@legendapp/spark-notifications/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-notifications/src/NativeDesktopNotifications.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-notifications/src/index.ts +130 -42
- package/vendor/node_modules/@legendapp/spark-notifications/windows/SparkNotifications/SparkNotifications.h +51 -8
- package/vendor/node_modules/@legendapp/spark-processes/macos/RNDesktopProcesses.mm +94 -21
- package/vendor/node_modules/@legendapp/spark-processes/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-processes/src/NativeDesktopProcesses.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-processes/src/index.ts +124 -28
- package/vendor/node_modules/@legendapp/spark-processes/src/types.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.h +83 -34
- package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-secure-storage/macos/RNDesktopSecureStorage.mm +49 -40
- package/vendor/node_modules/@legendapp/spark-secure-storage/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/NativeDesktopSecureStorage.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/desktop.ts +16 -14
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/expo.ts +0 -1
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/options.ts +3 -2
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/unavailable.ts +6 -3
- package/vendor/node_modules/@legendapp/spark-settings/package.json +10 -3
- package/vendor/node_modules/@legendapp/spark-settings/src/fileStorage.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-settings/src/index.ts +7 -9
- package/vendor/node_modules/@legendapp/spark-settings/src/storage/index.ts +142 -0
- package/vendor/node_modules/@legendapp/spark-settings/src/store.ts +63 -21
- package/vendor/node_modules/@legendapp/spark-settings-ui/package.json +20 -0
- package/vendor/node_modules/@legendapp/spark-settings-ui/src/index.tsx +436 -0
- package/vendor/node_modules/@legendapp/spark-settings-ui/src/options.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-sqlite/package.json +3 -3
- package/vendor/node_modules/@legendapp/spark-sqlite/src/database.ts +182 -0
- package/vendor/node_modules/@legendapp/spark-sqlite/src/index.ts +19 -6
- package/vendor/node_modules/@legendapp/spark-sqlite/src/types.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-system/macos/RNDesktopSystem.mm +36 -11
- package/vendor/node_modules/@legendapp/spark-system/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-system/src/NativeDesktopSystem.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-system/src/index.ts +89 -32
- package/vendor/node_modules/@legendapp/spark-system/windows/SparkSystem/SparkSystem.h +8 -4
- package/vendor/node_modules/@legendapp/spark-tray/macos/RNDesktopTray.mm +20 -8
- package/vendor/node_modules/@legendapp/spark-tray/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-tray/src/NativeDesktopTray.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-tray/src/index.ts +91 -34
- package/vendor/node_modules/@legendapp/spark-tray/windows/SparkTray/SparkTray.h +45 -15
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkButton.mm +2 -1
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkTextInput.mm +10 -2
- package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.mm +1419 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/glass-effect-view/RNGlassEffectView.mm +72 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.mm +194 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.mm +180 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.mm +155 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.h +18 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.mm +645 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.h +10 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.mm +422 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.mm +164 -0
- package/vendor/node_modules/@legendapp/spark-ui/package.json +17 -4
- package/vendor/node_modules/@legendapp/spark-ui/src/SparkSelectNativeComponent.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/src/SparkTextInputNativeComponent.ts +6 -2
- package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/SidebarSplitViewNativeComponent.ts +37 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/index.tsx +86 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/availability.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/classnames/index.ts +8 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/control.ts +42 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/desktop.tsx +56 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/glass-effect-view/index.tsx +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/index.android.tsx +35 -21
- package/vendor/node_modules/@legendapp/spark-ui/src/index.ios.tsx +55 -26
- package/vendor/node_modules/@legendapp/spark-ui/src/index.tsx +1 -27
- package/vendor/node_modules/@legendapp/spark-ui/src/index.web.tsx +45 -14
- package/vendor/node_modules/@legendapp/spark-ui/src/index.windows.tsx +1 -42
- package/vendor/node_modules/@legendapp/spark-ui/src/mobile-input.tsx +11 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSegmentedControlNativeComponent.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSelectNativeComponent.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/select.ts +5 -3
- package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/SFSymbolNativeComponent.ts +13 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/index.tsx +27 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarItemNativeComponent.ts +25 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarNativeComponent.ts +24 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/index.tsx +104 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/specialized.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/SwipeActionsNativeComponent.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/index.tsx +41 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/TextInputSearchNativeComponent.ts +33 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/index.tsx +34 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/types.ts +30 -19
- package/vendor/node_modules/@legendapp/spark-ui/uniwind.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/uniwind.web.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/windows/SparkUI/SparkUI.h +16 -11
- package/vendor/node_modules/@legendapp/spark-updates/macos/RNDesktopUpdates.mm +21 -8
- package/vendor/node_modules/@legendapp/spark-updates/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-updates/src/NativeDesktopUpdates.ts +3 -2
- package/vendor/node_modules/@legendapp/spark-updates/src/index.ts +71 -15
- package/vendor/node_modules/@legendapp/spark-webview/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-webview/src/WebView.tsx +11 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/adapter.ts +55 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/index.ts +2 -2
- package/vendor/node_modules/@legendapp/spark-webview/src/types.ts +32 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/view-props.ts +28 -0
- package/vendor/node_modules/@legendapp/spark-window-options/index.cjs +51 -14
- package/vendor/node_modules/@legendapp/spark-window-options/index.d.ts +21 -8
- package/vendor/node_modules/@legendapp/spark-window-options/package.json +1 -1
- package/windows-macos.ts +1 -0
- package/expo-metro.cjs +0 -1
- package/message-dialog.ts +0 -1
- package/universal.cjs +0 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/accelerator.ts +0 -22
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows-options.ts +0 -11
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.windows.ts +0 -15
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/accelerator.ts +0 -22
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.h +0 -4
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.mm +0 -53
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createMenu, type Menu, type MenuAction, type MenuRootItem } from "@legendapp/spark-native-menu";
|
|
2
|
+
import { createPrimaryWindowLifecycle } from "@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle";
|
|
3
|
+
import { SparkError, asyncRegistration, type AsyncRegistration, type Subscription } from "@legendapp/spark-desktop-app/src/contracts";
|
|
4
|
+
import { subscribeToOpenRequests } from "./requests";
|
|
5
|
+
|
|
6
|
+
export interface DocumentAppController extends AsyncRegistration {
|
|
7
|
+
/** Resolves after document listeners and the menu are installed. Initial-open work reports through reportError. */
|
|
8
|
+
readonly ready: Promise<void>;
|
|
9
|
+
isDocumentWindowOpen(): boolean;
|
|
10
|
+
setDocumentWindowOpen(isOpen: boolean): void;
|
|
11
|
+
reportError(error: unknown): void;
|
|
12
|
+
subscribe(listener: () => void): Subscription;
|
|
13
|
+
updateMenus(menus: readonly MenuRootItem[]): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface DocumentAppControllerOptions {
|
|
16
|
+
onMenuAction?: (action: MenuAction, controller: DocumentAppController) => void | Promise<void>;
|
|
17
|
+
launchArguments?: string[];
|
|
18
|
+
menus: readonly MenuRootItem[];
|
|
19
|
+
onInitialOpen: (launchArguments: string[] | undefined, controller: DocumentAppController) => Promise<void> | void;
|
|
20
|
+
onOpenDocument?: (path: string, controller: DocumentAppController) => Promise<void> | void;
|
|
21
|
+
onReopenRequested?: (controller: DocumentAppController) => Promise<void> | void;
|
|
22
|
+
ownerId: string;
|
|
23
|
+
reportError: (error: unknown) => void;
|
|
24
|
+
windowId: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** An application-owned controller. Await ready; remove also works during setup or after setup fails. */
|
|
28
|
+
export function createDocumentAppController(options: DocumentAppControllerOptions): DocumentAppController {
|
|
29
|
+
const { ownerId, windowId, menus, onMenuAction, onInitialOpen, onOpenDocument, onReopenRequested, reportError } = options;
|
|
30
|
+
if (![ownerId, windowId].every(id => typeof id === "string" && /^[a-zA-Z0-9_-]{1,100}$/.test(id))) {
|
|
31
|
+
throw new SparkError("E_INVALID_ARGUMENT", "Expected document owner and window IDs");
|
|
32
|
+
}
|
|
33
|
+
const launchArguments = options.launchArguments?.slice();
|
|
34
|
+
let active = true, windowOpen = false, menu: Menu | undefined;
|
|
35
|
+
let requests: Subscription | undefined, lifecycle: Subscription | undefined;
|
|
36
|
+
const listeners = new Set<() => void>(), handled = new Set<string>();
|
|
37
|
+
const stop = () => { active = false; listeners.clear(); requests?.remove(); lifecycle?.remove(); };
|
|
38
|
+
const registration = asyncRegistration(stop, async () => {
|
|
39
|
+
await controller.ready.catch(() => {});
|
|
40
|
+
requests?.remove(); lifecycle?.remove();
|
|
41
|
+
await menu?.remove();
|
|
42
|
+
});
|
|
43
|
+
const controller: DocumentAppController = {
|
|
44
|
+
ready: Promise.resolve().then(async () => {
|
|
45
|
+
if (!active) return;
|
|
46
|
+
try {
|
|
47
|
+
if (onOpenDocument) requests = await subscribeToOpenRequests(event => {
|
|
48
|
+
if (!active || event.type !== "file" || handled.has(event.id)) return;
|
|
49
|
+
handled.add(event.id);
|
|
50
|
+
if (handled.size > 200) handled.delete(handled.values().next().value!);
|
|
51
|
+
void Promise.resolve().then(() => { if (active) return onOpenDocument(event.path, controller); }).catch(reportError);
|
|
52
|
+
});
|
|
53
|
+
if (!active) { requests?.remove(); return; }
|
|
54
|
+
menu = await createMenu({ id: ownerId, items: menus, onAction: action => {
|
|
55
|
+
if (active) {
|
|
56
|
+
try { void Promise.resolve(onMenuAction?.(action, controller)).catch(reportError); }
|
|
57
|
+
catch (error) { reportError(error); }
|
|
58
|
+
}
|
|
59
|
+
} });
|
|
60
|
+
if (!active) return;
|
|
61
|
+
lifecycle = createPrimaryWindowLifecycle({
|
|
62
|
+
windowId,
|
|
63
|
+
onInitialOpen: () => onInitialOpen(launchArguments, controller),
|
|
64
|
+
onReopenRequested: () => onReopenRequested ? onReopenRequested(controller) : onInitialOpen(undefined, controller),
|
|
65
|
+
onWindowClosed: () => controller.setDocumentWindowOpen(false),
|
|
66
|
+
onError: reportError,
|
|
67
|
+
});
|
|
68
|
+
} catch (error) {
|
|
69
|
+
stop();
|
|
70
|
+
try { await menu?.remove(); }
|
|
71
|
+
catch (cleanup) { throw new SparkError("E_NATIVE", "Document setup and cleanup failed; retry controller.remove()", { cause: new AggregateError([error, cleanup]) }); }
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}),
|
|
75
|
+
isDocumentWindowOpen: () => windowOpen,
|
|
76
|
+
setDocumentWindowOpen(isOpen) {
|
|
77
|
+
if (!active) throw new SparkError("E_CLOSED", "Document controller was removed");
|
|
78
|
+
if (typeof isOpen !== "boolean") throw new SparkError("E_INVALID_ARGUMENT", "Expected a boolean window state");
|
|
79
|
+
if (windowOpen !== isOpen) { windowOpen = isOpen; for (const listener of listeners) listener(); }
|
|
80
|
+
},
|
|
81
|
+
reportError,
|
|
82
|
+
subscribe(listener) {
|
|
83
|
+
if (!active) throw new SparkError("E_CLOSED", "Document controller was removed");
|
|
84
|
+
listeners.add(listener); return { remove() { listeners.delete(listener); } };
|
|
85
|
+
},
|
|
86
|
+
async updateMenus(items) {
|
|
87
|
+
if (!active) throw new SparkError("E_CLOSED", "Document controller was removed");
|
|
88
|
+
await controller.ready;
|
|
89
|
+
if (!active) throw new SparkError("E_CLOSED", "Document controller was removed");
|
|
90
|
+
await menu!.update({ items });
|
|
91
|
+
},
|
|
92
|
+
remove: registration.remove,
|
|
93
|
+
};
|
|
94
|
+
// Removal need not await readiness first; the original promise still rejects to awaiters.
|
|
95
|
+
void controller.ready.catch(() => {});
|
|
96
|
+
return controller;
|
|
97
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Serialize destructive document transitions without queuing stale user intent. */
|
|
2
|
+
export function createDocumentTransitionGuard() {
|
|
3
|
+
let pending = false;
|
|
4
|
+
return async (prepare: () => Promise<boolean>, transition: () => void | Promise<void>) => {
|
|
5
|
+
if (pending) return false;
|
|
6
|
+
pending = true;
|
|
7
|
+
try {
|
|
8
|
+
if (!await prepare()) return false;
|
|
9
|
+
await transition();
|
|
10
|
+
return true;
|
|
11
|
+
} finally { pending = false; }
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
import type { AsyncRegistration, Subscription } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
import { createDocumentAppController, type DocumentAppController, type DocumentAppControllerOptions } from "./controller";
|
|
4
|
+
import { watchDocumentReload, type DocumentReloadOptions } from "./reload";
|
|
5
|
+
|
|
6
|
+
export interface UseWatchedDocumentReloadOptions extends Omit<DocumentReloadOptions, "path"> {
|
|
7
|
+
path: string | null | undefined;
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
onCleanupError?: (error: unknown, registration: AsyncRegistration) => void;
|
|
10
|
+
}
|
|
11
|
+
type ReloadOwner = { registration: AsyncRegistration; removing?: Promise<void> };
|
|
12
|
+
type ReloadLifecycle = { tail: Promise<void>; owner?: ReloadOwner };
|
|
13
|
+
export function useWatchedDocumentReload(options: UseWatchedDocumentReloadOptions): void {
|
|
14
|
+
const latest = useRef(options);
|
|
15
|
+
const lifecycleRef = useRef<ReloadLifecycle | null>(null);
|
|
16
|
+
if (!lifecycleRef.current) lifecycleRef.current = { tail: Promise.resolve() };
|
|
17
|
+
const lifecycle = lifecycleRef.current;
|
|
18
|
+
useLayoutEffect(() => { latest.current = options; });
|
|
19
|
+
const { path, enabled = true, delayMs } = options;
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!enabled || !path) return;
|
|
22
|
+
let active = true, owned: ReloadOwner | undefined;
|
|
23
|
+
const report = (error: unknown) => {
|
|
24
|
+
try { latest.current.onError(error); }
|
|
25
|
+
catch (callbackError) { console.error(callbackError); }
|
|
26
|
+
};
|
|
27
|
+
const remove = (owner: ReloadOwner) => {
|
|
28
|
+
if (!owner.removing) owner.removing = owner.registration.remove().then(() => {
|
|
29
|
+
if (lifecycle.owner === owner) lifecycle.owner = undefined;
|
|
30
|
+
}).catch(error => {
|
|
31
|
+
try {
|
|
32
|
+
if (latest.current.onCleanupError) latest.current.onCleanupError(error, owner.registration);
|
|
33
|
+
else {
|
|
34
|
+
console.error("Document reload watch cleanup failed; registration remains retryable", error, owner.registration);
|
|
35
|
+
report(error);
|
|
36
|
+
}
|
|
37
|
+
} catch (callbackError) { console.error(callbackError); }
|
|
38
|
+
throw error;
|
|
39
|
+
}).finally(() => { owner.removing = undefined; });
|
|
40
|
+
return owner.removing;
|
|
41
|
+
};
|
|
42
|
+
const creation = lifecycle.tail.then(async () => {
|
|
43
|
+
if (!active) return;
|
|
44
|
+
try {
|
|
45
|
+
if (lifecycle.owner) await remove(lifecycle.owner);
|
|
46
|
+
} catch { return; }
|
|
47
|
+
if (!active) return;
|
|
48
|
+
try {
|
|
49
|
+
const registration = await watchDocumentReload({
|
|
50
|
+
path, delayMs,
|
|
51
|
+
onReload: () => { if (active) return latest.current.onReload(); },
|
|
52
|
+
shouldReload: () => active && (latest.current.shouldReload?.() ?? true),
|
|
53
|
+
onError: error => { if (active) report(error); },
|
|
54
|
+
});
|
|
55
|
+
owned = { registration };
|
|
56
|
+
lifecycle.owner = owned;
|
|
57
|
+
} catch (error) { if (active) report(error); }
|
|
58
|
+
});
|
|
59
|
+
lifecycle.tail = creation;
|
|
60
|
+
return () => {
|
|
61
|
+
active = false;
|
|
62
|
+
const cleanup = creation.then(async () => { if (owned) await remove(owned).catch(() => {}); });
|
|
63
|
+
lifecycle.tail = cleanup;
|
|
64
|
+
};
|
|
65
|
+
}, [path, enabled, delayMs]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface UseDocumentAppControllerOptions extends DocumentAppControllerOptions {
|
|
69
|
+
onCleanupError?: (error: unknown, controller: DocumentAppController) => void;
|
|
70
|
+
}
|
|
71
|
+
export type DocumentAppControllerState =
|
|
72
|
+
| { status: "loading" }
|
|
73
|
+
| { status: "ready"; controller: DocumentAppController }
|
|
74
|
+
| { status: "error"; error: unknown };
|
|
75
|
+
|
|
76
|
+
/** Component-owned convenience. Use the factory for an application-owned lifetime. */
|
|
77
|
+
export function useDocumentAppController(options: UseDocumentAppControllerOptions): DocumentAppControllerState {
|
|
78
|
+
const latest = useRef(options);
|
|
79
|
+
useLayoutEffect(() => { latest.current = options; });
|
|
80
|
+
const [state, setState] = useState<DocumentAppControllerState>({ status: "loading" });
|
|
81
|
+
const current = useRef<{ controller?: DocumentAppController; items: DocumentAppControllerOptions["menus"]; active: boolean; ready: boolean } | undefined>(undefined);
|
|
82
|
+
const cleanup = useRef<{ promise: Promise<void>; controller?: DocumentAppController }>({ promise: Promise.resolve() });
|
|
83
|
+
const handlesDocuments = !!options.onOpenDocument;
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const owner: NonNullable<typeof current.current> = { items: options.menus, active: true, ready: false };
|
|
86
|
+
current.current = owner;
|
|
87
|
+
let subscription: Subscription | undefined;
|
|
88
|
+
setState({ status: "loading" });
|
|
89
|
+
const report = (error: unknown) => { if (owner.active) setState({ status: "error", error }); latest.current.reportError(error); };
|
|
90
|
+
const previous = cleanup.current;
|
|
91
|
+
const setup = previous.promise.catch(() => previous.controller?.remove()).then(async () => {
|
|
92
|
+
if (!owner.active) return;
|
|
93
|
+
const initialItems = owner.items;
|
|
94
|
+
const controller = createDocumentAppController({
|
|
95
|
+
ownerId: options.ownerId, windowId: options.windowId, menus: initialItems,
|
|
96
|
+
launchArguments: options.launchArguments,
|
|
97
|
+
onMenuAction: (action, value) => { if (owner.active) return latest.current.onMenuAction?.(action, value); },
|
|
98
|
+
onInitialOpen: (args, value) => { if (owner.active) return latest.current.onInitialOpen(args, value); },
|
|
99
|
+
onOpenDocument: handlesDocuments ? (path, value) => { if (owner.active) return latest.current.onOpenDocument?.(path, value); } : undefined,
|
|
100
|
+
onReopenRequested: value => {
|
|
101
|
+
if (owner.active) return latest.current.onReopenRequested ? latest.current.onReopenRequested(value) : latest.current.onInitialOpen(undefined, value);
|
|
102
|
+
},
|
|
103
|
+
reportError: error => latest.current.reportError(error),
|
|
104
|
+
});
|
|
105
|
+
owner.controller = controller;
|
|
106
|
+
await controller.ready;
|
|
107
|
+
if (owner.active) {
|
|
108
|
+
owner.ready = true;
|
|
109
|
+
if (owner.items !== initialItems) await controller.updateMenus(owner.items).catch(error => latest.current.reportError(error));
|
|
110
|
+
if (!owner.active) return;
|
|
111
|
+
subscription = controller.subscribe(() => setState({ status: "ready", controller }));
|
|
112
|
+
setState({ status: "ready", controller });
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
void setup.catch(report);
|
|
116
|
+
return () => {
|
|
117
|
+
owner.active = false; subscription?.remove();
|
|
118
|
+
// Stop callbacks immediately, even if setup is waiting on a native registration.
|
|
119
|
+
if (owner.controller) {
|
|
120
|
+
const controller = owner.controller;
|
|
121
|
+
const promise = controller.remove();
|
|
122
|
+
cleanup.current = { promise, controller };
|
|
123
|
+
void promise.catch(error => {
|
|
124
|
+
if (latest.current.onCleanupError) latest.current.onCleanupError(error, controller);
|
|
125
|
+
else latest.current.reportError(error);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}, [options.ownerId, options.windowId, handlesDocuments]);
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const owner = current.current;
|
|
132
|
+
if (!owner?.active || owner.items === options.menus) return;
|
|
133
|
+
owner.items = options.menus;
|
|
134
|
+
if (owner.ready && owner.controller) void owner.controller.updateMenus(options.menus).catch(error => {
|
|
135
|
+
if (owner.active) latest.current.reportError(error);
|
|
136
|
+
});
|
|
137
|
+
}, [options.menus]);
|
|
138
|
+
return state;
|
|
139
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { openFileDialog } from "@legendapp/spark-file-dialog";
|
|
2
|
+
export type { AsyncRegistration, Subscription } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
export * from "./requests";
|
|
4
|
+
export { createDocumentTransitionGuard } from "./documentTransition";
|
|
5
|
+
export * from "./controller";
|
|
6
|
+
export * from "./reload";
|
|
7
|
+
export * from "./hooks";
|
|
8
|
+
|
|
9
|
+
export interface OpenSelectedDocumentPathOptions {
|
|
10
|
+
allowedFileTypes: readonly string[];
|
|
11
|
+
invalidSelectionMessage?: string;
|
|
12
|
+
isDocumentPath: (path: string) => boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface GetLaunchDocumentPathOptions {
|
|
15
|
+
isDocumentPath: (path: string) => boolean;
|
|
16
|
+
launchArguments?: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getLaunchDocumentPath({
|
|
20
|
+
isDocumentPath,
|
|
21
|
+
launchArguments,
|
|
22
|
+
}: GetLaunchDocumentPathOptions) {
|
|
23
|
+
const argv = typeof process !== "undefined" && Array.isArray(process.argv) ? process.argv : [];
|
|
24
|
+
return launchArguments?.find(isDocumentPath) ?? argv.find(isDocumentPath) ?? null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function openSelectedDocumentPath({
|
|
28
|
+
allowedFileTypes,
|
|
29
|
+
invalidSelectionMessage,
|
|
30
|
+
isDocumentPath,
|
|
31
|
+
}: OpenSelectedDocumentPathOptions) {
|
|
32
|
+
const result = await openFileDialog({
|
|
33
|
+
filters: [{ extensions: allowedFileTypes }],
|
|
34
|
+
selection: "files",
|
|
35
|
+
});
|
|
36
|
+
const paths = result.canceled ? [] : result.paths;
|
|
37
|
+
const path = paths.find(isDocumentPath) ?? null;
|
|
38
|
+
|
|
39
|
+
if (path) {
|
|
40
|
+
return path;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (paths && paths.length > 0) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
invalidSelectionMessage ?? `Choose a supported file (${allowedFileTypes.map((type) => `.${type}`).join(", ")}).`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { watch } from "@legendapp/spark-file-system";
|
|
2
|
+
import { SparkError, asyncRegistration, type AsyncRegistration } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
|
|
4
|
+
export interface DocumentReloadOptions {
|
|
5
|
+
path: string;
|
|
6
|
+
delayMs?: number;
|
|
7
|
+
onReload: () => void | Promise<void>;
|
|
8
|
+
onError: (error: unknown) => void;
|
|
9
|
+
shouldReload?: () => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Debounces file invalidations. Removal stops queued reloads and awaits any running reload. */
|
|
13
|
+
export async function watchDocumentReload(options: DocumentReloadOptions): Promise<AsyncRegistration> {
|
|
14
|
+
const { path, delayMs = 100, onReload, onError, shouldReload } = options;
|
|
15
|
+
if (!Number.isFinite(delayMs) || delayMs < 0 || delayMs > 2147483647) {
|
|
16
|
+
throw new SparkError("E_INVALID_ARGUMENT", "Expected a nonnegative timer delay");
|
|
17
|
+
}
|
|
18
|
+
let active = true, ready = false, invalidated = false, timeout: ReturnType<typeof setTimeout> | undefined;
|
|
19
|
+
let pending = Promise.resolve();
|
|
20
|
+
const invalidate = () => {
|
|
21
|
+
if (!active) return;
|
|
22
|
+
if (!ready) { invalidated = true; return; }
|
|
23
|
+
clearTimeout(timeout);
|
|
24
|
+
timeout = setTimeout(() => {
|
|
25
|
+
pending = pending.then(async () => {
|
|
26
|
+
if (active && (!shouldReload || shouldReload())) await onReload();
|
|
27
|
+
}).catch(onError);
|
|
28
|
+
}, delayMs);
|
|
29
|
+
};
|
|
30
|
+
// Native backends can report an invalidation before registration is acknowledged.
|
|
31
|
+
// Do not run application work until creation succeeds.
|
|
32
|
+
const subscription = await watch(path, invalidate);
|
|
33
|
+
ready = true;
|
|
34
|
+
if (invalidated) invalidate();
|
|
35
|
+
return asyncRegistration(() => { active = false; clearTimeout(timeout); }, async () => {
|
|
36
|
+
await subscription.remove();
|
|
37
|
+
await pending;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import { callLinks, linksCommand } from "@legendapp/spark-desktop-links/src/native";
|
|
3
|
+
import { nativePath } from "@legendapp/spark-desktop-app/src/contracts/path";
|
|
4
|
+
import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
|
|
5
|
+
export { subscribeToOpenRequests, type OpenRequest } from "@legendapp/spark-desktop-app/src/open-requests";
|
|
6
|
+
export interface RecentDocument { path: string; name: string }
|
|
7
|
+
export async function noteRecentDocument(path: string): Promise<void> { await linksCommand("noteRecent", { path: nativePath(path, Platform.OS) }); }
|
|
8
|
+
export function clearRecentDocuments(): Promise<void> { return linksCommand("clearRecent"); }
|
|
9
|
+
export async function getRecentDocuments(): Promise<RecentDocument[]> {
|
|
10
|
+
const paths = await callLinks("recent", {}, (value): value is string[] => Array.isArray(value) && value.every(item => typeof item === "string"));
|
|
11
|
+
return paths.map(value => {
|
|
12
|
+
try { const path = nativePath(value, Platform.OS); return { path, name: (Platform.OS === "windows" ? path.replaceAll("\\", "/") : path).split("/").filter(Boolean).at(-1) ?? path }; }
|
|
13
|
+
catch (cause) { throw new SparkError("E_INVALID_DATA", "Recent document contains an invalid path", { cause }); }
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@legendapp/spark-drag-drop",
|
|
3
|
-
"version": "0.0.1-next.
|
|
3
|
+
"version": "0.0.1-next.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "src/index.tsx",
|
|
6
6
|
"react-native": "src/index.tsx",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"ios": {
|
|
23
23
|
"componentProvider": {
|
|
24
24
|
"DesktopDragView": "RNDesktopDragView"
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
"modulesProvider": {}
|
|
26
27
|
}
|
|
27
28
|
},
|
|
28
29
|
"spark": {
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
]
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
|
-
"@legendapp/spark-desktop-app": "0.0.1-next.
|
|
42
|
+
"@legendapp/spark-desktop-app": "0.0.1-next.4"
|
|
42
43
|
},
|
|
43
44
|
"private": true
|
|
44
45
|
}
|
package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface NativeProps extends ViewProps {
|
|
|
6
6
|
sourceJson?: string;
|
|
7
7
|
optionsJson?: string;
|
|
8
8
|
disabled?: WithDefault<boolean, false>;
|
|
9
|
-
|
|
9
|
+
onError?: DirectEventHandler<Payload>;
|
|
10
10
|
onDrop?: DirectEventHandler<Payload>;
|
|
11
11
|
onDragEnter?: DirectEventHandler<Payload>;
|
|
12
12
|
onDragOver?: DirectEventHandler<Payload>;
|
|
@@ -1,28 +1,83 @@
|
|
|
1
|
+
import { SparkError, parseNativeResult } from "@legendapp/spark-desktop-app/src/contracts";
|
|
2
|
+
import { nativePath } from "@legendapp/spark-desktop-app/src/contracts/path";
|
|
1
3
|
export type DragOperation = "copy" | "move" | "link";
|
|
2
|
-
/** Custom
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/** Custom values are UTF-8 strings keyed by MIME type. JSON schemas belong to the app. */
|
|
5
|
+
export interface DragPayload { files?: readonly string[]; text?: string; urls?: readonly string[]; data?: Readonly<Record<string, string>> }
|
|
6
|
+
/** Logical coordinates from the target's top-left corner, positive downward. */
|
|
7
|
+
export interface DragOverEvent { x: number; y: number; operation: DragOperation }
|
|
8
|
+
export interface DropEvent extends DragPayload, DragOverEvent {}
|
|
9
|
+
export type DragEndEvent = { accepted: true; operation: DragOperation } | { accepted: false; operation: "none" };
|
|
10
|
+
export interface DragOptions {
|
|
11
|
+
sourceOperations?: readonly DragOperation[];
|
|
12
|
+
acceptedOperations?: readonly DragOperation[];
|
|
9
13
|
/** Built-ins: files, text, urls. Custom types use MIME names. Default: built-ins. */
|
|
10
|
-
acceptedTypes?: string[];
|
|
11
|
-
}
|
|
14
|
+
acceptedTypes?: readonly string[];
|
|
15
|
+
}
|
|
12
16
|
const operations = ["copy", "move", "link"];
|
|
13
17
|
const builtins = ["files", "text", "urls"];
|
|
14
18
|
const customType = (type: string) => /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/.test(type) && !["application/x-spark-drag", "text/plain", "text/uri-list"].includes(type);
|
|
15
|
-
|
|
19
|
+
const record = (value: unknown): value is Record<string, unknown> => !!value && typeof value === "object" && !Array.isArray(value);
|
|
20
|
+
const strings = (value: unknown): value is string[] => Array.isArray(value) && Array.from(value).every(item => typeof item === "string");
|
|
21
|
+
const url = (value: string) => /^[a-z][a-z0-9+.-]*:\S+$/i.test(value) && !/[\u0000-\u0020\u007f]/.test(value);
|
|
22
|
+
function invalid(message: string): never { throw new SparkError("E_INVALID_ARGUMENT", message); }
|
|
23
|
+
/** Snapshot and normalize file URLs before passing the source to native. */
|
|
24
|
+
export function dragSource(source: DragPayload | undefined, platform: string, incoming = false): DragPayload | undefined {
|
|
25
|
+
if (source === undefined) return undefined;
|
|
26
|
+
if (!record(source)) invalid("Expected a drag payload");
|
|
27
|
+
for (const key of Object.keys(source)) if (![...builtins, "data"].includes(key)) throw new SparkError("E_UNSUPPORTED_OPTION", `Unknown drag payload field: ${key}`);
|
|
28
|
+
const result: DragPayload = {};
|
|
29
|
+
if (source.files !== undefined) {
|
|
30
|
+
if (!strings(source.files)) invalid("Drag files must be an array of absolute paths or file URLs");
|
|
31
|
+
result.files = source.files.map(file => nativePath(file, platform));
|
|
32
|
+
}
|
|
33
|
+
if (source.text !== undefined) {
|
|
34
|
+
if (typeof source.text !== "string") invalid("Drag text must be a string");
|
|
35
|
+
result.text = source.text;
|
|
36
|
+
}
|
|
37
|
+
if (source.urls !== undefined) {
|
|
38
|
+
if (!strings(source.urls) || !source.urls.every(url)) invalid("Drag URLs must be absolute URLs without whitespace");
|
|
39
|
+
if (!incoming && platform === "windows" && source.urls.length > 1) throw new SparkError("E_UNSUPPORTED_OPTION", "Windows supports one URL per drag source");
|
|
40
|
+
result.urls = [...source.urls];
|
|
41
|
+
}
|
|
42
|
+
if (source.data !== undefined) {
|
|
43
|
+
if (!record(source.data) || Object.entries(source.data).some(([type, value]) => !customType(type) || typeof value !== "string")) invalid("Custom drag data must map MIME types to strings");
|
|
44
|
+
result.data = { ...source.data } as Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
if (!incoming && !result.files?.length && result.text === undefined && !result.urls?.length && !Object.keys(result.data ?? {}).length) invalid("Drag source must contain at least one representation");
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
export function dragConfiguration(source: DragPayload | undefined, options: DragOptions, platform: string): string {
|
|
50
|
+
dragSource(source, platform);
|
|
51
|
+
return dragOptions(options);
|
|
52
|
+
}
|
|
53
|
+
export function dragOptions(options: DragOptions): string {
|
|
54
|
+
if (!record(options)) invalid("Expected drag options");
|
|
55
|
+
for (const key of Object.keys(options)) if (!["sourceOperations", "acceptedOperations", "acceptedTypes"].includes(key)) throw new SparkError("E_UNSUPPORTED_OPTION", `Unknown drag option: ${key}`);
|
|
16
56
|
for (const values of [options.sourceOperations, options.acceptedOperations]) {
|
|
17
|
-
if (values !== undefined && (!
|
|
57
|
+
if (values !== undefined && (!strings(values) || values.some(value => !operations.includes(value)) || new Set(values).size !== values.length)) invalid("Drag operations must be unique copy, move or link values");
|
|
18
58
|
}
|
|
19
59
|
const types = options.acceptedTypes ?? builtins;
|
|
20
|
-
if (!
|
|
21
|
-
if (source) {
|
|
22
|
-
if (source.files?.some(file => typeof file !== "string" || (platform === "windows" ? !/^(?:[a-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+)/i.test(file) : !file.startsWith("/")))) throw new Error("Drag source files must use absolute paths");
|
|
23
|
-
if (source.text !== undefined && typeof source.text !== "string") throw new Error("Drag text must be a string");
|
|
24
|
-
if (source.urls?.some(url => typeof url !== "string" || !/^[a-z][a-z0-9+.-]*:/i.test(url))) throw new Error("Drag URLs must be absolute URLs");
|
|
25
|
-
if (source.data && (typeof source.data !== "object" || Array.isArray(source.data) || Object.entries(source.data).some(([type, value]) => !customType(type) || typeof value !== "string"))) throw new Error("Custom drag data must map MIME types to strings");
|
|
26
|
-
}
|
|
60
|
+
if (!strings(types) || new Set(types).size !== types.length || types.some(type => !builtins.includes(type) && !customType(type))) invalid("Invalid or duplicate accepted drag type");
|
|
27
61
|
return JSON.stringify({ sourceOperations: options.sourceOperations ?? ["copy"], acceptedOperations: options.acceptedOperations ?? ["copy"], acceptedTypes: types });
|
|
28
62
|
}
|
|
63
|
+
function position(value: unknown): value is DragOverEvent {
|
|
64
|
+
return record(value) && typeof value.x === "number" && Number.isFinite(value.x) && typeof value.y === "number" && Number.isFinite(value.y) && operations.includes(value.operation as string);
|
|
65
|
+
}
|
|
66
|
+
export function dragPosition(json: string): DragOverEvent {
|
|
67
|
+
const { x, y, operation } = parseNativeResult(json, position); return { x, y, operation };
|
|
68
|
+
}
|
|
69
|
+
export function dragEnd(json: string): DragEndEvent {
|
|
70
|
+
const value = parseNativeResult(json, (value): value is DragEndEvent => record(value) && (value.accepted === true ? operations.includes(value.operation as string) : value.accepted === false && value.operation === "none"));
|
|
71
|
+
return { accepted: value.accepted, operation: value.operation } as DragEndEvent;
|
|
72
|
+
}
|
|
73
|
+
export function dragDrop(json: string, platform: string): DropEvent {
|
|
74
|
+
const value = parseNativeResult(json, (value): value is DropEvent => position(value) && record(value));
|
|
75
|
+
// Native drops may contain no text/custom representation, unlike a requested source.
|
|
76
|
+
const { x, y, operation } = value;
|
|
77
|
+
const payload: DragPayload = {};
|
|
78
|
+
for (const key of [...builtins, "data"] as const) if (Object.hasOwn(value, key)) (payload as Record<string, unknown>)[key] = (value as unknown as Record<string, unknown>)[key];
|
|
79
|
+
try {
|
|
80
|
+
const normalized = dragSource(payload, platform, true);
|
|
81
|
+
return { ...normalized, x, y, operation };
|
|
82
|
+
} catch (cause) { throw new SparkError("E_INVALID_DATA", "Invalid native drag payload", { cause }); }
|
|
83
|
+
}
|
|
@@ -1,17 +1,60 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import { Platform,
|
|
1
|
+
import React, { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
import { Platform, UIManager, View, type NativeSyntheticEvent, type ViewProps } from "react-native";
|
|
3
3
|
import NativeView from "./DesktopDragViewNativeComponent";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export type
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
4
|
+
import { SparkError, parseNativeResult, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
|
|
5
|
+
import { dragOptions, dragSource, dragDrop, dragEnd, dragPosition, type DragPayload, type DragOptions, type DragOverEvent, type DropEvent, type DragEndEvent } from "./contracts";
|
|
6
|
+
export type { DragPayload, DragOptions, DragOperation, DragOverEvent, DropEvent, DragEndEvent } from "./contracts";
|
|
7
|
+
export interface DragDropViewProps extends ViewProps, DragOptions {
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
source?: DragPayload;
|
|
10
|
+
onDrop?: (event: DropEvent) => void;
|
|
11
|
+
onDragEnter?: (event: DropEvent) => void;
|
|
12
|
+
onDragOver?: (event: DragOverEvent) => void;
|
|
13
|
+
onDragLeave?: () => void;
|
|
14
|
+
onDragEnd?: (event: DragEndEvent) => void;
|
|
15
|
+
onError?: (error: SparkError) => void;
|
|
16
|
+
}
|
|
17
|
+
export function getDragDropAvailability(): Availability {
|
|
18
|
+
if (Platform.OS !== "macos" && Platform.OS !== "windows") return { available: false, reason: "unsupported-platform" };
|
|
19
|
+
return UIManager.hasViewManagerConfig("DesktopDragView") ? { available: true } : { available: false, reason: "missing-module" };
|
|
20
|
+
}
|
|
21
|
+
type Event = NativeSyntheticEvent<{ json: string }>;
|
|
22
|
+
export function DragDropView({ source, sourceOperations, acceptedOperations, acceptedTypes, disabled = false, onDrop, onDragEnter, onDragOver, onDragLeave, onDragEnd, onError = console.error, ...props }: DragDropViewProps) {
|
|
23
|
+
const optionsJson = dragOptions({ sourceOperations, acceptedOperations, acceptedTypes });
|
|
24
|
+
const sourceJson = source === undefined ? "" : JSON.stringify(dragSource(source, Platform.OS));
|
|
25
|
+
if (typeof disabled !== "boolean") throw new SparkError("E_INVALID_ARGUMENT", "Expected disabled to be a boolean");
|
|
26
|
+
for (const handler of [onDrop, onDragEnter, onDragOver, onDragLeave, onDragEnd, onError]) if (handler !== undefined && typeof handler !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected a drag event callback");
|
|
27
|
+
const availability = getDragDropAvailability();
|
|
28
|
+
const [failed, setFailed] = useState(false);
|
|
29
|
+
const mounted = useRef(false), reported = useRef<string | undefined>(undefined);
|
|
30
|
+
useLayoutEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
|
|
31
|
+
const unavailable = !availability.available ? availability.reason : undefined;
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (unavailable && reported.current !== unavailable) {
|
|
34
|
+
reported.current = unavailable;
|
|
35
|
+
onError(new SparkError(unavailable === "unsupported-platform" ? "E_UNSUPPORTED_PLATFORM" : "E_MODULE_UNAVAILABLE", "Drag and drop is unavailable"));
|
|
36
|
+
}
|
|
37
|
+
}, [unavailable, onError]);
|
|
38
|
+
function receive<T>(event: Event, parse: (json: string) => T, handler?: (value: T) => void) {
|
|
39
|
+
if (!mounted.current || disabled || failed) return;
|
|
40
|
+
let value: T;
|
|
41
|
+
try { value = parse(event?.nativeEvent?.json); }
|
|
42
|
+
catch (cause) { onError(cause instanceof SparkError ? cause : new SparkError("E_INVALID_DATA", "Invalid native drag event", { cause })); return; }
|
|
43
|
+
handler?.(value);
|
|
44
|
+
}
|
|
45
|
+
function error(event: Event) {
|
|
46
|
+
if (!mounted.current || failed) return;
|
|
47
|
+
let value: { message: string; unavailable: boolean };
|
|
48
|
+
try { value = parseNativeResult(event?.nativeEvent?.json, (value): value is { message: string; unavailable: boolean } => !!value && typeof value === "object" && "message" in value && typeof value.message === "string" && "unavailable" in value && typeof value.unavailable === "boolean"); }
|
|
49
|
+
catch (cause) { onError(cause as SparkError); return; }
|
|
50
|
+
if (value.unavailable) setFailed(true);
|
|
51
|
+
onError(new SparkError(value.unavailable ? "E_UNAVAILABLE" : "E_NATIVE", value.message));
|
|
52
|
+
}
|
|
53
|
+
if (!availability.available || failed) return <View {...props} />;
|
|
54
|
+
return <NativeView {...props} disabled={disabled} sourceJson={sourceJson} optionsJson={optionsJson} onError={error}
|
|
55
|
+
onDrop={event => receive(event, json => dragDrop(json, Platform.OS), onDrop)}
|
|
56
|
+
onDragEnter={event => receive(event, json => dragDrop(json, Platform.OS), onDragEnter)}
|
|
57
|
+
onDragOver={onDragOver ? event => receive(event, dragPosition, onDragOver) : undefined}
|
|
58
|
+
onDragLeave={() => { if (mounted.current && !disabled && !failed) onDragLeave?.(); }}
|
|
59
|
+
onDragEnd={event => receive(event, dragEnd, onDragEnd)} />;
|
|
17
60
|
}
|