@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
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
#endif
|
|
13
13
|
#include <atomic>
|
|
14
14
|
#include <chrono>
|
|
15
|
-
#include <
|
|
15
|
+
#include <functional>
|
|
16
16
|
#include <string>
|
|
17
|
-
#include <vector>
|
|
18
17
|
#include <thread>
|
|
19
18
|
#include <stdexcept>
|
|
20
19
|
#include <algorithm>
|
|
@@ -33,8 +32,7 @@ class AuthLoopback {
|
|
|
33
32
|
AuthSocket listener = InvalidSocket;
|
|
34
33
|
std::atomic<bool> stopped{false};
|
|
35
34
|
std::thread worker;
|
|
36
|
-
std::
|
|
37
|
-
std::vector<std::string> results;
|
|
35
|
+
std::function<void(std::string)> received;
|
|
38
36
|
std::string route, origin;
|
|
39
37
|
bool initialized = false;
|
|
40
38
|
void Receive() {
|
|
@@ -71,15 +69,16 @@ class AuthLoopback {
|
|
|
71
69
|
(request.substr(end, first - end) == " HTTP/1.1" || request.substr(end, first - end) == " HTTP/1.0");
|
|
72
70
|
}
|
|
73
71
|
}
|
|
74
|
-
if (valid) { std::lock_guard lock(mutex); if (results.size() < 16) results.push_back(origin + target); }
|
|
75
72
|
const std::string body = valid ? "Callback received. You may return to the application." : "Invalid callback request.";
|
|
76
73
|
const std::string response = std::string("HTTP/1.1 ") + (valid ? "200 OK" : "400 Bad Request") + "\r\nContent-Type: text/plain; charset=utf-8\r\nCache-Control: no-store\r\nConnection: close\r\nContent-Length: " + std::to_string(body.size()) + "\r\n\r\n" + body;
|
|
77
74
|
send(client, response.data(), static_cast<int>(response.size()), 0); CloseSocket(client);
|
|
75
|
+
if (valid && !stopped) received(origin + target);
|
|
78
76
|
}
|
|
79
77
|
CloseSocket(listener); listener = InvalidSocket;
|
|
80
78
|
}
|
|
81
79
|
public:
|
|
82
|
-
AuthLoopback(unsigned short port, std::string path) : route(std::move(path)) {
|
|
80
|
+
AuthLoopback(unsigned short port, std::string path, std::function<void(std::string)> callback) : received(std::move(callback)), route(std::move(path)) {
|
|
81
|
+
if (!received) throw std::invalid_argument("Expected a callback listener");
|
|
83
82
|
if (route.empty() || route[0] != '/' || route.find_first_not_of("/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_") != std::string::npos) throw std::invalid_argument("Invalid callback path");
|
|
84
83
|
#ifdef _WIN32
|
|
85
84
|
WSADATA data{}; if (WSAStartup(MAKEWORD(2, 2), &data)) throw std::runtime_error("Could not initialize loopback socket"); initialized = true;
|
|
@@ -115,7 +114,6 @@ class AuthLoopback {
|
|
|
115
114
|
#endif
|
|
116
115
|
}
|
|
117
116
|
std::string RedirectURI() const { return origin + route; }
|
|
118
|
-
std::vector<std::string> Drain() { std::lock_guard lock(mutex); auto values = std::move(results); results.clear(); return values; }
|
|
119
117
|
AuthLoopback(AuthLoopback const &) = delete;
|
|
120
118
|
};
|
|
121
119
|
}
|
|
@@ -29,30 +29,31 @@ RCT_EXPORT_MODULE(NativeDesktopLinks)
|
|
|
29
29
|
} else if ([method isEqual:@"authPrepare"]) {
|
|
30
30
|
if (key.empty() || _authSessions.count(key) || _authSessions.size() >= 4) throw std::invalid_argument("Invalid or busy auth session");
|
|
31
31
|
NSInteger port = [args[@"port"] integerValue]; if (port < 0 || port > 65535) throw std::invalid_argument("Invalid callback port");
|
|
32
|
-
auto receiver = std::make_unique<spark::AuthLoopback>((unsigned short)port, std::string([args[@"path"] UTF8String]))
|
|
32
|
+
auto receiver = std::make_unique<spark::AuthLoopback>((unsigned short)port, std::string([args[@"path"] UTF8String]), [identifier](std::string value) {
|
|
33
|
+
NSString *url = [NSString stringWithUTF8String:value.c_str()];
|
|
34
|
+
dispatch_async(dispatch_get_main_queue(), ^{ SparkEmit(@{ @"type": @"authRedirect", @"id": identifier, @"url": url }); });
|
|
35
|
+
});
|
|
33
36
|
NSString *uri = [NSString stringWithUTF8String:receiver->RedirectURI().c_str()]; _authSessions.emplace(key, std::move(receiver)); resolve(SparkJSON(uri));
|
|
34
37
|
} else if ([method isEqual:@"authClose"]) { _authSessions.erase(key); resolve(@"null"); }
|
|
35
|
-
else
|
|
36
|
-
auto found = _authSessions.find(key); if (found == _authSessions.end()) throw std::invalid_argument("Auth session is closed");
|
|
37
|
-
NSMutableArray *urls = [NSMutableArray new]; for (auto const &value : found->second->Drain()) [urls addObject:[NSString stringWithUTF8String:value.c_str()]];
|
|
38
|
-
resolve(SparkJSON(urls));
|
|
39
|
-
} else throw std::invalid_argument("Unknown auth operation");
|
|
38
|
+
else throw std::invalid_argument("Unknown auth operation");
|
|
40
39
|
} catch (std::exception const &error) { reject(@"E_AUTH", [NSString stringWithUTF8String:error.what()], nil); }
|
|
41
40
|
return;
|
|
42
41
|
}
|
|
43
42
|
if ([method isEqual:@"recent"]) {
|
|
44
43
|
NSArray *result = [NSUserDefaults.standardUserDefaults arrayForKey:[SparkNamespace() stringByAppendingString:@".recentDocuments"]] ?: @[];
|
|
45
|
-
|
|
44
|
+
NSMutableArray *paths = [NSMutableArray new];
|
|
45
|
+
for (NSString *value in result) { NSURL *url = [NSURL URLWithString:value]; if (!url.isFileURL || !url.path.length) { reject(@"E_INVALID_DATA", @"Invalid recent document URL", nil); return; } [paths addObject:url.path]; }
|
|
46
|
+
resolve(SparkJSON(paths)); return;
|
|
46
47
|
}
|
|
47
48
|
if ([method isEqual:@"clearRecent"]) {
|
|
48
49
|
[NSUserDefaults.standardUserDefaults removeObjectForKey:[SparkNamespace() stringByAppendingString:@".recentDocuments"]];
|
|
49
50
|
if (![SparkContext()[@"runtime"][@"mode"] isEqual:@"go"]) [NSDocumentController.sharedDocumentController clearRecentDocuments:nil];
|
|
50
51
|
resolve(@"null"); return;
|
|
51
52
|
}
|
|
52
|
-
NSURL *url = [NSURL URLWithString:args[@"url"] ?: @""];
|
|
53
|
+
NSURL *url = ([method isEqual:@"noteRecent"] || [method isEqual:@"openPath"]) ? [NSURL fileURLWithPath:args[@"path"]] : [NSURL URLWithString:args[@"url"] ?: @""];
|
|
53
54
|
if (!url.scheme.length) { SparkInvalid(reject, @"URL must have a scheme"); return; }
|
|
54
55
|
if ([method isEqual:@"canOpen"]) resolve(SparkJSON(@([NSWorkspace.sharedWorkspace URLForApplicationToOpenURL:url] != nil)));
|
|
55
|
-
else if ([method isEqual:@"open"]) {
|
|
56
|
+
else if ([method isEqual:@"open"] || [method isEqual:@"openPath"]) {
|
|
56
57
|
// Opening a URL can deliver an Apple event back to this app. Keep its
|
|
57
58
|
// main run loop free while LaunchServices resolves and opens the target.
|
|
58
59
|
[NSWorkspace.sharedWorkspace openURL:url configuration:NSWorkspaceOpenConfiguration.configuration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@legendapp/spark-desktop-links",
|
|
3
|
-
"version": "0.0.1-next.
|
|
3
|
+
"version": "0.0.1-next.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "src/index",
|
|
6
6
|
"react-native": "src/index",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
]
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@legendapp/spark-desktop-app": "0.0.1-next.
|
|
45
|
+
"@legendapp/spark-desktop-app": "0.0.1-next.4"
|
|
46
46
|
},
|
|
47
47
|
"peerDependenciesMeta": {
|
|
48
48
|
"expo-linking": {
|
|
@@ -3,4 +3,4 @@ import { TurboModuleRegistry } from "react-native";
|
|
|
3
3
|
export interface Spec extends TurboModule {
|
|
4
4
|
call(method: string, args: string): Promise<string>;
|
|
5
5
|
}
|
|
6
|
-
export default TurboModuleRegistry.
|
|
6
|
+
export default TurboModuleRegistry.get<Spec>("NativeDesktopLinks");
|
|
@@ -1,37 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import { onDesktopEvent } from "@legendapp/spark-desktop-app/src/events";
|
|
3
|
+
import { callAppNative } from "@legendapp/spark-desktop-app/src/transport";
|
|
4
|
+
import { nativePath } from "@legendapp/spark-desktop-app/src/contracts/path";
|
|
5
|
+
import { SparkError, type Subscription } from "@legendapp/spark-desktop-app/src/contracts";
|
|
6
|
+
export type { Subscription } from "@legendapp/spark-desktop-app/src/contracts";
|
|
7
|
+
import { callLinks, linksCommand } from "./native";
|
|
8
|
+
export type URLListener = (event: { url: string }) => void;
|
|
9
|
+
function url(value: string) {
|
|
10
|
+
if (typeof value !== "string" || !/^[a-z][a-z0-9+.-]*:/i.test(value) || value.includes("\0")) throw new SparkError("E_INVALID_ARGUMENT", "URL must include a scheme and contain no NUL");
|
|
11
|
+
return value;
|
|
8
12
|
}
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
/** Subscribe before fetching queued launches; event ids deduplicate the overlap. */
|
|
14
|
-
export async function onOpen(listener: (event: OpenEvent) => void) {
|
|
15
|
-
const seen = new Set<string>(); let removed = false;
|
|
16
|
-
function deliver(event: DesktopEvent) {
|
|
17
|
-
if (removed || (event.type !== "openFile" && event.type !== "openURL") || !event.id || seen.has(event.id)) return;
|
|
18
|
-
seen.add(event.id);
|
|
19
|
-
if (seen.size > 200) seen.delete(seen.values().next().value!);
|
|
20
|
-
listener(event as OpenEvent);
|
|
21
|
-
}
|
|
22
|
-
const subscription = onDesktopEvent(deliver);
|
|
23
|
-
try { for (const event of await callApp<DesktopEvent[]>("pendingURLs")) deliver(event); }
|
|
24
|
-
catch (error) { subscription.remove(); throw error; }
|
|
25
|
-
return { remove() { removed = true; subscription.remove(); } };
|
|
13
|
+
/** Selected Expo Linking contract: resolves true after native launch acceptance. */
|
|
14
|
+
export async function openURL(value: string): Promise<true> { await linksCommand("open", { url: url(value) }); return true; }
|
|
15
|
+
export function canOpenURL(value: string): Promise<boolean> {
|
|
16
|
+
return Promise.resolve().then(() => callLinks("canOpen", { url: url(value) }, (value): value is boolean => typeof value === "boolean"));
|
|
26
17
|
}
|
|
27
|
-
|
|
28
|
-
export
|
|
29
|
-
/**
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
/** Spark extension: open a local file or directory in its associated application. */
|
|
19
|
+
export async function openPath(path: string): Promise<void> { await linksCommand("openPath", { path: nativePath(path, Platform.OS) }); }
|
|
20
|
+
/** Stable native-process launch URL; later opens and JS reloads do not replace it. */
|
|
21
|
+
export function getInitialURL(): Promise<string | null> {
|
|
22
|
+
return callAppNative("initialURL", (value): value is string | null => value === null || (typeof value === "string" && /^[a-z][a-z0-9+.-]*:/i.test(value) && !value.includes("\0")));
|
|
23
|
+
}
|
|
24
|
+
/** Live URL events only. Queued file/URL requests belong to app/documents. */
|
|
25
|
+
export function addEventListener(type: "url", listener: URLListener): Subscription {
|
|
26
|
+
if (type !== "url" || typeof listener !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected a url event listener");
|
|
27
|
+
if (Platform.OS !== "macos" && Platform.OS !== "windows") throw new SparkError("E_UNSUPPORTED_PLATFORM", "Desktop URL events require a desktop host");
|
|
34
28
|
return onDesktopEvent(event => {
|
|
35
|
-
if (event.type === "openURL" && event.initial !== true && typeof event.url === "string") listener({ url: event.url });
|
|
36
|
-
});
|
|
29
|
+
if (event.type === "openURL" && event.initial !== true && typeof event.url === "string" && /^[a-z][a-z0-9+.-]*:/i.test(event.url) && !event.url.includes("\0")) listener({ url: event.url });
|
|
30
|
+
}, { types: ["openURL"] });
|
|
37
31
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
+
import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
|
|
1
2
|
export { openURL, canOpenURL, getInitialURL, addEventListener } from "expo-linking";
|
|
2
|
-
export type {
|
|
3
|
-
|
|
4
|
-
const unavailable = async (..._args: unknown[]): Promise<never> => { throw Object.assign(new Error("Desktop document events/history are unavailable on this platform; use URL events instead"), { code: "E_UNAVAILABLE" }); };
|
|
5
|
-
export const onOpen = unavailable, noteRecentDocument = unavailable, clearRecentDocuments = unavailable, getRecentDocuments = unavailable;
|
|
3
|
+
export type { URLListener } from "./api";
|
|
4
|
+
export async function openPath(_path: string): Promise<void> { throw new SparkError("E_UNSUPPORTED_PLATFORM", "Opening a native desktop path requires a desktop host"); }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import Native from "./NativeDesktopLinks";
|
|
3
|
+
import { SparkError, invokeNative, parseNativeResult } from "@legendapp/spark-desktop-app/src/contracts";
|
|
4
|
+
export async function callLinks<T>(method: string, args: object, validate: (value: unknown) => value is T): Promise<T> {
|
|
5
|
+
if (Platform.OS !== "macos" && Platform.OS !== "windows") throw new SparkError("E_UNSUPPORTED_PLATFORM", "Desktop linking requires a desktop host");
|
|
6
|
+
if (!Native) throw new SparkError("E_MODULE_UNAVAILABLE", "Desktop linking module is unavailable");
|
|
7
|
+
return parseNativeResult(await invokeNative(() => Native!.call(method, JSON.stringify(args))), validate);
|
|
8
|
+
}
|
|
9
|
+
export async function linksCommand(method: string, args: object = {}): Promise<void> { await callLinks(method, args, (value): value is null => value === null); }
|
|
@@ -41,13 +41,17 @@ struct RecentDocuments {
|
|
|
41
41
|
}
|
|
42
42
|
void Write(Json::JsonArray const &list) { auto value = list.Stringify(); check_win32(RegSetValueExW(key, L"URLs", 0, REG_SZ, reinterpret_cast<BYTE const *>(value.c_str()), static_cast<DWORD>((value.size() + 1) * sizeof(wchar_t)))); }
|
|
43
43
|
bool ShellEnabled() { wchar_t mode[16]{}; GetEnvironmentVariableW(L"SPARK_RUNTIME_MODE", mode, 16); return std::wstring(mode) == L"dev"; }
|
|
44
|
-
|
|
44
|
+
static std::wstring Path(hstring const &url) {
|
|
45
|
+
DWORD size = 32768; std::wstring path(size, L'\0'); check_hresult(PathCreateFromUrlW(url.c_str(), path.data(), &size, 0)); path.resize(wcslen(path.c_str())); return path;
|
|
46
|
+
}
|
|
47
|
+
Json::JsonArray Paths() { Json::JsonArray paths; for (auto const &entry : Read()) paths.Append(Json::JsonValue::CreateStringValue(Path(entry.GetString()))); return paths; }
|
|
48
|
+
void Add(hstring const &path) {
|
|
49
|
+
DWORD size = 32768; std::wstring url(size, L'\0'); check_hresult(UrlCreateFromPathW(path.c_str(), url.data(), &size, 0)); url.resize(wcslen(url.c_str()));
|
|
45
50
|
Windows::Foundation::Uri uri(url);
|
|
46
51
|
if (uri.SchemeName() != L"file") throw hresult_invalid_argument(L"Recent documents require file URLs");
|
|
47
52
|
Json::JsonArray next; next.Append(Json::JsonValue::CreateStringValue(uri.AbsoluteUri()));
|
|
48
53
|
for (auto const &entry : Read()) if (entry.GetString() != uri.AbsoluteUri() && next.Size() < 20) next.Append(entry);
|
|
49
54
|
if (ShellEnabled()) {
|
|
50
|
-
DWORD size = 32768; std::wstring path(size, L'\0'); check_hresult(PathCreateFromUrlW(uri.AbsoluteUri().c_str(), path.data(), &size, 0));
|
|
51
55
|
com_ptr<IShellItem> item; check_hresult(SHCreateItemFromParsingName(path.c_str(), nullptr, IID_PPV_ARGS(item.put())));
|
|
52
56
|
SHARDAPPIDINFO info{item.get(), appId.c_str()}; SHAddToRecentDocs(SHARD_APPIDINFO, &info);
|
|
53
57
|
}
|
|
@@ -68,7 +72,7 @@ struct SparkLinks {
|
|
|
68
72
|
React::ReactContext context;
|
|
69
73
|
REACT_INIT(Initialize)
|
|
70
74
|
void Initialize(React::ReactContext const &value) noexcept { context = value; }
|
|
71
|
-
static fire_and_forget Invoke(std::shared_ptr<Receivers> receivers, std::string method, std::string encoded, React::ReactPromise<std::string> promise) {
|
|
75
|
+
static fire_and_forget Invoke(React::ReactContext context, std::shared_ptr<Receivers> receivers, std::string method, std::string encoded, React::ReactPromise<std::string> promise) {
|
|
72
76
|
try {
|
|
73
77
|
auto args = Json::JsonObject::Parse(to_hstring(encoded));
|
|
74
78
|
if (method == "cryptoRandom") {
|
|
@@ -86,32 +90,28 @@ struct SparkLinks {
|
|
|
86
90
|
if (method == "authPrepare") {
|
|
87
91
|
if (id.empty() || receivers->count(id) || receivers->size() >= 4) throw hresult_invalid_argument(L"Invalid or busy auth session");
|
|
88
92
|
auto port = args.GetNamedNumber(L"port"); if (port < 0 || port > 65535 || port != std::floor(port)) throw hresult_invalid_argument(L"Invalid callback port");
|
|
89
|
-
auto receiver = std::make_unique<spark::AuthLoopback>(static_cast<unsigned short>(port), to_string(args.GetNamedString(L"path")))
|
|
93
|
+
auto receiver = std::make_unique<spark::AuthLoopback>(static_cast<unsigned short>(port), to_string(args.GetNamedString(L"path")), [context, id](std::string url) {
|
|
94
|
+
context.UIDispatcher().Post([context, id, url = std::move(url)] {
|
|
95
|
+
context.EmitJSEvent(L"RCTDeviceEventEmitter", L"desktop", React::JSValueObject{{"type", "authRedirect"}, {"id", id}, {"url", url}});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
90
98
|
auto uri = receiver->RedirectURI(); receivers->emplace(id, std::move(receiver)); promise.Resolve(to_string(Json::JsonValue::CreateStringValue(to_hstring(uri)).Stringify()));
|
|
91
99
|
} else if (method == "authClose") { receivers->erase(id); promise.Resolve("null"); }
|
|
92
|
-
else
|
|
93
|
-
auto found = receivers->find(id); if (found == receivers->end()) throw hresult_invalid_argument(L"Auth session is closed");
|
|
94
|
-
Json::JsonArray urls; for (auto const &uri : found->second->Drain()) urls.Append(Json::JsonValue::CreateStringValue(to_hstring(uri))); promise.Resolve(to_string(urls.Stringify()));
|
|
95
|
-
} else throw hresult_invalid_argument(L"Unknown auth operation");
|
|
100
|
+
else throw hresult_invalid_argument(L"Unknown auth operation");
|
|
96
101
|
} else if (method == "recent" || method == "noteRecent" || method == "clearRecent") {
|
|
97
102
|
RecentDocuments recent;
|
|
98
|
-
if (method == "recent") promise.Resolve(to_string(recent.
|
|
99
|
-
else { if (method == "noteRecent") recent.Add(args.GetNamedString(L"
|
|
100
|
-
} else if (method == "
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (colon != std::wstring::npos && colon > 1 && candidate[0] != L'-') { initial = candidate; break; }
|
|
106
|
-
}
|
|
107
|
-
LocalFree(arguments);
|
|
108
|
-
}
|
|
109
|
-
promise.Resolve(initial.empty() ? "null" : to_string(Json::JsonValue::CreateStringValue(initial).Stringify()));
|
|
103
|
+
if (method == "recent") promise.Resolve(to_string(recent.Paths().Stringify()));
|
|
104
|
+
else { if (method == "noteRecent") recent.Add(args.GetNamedString(L"path")); else recent.Clear(); promise.Resolve("null"); }
|
|
105
|
+
} else if (method == "openPath") {
|
|
106
|
+
auto path = args.GetNamedString(L"path");
|
|
107
|
+
auto result = reinterpret_cast<INT_PTR>(ShellExecuteW(nullptr, L"open", path.c_str(), nullptr, nullptr, SW_SHOWNORMAL));
|
|
108
|
+
if (result <= 32) { promise.Reject(React::ReactError{result == SE_ERR_FNF || result == SE_ERR_PNF ? "E_NOT_FOUND" : result == SE_ERR_ACCESSDENIED ? "E_PERMISSION_DENIED" : "E_NATIVE", "No application opened this path"}); co_return; }
|
|
109
|
+
promise.Resolve("null");
|
|
110
110
|
} else {
|
|
111
111
|
Windows::Foundation::Uri uri(args.GetNamedString(L"url"));
|
|
112
112
|
if (method == "open") {
|
|
113
113
|
if (!co_await Windows::System::Launcher::LaunchUriAsync(uri)) { promise.Reject(React::ReactError{"E_OPEN_URL", "No application opened this URL"}); co_return; }
|
|
114
|
-
promise.Resolve("
|
|
114
|
+
promise.Resolve("null");
|
|
115
115
|
} else if (method == "canOpen") {
|
|
116
116
|
auto status = co_await Windows::System::Launcher::QueryUriSupportAsync(uri, Windows::System::LaunchQuerySupportType::Uri);
|
|
117
117
|
promise.Resolve(status == Windows::System::LaunchQuerySupportStatus::Available ? "true" : "false");
|
|
@@ -122,7 +122,7 @@ struct SparkLinks {
|
|
|
122
122
|
}
|
|
123
123
|
REACT_METHOD(call)
|
|
124
124
|
void call(std::string method, std::string args, React::ReactPromise<std::string> promise) noexcept {
|
|
125
|
-
context.UIDispatcher().Post([receivers = receivers, method = std::move(method), args = std::move(args), promise]() { Invoke(receivers, method, args, promise); });
|
|
125
|
+
context.UIDispatcher().Post([context = context, receivers = receivers, method = std::move(method), args = std::move(args), promise]() { Invoke(context, receivers, method, args, promise); });
|
|
126
126
|
}
|
|
127
127
|
};
|
|
128
128
|
}
|
|
@@ -16,7 +16,7 @@ RCT_EXPORT_MODULE(NativeDesktopShortcuts)
|
|
|
16
16
|
for (NSDictionary *existing in self.shortcuts.allValues) {
|
|
17
17
|
if ([existing[@"key"] isEqual:args[@"key"]] && [existing[@"modifiers"] isEqual:args[@"modifiers"]] &&
|
|
18
18
|
((!existing[@"windowId"] && !args[@"windowId"]) || [existing[@"windowId"] isEqual:args[@"windowId"]])) {
|
|
19
|
-
reject(@"
|
|
19
|
+
reject(@"E_BUSY", @"Shortcut is already registered in this scope", nil); return;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
self.shortcuts[args[@"id"]] = args;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#import "RNKeyboardManager.h"
|
|
2
|
+
|
|
3
|
+
#import <React/RCTBridgeModule.h>
|
|
4
|
+
#import <TargetConditionals.h>
|
|
5
|
+
#include <cmath>
|
|
6
|
+
#include <atomic>
|
|
7
|
+
|
|
8
|
+
#if TARGET_OS_OSX
|
|
9
|
+
#import <AppKit/AppKit.h>
|
|
10
|
+
#import <IOKit/hidsystem/IOLLEvent.h>
|
|
11
|
+
#import <IOKit/hidsystem/ev_keymap.h>
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
static NSInteger const RNKeyboardMediaPlayPause = 10001;
|
|
15
|
+
static NSInteger const RNKeyboardMediaNext = 10002;
|
|
16
|
+
static NSInteger const RNKeyboardMediaPrevious = 10003;
|
|
17
|
+
|
|
18
|
+
#if TARGET_OS_OSX
|
|
19
|
+
static NSUInteger const RNKeyboardModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagOption | NSEventModifierFlagShift | NSEventModifierFlagFunction | NSEventModifierFlagCapsLock;
|
|
20
|
+
@interface SparkKeyboardRule : NSObject
|
|
21
|
+
@property (nonatomic, copy) NSString *key;
|
|
22
|
+
@property (nonatomic) NSUInteger modifiers;
|
|
23
|
+
@property (nonatomic) BOOL allowExtraModifiers;
|
|
24
|
+
@property (nonatomic) BOOL repeat;
|
|
25
|
+
@property (nonatomic, copy) NSSet<NSString *> *windowIds;
|
|
26
|
+
@property (nonatomic, copy) NSSet<NSString *> *excludedWindowIds;
|
|
27
|
+
@end
|
|
28
|
+
@implementation SparkKeyboardRule @end
|
|
29
|
+
|
|
30
|
+
static BOOL SparkKeyboardBoolean(id value) { return [value isKindOfClass:NSNumber.class] && CFGetTypeID((__bridge CFTypeRef)value) == CFBooleanGetTypeID(); }
|
|
31
|
+
|
|
32
|
+
// Stripping modifiers renders navigation and function keys as C0 control characters (Right is
|
|
33
|
+
// U+001D, Backspace U+0008), which no accelerator can name; accelerators parse AppKit's
|
|
34
|
+
// private-use code and U+007F instead. Tab and Return are also C0 but already spell their
|
|
35
|
+
// accelerators, so only keys whose unmodified character identifies them are substituted.
|
|
36
|
+
static NSString *SparkKeyboardKeyString(NSEvent *event) {
|
|
37
|
+
NSString *key = [event charactersByApplyingModifiers:0] ?: @"";
|
|
38
|
+
if (key.length == 1 && [key characterAtIndex:0] < 0x20) {
|
|
39
|
+
NSString *unmodified = event.charactersIgnoringModifiers;
|
|
40
|
+
if (unmodified.length == 1) {
|
|
41
|
+
unichar code = [unmodified characterAtIndex:0];
|
|
42
|
+
if ((code >= 0xF700 && code <= 0xF747) || code == 0x7F) return unmodified.lowercaseString;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return key.lowercaseString;
|
|
46
|
+
}
|
|
47
|
+
static NSSet<NSString *> *SparkKeyboardWindows(id value, BOOL *valid) {
|
|
48
|
+
if (!value) return nil;
|
|
49
|
+
if (![value isKindOfClass:NSArray.class]) { *valid = NO; return nil; }
|
|
50
|
+
for (id identifier in value) if (![identifier isKindOfClass:NSString.class] || ![identifier length]) { *valid = NO; return nil; }
|
|
51
|
+
return [NSSet setWithArray:value];
|
|
52
|
+
}
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
@implementation RNKeyboardManager {
|
|
56
|
+
std::atomic<bool> _hasListeners;
|
|
57
|
+
#if TARGET_OS_OSX
|
|
58
|
+
id _localEventMonitor;
|
|
59
|
+
NSMutableDictionary<NSString *, NSArray<SparkKeyboardRule *> *> *_consumptionOwners;
|
|
60
|
+
NSMutableSet<NSString *> *_captureOwners;
|
|
61
|
+
NSDictionary<NSString *, NSArray<SparkKeyboardRule *> *> *_rulesByKey;
|
|
62
|
+
NSMutableDictionary<NSNumber *, NSNumber *> *_consumedKeys;
|
|
63
|
+
#endif
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
RCT_EXPORT_MODULE(NativeKeyboardManager)
|
|
67
|
+
|
|
68
|
+
+ (BOOL)requiresMainQueueSetup
|
|
69
|
+
{
|
|
70
|
+
return YES;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (instancetype)init
|
|
74
|
+
{
|
|
75
|
+
if (self = [super init]) {
|
|
76
|
+
_hasListeners.store(false, std::memory_order_relaxed);
|
|
77
|
+
#if TARGET_OS_OSX
|
|
78
|
+
_consumptionOwners = [NSMutableDictionary new];
|
|
79
|
+
_captureOwners = [NSMutableSet new];
|
|
80
|
+
_rulesByKey = @{};
|
|
81
|
+
_consumedKeys = [NSMutableDictionary new];
|
|
82
|
+
[NSNotificationCenter.defaultCenter addObserver:self
|
|
83
|
+
selector:@selector(applicationWillTerminate:)
|
|
84
|
+
name:NSApplicationWillTerminateNotification
|
|
85
|
+
object:nil];
|
|
86
|
+
#endif
|
|
87
|
+
}
|
|
88
|
+
return self;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
- (void)dealloc
|
|
92
|
+
{
|
|
93
|
+
#if TARGET_OS_OSX
|
|
94
|
+
id monitor = _localEventMonitor;
|
|
95
|
+
if (monitor) {
|
|
96
|
+
if (NSThread.isMainThread) [NSEvent removeMonitor:monitor];
|
|
97
|
+
else dispatch_async(dispatch_get_main_queue(), ^{ [NSEvent removeMonitor:monitor]; });
|
|
98
|
+
}
|
|
99
|
+
[NSNotificationCenter.defaultCenter removeObserver:self];
|
|
100
|
+
#endif
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
- (NSArray<NSString *> *)supportedEvents
|
|
104
|
+
{
|
|
105
|
+
return @[@"onKeyDown", @"onKeyUp"];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
- (void)startObserving
|
|
109
|
+
{
|
|
110
|
+
_hasListeners.store(true, std::memory_order_relaxed);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
- (void)stopObserving
|
|
114
|
+
{
|
|
115
|
+
_hasListeners.store(false, std::memory_order_relaxed);
|
|
116
|
+
#if TARGET_OS_OSX
|
|
117
|
+
if (NSThread.isMainThread) [self stopMonitoringInternal];
|
|
118
|
+
else dispatch_async(dispatch_get_main_queue(), ^{ [self stopMonitoringInternal]; });
|
|
119
|
+
#endif
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
123
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
124
|
+
{
|
|
125
|
+
return std::make_shared<facebook::react::NativeKeyboardManagerSpecJSI>(params);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
- (void)startMonitoringKeyboard:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
129
|
+
{
|
|
130
|
+
#if TARGET_OS_OSX
|
|
131
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
132
|
+
[self startMonitoringInternal];
|
|
133
|
+
if (self->_localEventMonitor) resolve(@YES); else reject(@"E_UNAVAILABLE", @"Keyboard event monitor could not start", nil);
|
|
134
|
+
});
|
|
135
|
+
#else
|
|
136
|
+
reject(@"E_UNSUPPORTED_PLATFORM", @"Keyboard monitoring requires macOS", nil);
|
|
137
|
+
#endif
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
- (void)stopMonitoringKeyboard:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
141
|
+
{
|
|
142
|
+
#if TARGET_OS_OSX
|
|
143
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
144
|
+
[self stopMonitoringInternal];
|
|
145
|
+
resolve(@YES);
|
|
146
|
+
});
|
|
147
|
+
#else
|
|
148
|
+
resolve(@NO);
|
|
149
|
+
#endif
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
- (void)setConsumption:(NSString *)ownerId rulesJson:(NSString *)rulesJson capture:(BOOL)capture resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
153
|
+
{
|
|
154
|
+
#if TARGET_OS_OSX
|
|
155
|
+
id values = [NSJSONSerialization JSONObjectWithData:[rulesJson dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingFragmentsAllowed error:nil];
|
|
156
|
+
if (!ownerId.length || ![values isKindOfClass:NSArray.class]) { reject(@"E_INVALID_ARGUMENT", @"Expected an owner and keyboard consumption rules", nil); return; }
|
|
157
|
+
NSMutableArray<SparkKeyboardRule *> *rules = [NSMutableArray new];
|
|
158
|
+
for (id value in values) {
|
|
159
|
+
if (![value isKindOfClass:NSDictionary.class]) { reject(@"E_INVALID_ARGUMENT", @"Invalid keyboard consumption rule", nil); return; }
|
|
160
|
+
id key = value[@"key"], modifiers = value[@"modifiers"];
|
|
161
|
+
BOOL valid = [key isKindOfClass:NSString.class] && [key length] && [modifiers isKindOfClass:NSNumber.class] && !SparkKeyboardBoolean(modifiers);
|
|
162
|
+
double bits = valid ? [modifiers doubleValue] : -1;
|
|
163
|
+
valid = valid && std::isfinite(bits) && bits >= 0 && bits <= RNKeyboardModifierMask && std::floor(bits) == bits && (((NSUInteger)bits & ~RNKeyboardModifierMask) == 0);
|
|
164
|
+
valid = valid && SparkKeyboardBoolean(value[@"allowExtraModifiers"]) && SparkKeyboardBoolean(value[@"repeat"]);
|
|
165
|
+
SparkKeyboardRule *rule = [SparkKeyboardRule new];
|
|
166
|
+
rule.windowIds = SparkKeyboardWindows(value[@"windowIds"], &valid);
|
|
167
|
+
rule.excludedWindowIds = SparkKeyboardWindows(value[@"excludedWindowIds"], &valid);
|
|
168
|
+
if (!valid) { reject(@"E_INVALID_ARGUMENT", @"Invalid keyboard consumption rule", nil); return; }
|
|
169
|
+
rule.key = [key lowercaseString]; rule.modifiers = (NSUInteger)bits;
|
|
170
|
+
rule.allowExtraModifiers = [value[@"allowExtraModifiers"] boolValue]; rule.repeat = [value[@"repeat"] boolValue];
|
|
171
|
+
[rules addObject:rule];
|
|
172
|
+
}
|
|
173
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
174
|
+
if (rules.count) self->_consumptionOwners[ownerId] = rules; else [self->_consumptionOwners removeObjectForKey:ownerId];
|
|
175
|
+
if (capture) [self->_captureOwners addObject:ownerId]; else [self->_captureOwners removeObject:ownerId];
|
|
176
|
+
NSMutableDictionary<NSString *, NSMutableArray<SparkKeyboardRule *> *> *byKey = [NSMutableDictionary new];
|
|
177
|
+
for (NSArray<SparkKeyboardRule *> *ownerRules in self->_consumptionOwners.allValues) for (SparkKeyboardRule *rule in ownerRules) {
|
|
178
|
+
if (!byKey[rule.key]) byKey[rule.key] = [NSMutableArray new];
|
|
179
|
+
[byKey[rule.key] addObject:rule];
|
|
180
|
+
}
|
|
181
|
+
self->_rulesByKey = byKey;
|
|
182
|
+
resolve(@YES);
|
|
183
|
+
});
|
|
184
|
+
#else
|
|
185
|
+
reject(@"E_UNSUPPORTED_PLATFORM", @"Keyboard consumption requires macOS", nil);
|
|
186
|
+
#endif
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
- (void)invalidate
|
|
190
|
+
{
|
|
191
|
+
_hasListeners.store(false, std::memory_order_relaxed);
|
|
192
|
+
#if TARGET_OS_OSX
|
|
193
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
194
|
+
[self stopMonitoringInternal];
|
|
195
|
+
[self->_consumptionOwners removeAllObjects]; [self->_captureOwners removeAllObjects]; self->_rulesByKey = @{};
|
|
196
|
+
});
|
|
197
|
+
#endif
|
|
198
|
+
[super invalidate];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#if TARGET_OS_OSX
|
|
202
|
+
- (void)applicationWillTerminate:(NSNotification *)notification
|
|
203
|
+
{
|
|
204
|
+
[self stopMonitoringInternal];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
- (void)startMonitoringInternal
|
|
208
|
+
{
|
|
209
|
+
[self stopMonitoringInternal];
|
|
210
|
+
__weak RNKeyboardManager *weakSelf = self;
|
|
211
|
+
NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskSystemDefined;
|
|
212
|
+
_localEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent *(NSEvent *event) {
|
|
213
|
+
RNKeyboardManager *strongSelf = weakSelf;
|
|
214
|
+
if (!strongSelf) {
|
|
215
|
+
return event;
|
|
216
|
+
}
|
|
217
|
+
return [strongSelf handleKeyboardEvent:event];
|
|
218
|
+
}];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
- (void)stopMonitoringInternal
|
|
222
|
+
{
|
|
223
|
+
if (_localEventMonitor) {
|
|
224
|
+
[NSEvent removeMonitor:_localEventMonitor];
|
|
225
|
+
_localEventMonitor = nil;
|
|
226
|
+
}
|
|
227
|
+
[_consumedKeys removeAllObjects];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
- (NSEvent *)handleKeyboardEvent:(NSEvent *)event
|
|
231
|
+
{
|
|
232
|
+
if (event.type == NSEventTypeSystemDefined) {
|
|
233
|
+
return [self handleSystemDefinedEvent:event];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (event.type != NSEventTypeKeyDown && event.type != NSEventTypeKeyUp) {
|
|
237
|
+
return event;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
NSString *eventName = event.type == NSEventTypeKeyDown ? @"onKeyDown" : @"onKeyUp";
|
|
241
|
+
BOOL handled = [self emitKeyboardEvent:eventName keyCode:event.keyCode key:SparkKeyboardKeyString(event) modifiers:event.modifierFlags window:event.window repeated:event.isARepeat];
|
|
242
|
+
return handled ? nil : event;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
- (NSEvent *)handleSystemDefinedEvent:(NSEvent *)event
|
|
246
|
+
{
|
|
247
|
+
if (event.subtype != NX_SUBTYPE_AUX_CONTROL_BUTTONS) {
|
|
248
|
+
return event;
|
|
249
|
+
}
|
|
250
|
+
NSInteger data = event.data1;
|
|
251
|
+
NSInteger keyCode = (data & 0xFFFF0000) >> 16;
|
|
252
|
+
NSInteger keyFlags = data & 0x0000FFFF;
|
|
253
|
+
NSInteger keyState = (keyFlags & 0xFF00) >> 8;
|
|
254
|
+
NSNumber *mappedKeyCode = [self mappedMediaKeyCode:keyCode];
|
|
255
|
+
if (!mappedKeyCode) {
|
|
256
|
+
return event;
|
|
257
|
+
}
|
|
258
|
+
NSString *eventName = keyState == NX_KEYDOWN ? @"onKeyDown" : @"onKeyUp";
|
|
259
|
+
BOOL handled = [self emitKeyboardEvent:eventName keyCode:mappedKeyCode.integerValue key:@{@10001: @"MediaPlayPause", @10002: @"MediaNext", @10003: @"MediaPrevious"}[mappedKeyCode] modifiers:event.modifierFlags window:event.window repeated:(keyFlags & 1) != 0];
|
|
260
|
+
return handled ? nil : event;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
- (NSNumber *)mappedMediaKeyCode:(NSInteger)keyCode
|
|
264
|
+
{
|
|
265
|
+
switch (keyCode) {
|
|
266
|
+
case NX_KEYTYPE_PLAY:
|
|
267
|
+
return @(RNKeyboardMediaPlayPause);
|
|
268
|
+
case NX_KEYTYPE_FAST:
|
|
269
|
+
case NX_KEYTYPE_NEXT:
|
|
270
|
+
return @(RNKeyboardMediaNext);
|
|
271
|
+
case NX_KEYTYPE_REWIND:
|
|
272
|
+
case NX_KEYTYPE_PREVIOUS:
|
|
273
|
+
return @(RNKeyboardMediaPrevious);
|
|
274
|
+
default:
|
|
275
|
+
return nil;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
- (BOOL)emitKeyboardEvent:(NSString *)eventName keyCode:(NSInteger)keyCode key:(NSString *)key modifiers:(NSUInteger)modifiers window:(NSWindow *)window repeated:(BOOL)repeated
|
|
280
|
+
{
|
|
281
|
+
NSString *identifier = (window ?: NSApp.keyWindow).identifier;
|
|
282
|
+
NSString *windowId = [identifier hasPrefix:@"spark."] ? [identifier substringFromIndex:6] : identifier;
|
|
283
|
+
BOOL down = [eventName isEqual:@"onKeyDown"];
|
|
284
|
+
NSNumber *held = _consumedKeys[@(keyCode)];
|
|
285
|
+
BOOL captured = _captureOwners.count > 0 || (!down && held.boolValue);
|
|
286
|
+
BOOL consumed = captured || (!down && held != nil);
|
|
287
|
+
if (down && !consumed) {
|
|
288
|
+
NSString *normalizedKey = key.lowercaseString;
|
|
289
|
+
for (SparkKeyboardRule *rule in _rulesByKey[normalizedKey]) {
|
|
290
|
+
if ((repeated && !rule.repeat) || (rule.windowIds && (!windowId || ![rule.windowIds containsObject:windowId])) || (windowId && [rule.excludedWindowIds containsObject:windowId])) continue;
|
|
291
|
+
NSUInteger active = modifiers & RNKeyboardModifierMask;
|
|
292
|
+
if (!(rule.modifiers & NSEventModifierFlagCapsLock)) active &= ~NSEventModifierFlagCapsLock;
|
|
293
|
+
if (!(rule.modifiers & NSEventModifierFlagFunction) && key.length == 1 && [key characterAtIndex:0] >= 0xf700 && [key characterAtIndex:0] <= 0xf747) active &= ~NSEventModifierFlagFunction;
|
|
294
|
+
if (rule.allowExtraModifiers ? (active & rule.modifiers) == rule.modifiers : active == rule.modifiers) { consumed = YES; break; }
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (down && consumed) _consumedKeys[@(keyCode)] = @(captured || held.boolValue);
|
|
298
|
+
if (!down) [_consumedKeys removeObjectForKey:@(keyCode)];
|
|
299
|
+
if (_hasListeners.load(std::memory_order_relaxed)) [self sendEventWithName:eventName body:@{
|
|
300
|
+
@"keyCode": @(keyCode), @"key": key, @"modifiers": @(modifiers), @"windowId": windowId ?: (id)NSNull.null,
|
|
301
|
+
@"repeated": @(repeated), @"consumed": @(consumed), @"captured": @(captured),
|
|
302
|
+
}];
|
|
303
|
+
return consumed;
|
|
304
|
+
}
|
|
305
|
+
#endif
|
|
306
|
+
|
|
307
|
+
@end
|