@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,37 @@
|
|
|
1
|
+
import type { HostComponent, ViewProps } from "react-native";
|
|
2
|
+
import { codegenNativeComponent } from "react-native";
|
|
3
|
+
import type { DirectEventHandler, Double } from "react-native/Libraries/Types/CodegenTypes";
|
|
4
|
+
|
|
5
|
+
export type SidebarSplitViewResizeEvent = Readonly<{
|
|
6
|
+
contentHeight: Double;
|
|
7
|
+
contentWidth: Double;
|
|
8
|
+
contentX: Double;
|
|
9
|
+
height: Double;
|
|
10
|
+
isLayoutReady: boolean;
|
|
11
|
+
isVertical: boolean;
|
|
12
|
+
listHeight: Double;
|
|
13
|
+
listWidth: Double;
|
|
14
|
+
listX: Double;
|
|
15
|
+
sidebarHeight: Double;
|
|
16
|
+
sidebarWidth: Double;
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
export interface NativeProps extends ViewProps {
|
|
20
|
+
appearance?: string;
|
|
21
|
+
contentTitlebarHeight?: Double;
|
|
22
|
+
contentTitlebarMaterial?: string;
|
|
23
|
+
contentTitlebarOverlayColor?: string;
|
|
24
|
+
contentTitlebarOverlayOpacity?: Double;
|
|
25
|
+
contentMinWidth?: Double;
|
|
26
|
+
hasList?: boolean;
|
|
27
|
+
listMinWidth?: Double;
|
|
28
|
+
listWidth?: Double;
|
|
29
|
+
onSplitViewDidResize?: DirectEventHandler<SidebarSplitViewResizeEvent>;
|
|
30
|
+
sidebarCollapsed?: boolean;
|
|
31
|
+
sidebarMinWidth?: Double;
|
|
32
|
+
sidebarTitlebarOverlayColor?: string;
|
|
33
|
+
sidebarTitlebarOverlayOpacity?: Double;
|
|
34
|
+
sidebarWidth?: Double;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default codegenNativeComponent<NativeProps>("SidebarSplitView") as HostComponent<NativeProps>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { useState, type ReactNode } from "react";
|
|
2
|
+
import { View, type NativeSyntheticEvent } from "react-native";
|
|
3
|
+
import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
|
|
4
|
+
import { useControl } from "../control";
|
|
5
|
+
import { appearance, callback, finite, macosViewAvailability, type SpecializedViewProps } from "../specialized";
|
|
6
|
+
import NativeSplitView from "./SidebarSplitViewNativeComponent";
|
|
7
|
+
export type SidebarSplitViewAppearance = "system" | "light" | "dark";
|
|
8
|
+
export type SidebarSplitViewTitlebarMaterial = "none" | "glass" | "titlebar" | "headerView" | "hudWindow" | "sidebar" | "windowBackground";
|
|
9
|
+
export interface SidebarSplitViewPaneMetrics { contentHeight: number; contentWidth: number; sidebarHeight: number; sidebarWidth: number; listHeight?: number; listWidth?: number }
|
|
10
|
+
export interface SidebarSplitViewResizeEvent extends SidebarSplitViewPaneMetrics { listHeight: number; listWidth: number; contentX: number; listX: number; height: number; phase: "provisional" | "ready" }
|
|
11
|
+
export interface SplitViewTitleBarOverlay { color: string; opacity?: number }
|
|
12
|
+
export interface SplitViewTitleBarOptions {
|
|
13
|
+
content?: { height?: number; material?: SidebarSplitViewTitlebarMaterial; overlay?: SplitViewTitleBarOverlay };
|
|
14
|
+
sidebar?: { overlay?: SplitViewTitleBarOverlay };
|
|
15
|
+
}
|
|
16
|
+
export interface SidebarSplitViewProps extends Omit<SpecializedViewProps, "children"> {
|
|
17
|
+
sidebar: ReactNode;
|
|
18
|
+
content: ReactNode;
|
|
19
|
+
/** Optional middle column (AppKit content list, as in Mail): sidebar | list | content in one native split. */
|
|
20
|
+
list?: ReactNode;
|
|
21
|
+
children?: never;
|
|
22
|
+
appearance?: SidebarSplitViewAppearance;
|
|
23
|
+
contentMinWidth?: number;
|
|
24
|
+
sidebarMinWidth?: number;
|
|
25
|
+
sidebarWidth?: number;
|
|
26
|
+
listMinWidth?: number;
|
|
27
|
+
listWidth?: number;
|
|
28
|
+
sidebarCollapsed?: boolean;
|
|
29
|
+
/** Used only for initial layout, before native measurements arrive. */
|
|
30
|
+
initialPaneMetrics?: SidebarSplitViewPaneMetrics;
|
|
31
|
+
titleBar?: SplitViewTitleBarOptions;
|
|
32
|
+
onResize?: (event: SidebarSplitViewResizeEvent) => void;
|
|
33
|
+
}
|
|
34
|
+
export function getSplitViewAvailability() { return macosViewAvailability("SidebarSplitView"); }
|
|
35
|
+
function metrics(value: SidebarSplitViewPaneMetrics) {
|
|
36
|
+
if (!value || typeof value !== "object") throw new SparkError("E_INVALID_ARGUMENT", "Expected pane metrics");
|
|
37
|
+
for (const key of ["contentHeight", "contentWidth", "sidebarHeight", "sidebarWidth"] as const) finite(value[key], key);
|
|
38
|
+
for (const key of ["listHeight", "listWidth"] as const) if (value[key] !== undefined) finite(value[key], key);
|
|
39
|
+
}
|
|
40
|
+
const paneKeys = ["contentHeight", "contentWidth", "sidebarHeight", "sidebarWidth", "listHeight", "listWidth"] as const;
|
|
41
|
+
function keys(value: unknown, allowed: readonly string[]) {
|
|
42
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new SparkError("E_INVALID_ARGUMENT", "Expected title-bar options");
|
|
43
|
+
for (const key of Object.keys(value)) if (!allowed.includes(key)) throw new SparkError("E_UNSUPPORTED_OPTION", `Unknown title-bar option: ${key}`);
|
|
44
|
+
}
|
|
45
|
+
function overlay(value?: SplitViewTitleBarOverlay) {
|
|
46
|
+
if (value === undefined) return;
|
|
47
|
+
keys(value, ["color", "opacity"]);
|
|
48
|
+
if (typeof value.color !== "string" || !/^#(?:[\da-f]{6}|[\da-f]{8})$/i.test(value.color)) throw new SparkError("E_INVALID_ARGUMENT", "Expected #RRGGBB or #RRGGBBAA title-bar color");
|
|
49
|
+
if (value.opacity !== undefined) finite(value.opacity, "overlay opacity", 0, 1);
|
|
50
|
+
}
|
|
51
|
+
export function SidebarSplitView({ sidebar, content, list, children, appearance: theme = "system", contentMinWidth = 320, sidebarMinWidth = 180, sidebarWidth, listMinWidth = 240, listWidth, sidebarCollapsed = false, initialPaneMetrics, titleBar = {}, onResize, ref, onError, ...props }: SidebarSplitViewProps) {
|
|
52
|
+
appearance(theme); finite(contentMinWidth, "minimum content width"); finite(sidebarMinWidth, "minimum sidebar width"); finite(listMinWidth, "minimum list width");
|
|
53
|
+
if (sidebarWidth !== undefined) finite(sidebarWidth, "sidebar width", sidebarMinWidth);
|
|
54
|
+
if (listWidth !== undefined) finite(listWidth, "list width", listMinWidth);
|
|
55
|
+
const hasList = list !== undefined && list !== null && typeof list !== "boolean" && list !== "";
|
|
56
|
+
if (typeof sidebarCollapsed !== "boolean" || children !== undefined) throw new SparkError("E_INVALID_ARGUMENT", "Use named sidebar/content panes and a boolean collapsed state");
|
|
57
|
+
if (initialPaneMetrics !== undefined) metrics(initialPaneMetrics);
|
|
58
|
+
keys(titleBar, ["content", "sidebar"]);
|
|
59
|
+
if (titleBar.content !== undefined) { keys(titleBar.content, ["height", "material", "overlay"]); if (titleBar.content.height !== undefined) finite(titleBar.content.height, "title-bar height"); }
|
|
60
|
+
if (titleBar.sidebar !== undefined) keys(titleBar.sidebar, ["overlay"]);
|
|
61
|
+
overlay(titleBar.content?.overlay); overlay(titleBar.sidebar?.overlay);
|
|
62
|
+
const material = titleBar.content?.material ?? "none";
|
|
63
|
+
if (!["none", "glass", "titlebar", "headerView", "hudWindow", "sidebar", "windowBackground"].includes(material)) throw new SparkError("E_INVALID_ARGUMENT", "Invalid title-bar material");
|
|
64
|
+
callback(onResize, "resize");
|
|
65
|
+
const control = useControl({ ref, onError }, getSplitViewAvailability());
|
|
66
|
+
const [paneMetrics, setPaneMetrics] = useState<SidebarSplitViewPaneMetrics | undefined>(() => initialPaneMetrics ? { ...initialPaneMetrics } : undefined);
|
|
67
|
+
function resize(event: NativeSyntheticEvent<SidebarSplitViewPaneMetrics & { contentX: number; listX: number; height: number; isLayoutReady: boolean }>) {
|
|
68
|
+
if (!control.active()) return;
|
|
69
|
+
let value: SidebarSplitViewResizeEvent;
|
|
70
|
+
try {
|
|
71
|
+
const data = event?.nativeEvent; metrics(data); finite(data.listHeight, "list height"); finite(data.listWidth, "list width"); finite(data.contentX, "content x", -Infinity); finite(data.listX, "list x", -Infinity); finite(data.height, "height");
|
|
72
|
+
if (typeof data.isLayoutReady !== "boolean") throw new Error("Expected layout readiness");
|
|
73
|
+
value = { contentHeight: data.contentHeight, contentWidth: data.contentWidth, sidebarHeight: data.sidebarHeight, sidebarWidth: data.sidebarWidth, listHeight: data.listHeight, listWidth: data.listWidth, contentX: data.contentX, listX: data.listX, height: data.height, phase: data.isLayoutReady ? "ready" : "provisional" };
|
|
74
|
+
} catch (cause) { control.error(new SparkError("E_INVALID_DATA", "Invalid split-view layout", { cause })); return; }
|
|
75
|
+
setPaneMetrics(current => current && paneKeys.every(key => current[key] === value[key]) ? current : value);
|
|
76
|
+
onResize?.(value);
|
|
77
|
+
}
|
|
78
|
+
if (control.failed) return <View {...props} ref={control.ref} style={[{ flexDirection: "row" }, props.style]}>{sidebarCollapsed ? null : sidebar}{list}{content}</View>;
|
|
79
|
+
return <NativeSplitView {...props} ref={control.ref} appearance={theme} contentMinWidth={contentMinWidth} sidebarMinWidth={sidebarMinWidth} sidebarWidth={sidebarWidth} hasList={hasList} listMinWidth={listMinWidth} listWidth={listWidth} sidebarCollapsed={sidebarCollapsed} onSplitViewDidResize={resize}
|
|
80
|
+
contentTitlebarHeight={titleBar.content?.height ?? 0} contentTitlebarMaterial={material} contentTitlebarOverlayColor={titleBar.content?.overlay?.color} contentTitlebarOverlayOpacity={titleBar.content?.overlay?.opacity ?? (titleBar.content?.overlay ? 1 : 0)}
|
|
81
|
+
sidebarTitlebarOverlayColor={titleBar.sidebar?.overlay?.color} sidebarTitlebarOverlayOpacity={titleBar.sidebar?.overlay?.opacity ?? (titleBar.sidebar?.overlay ? 1 : 0)}>
|
|
82
|
+
<View key="sidebar" style={{ position: "absolute", top: 0, left: 0, minWidth: 0, height: paneMetrics?.sidebarHeight, width: sidebarCollapsed ? 0 : paneMetrics?.sidebarWidth ?? sidebarWidth ?? sidebarMinWidth }}>{sidebar}</View>
|
|
83
|
+
<View key="content" style={{ position: "absolute", top: 0, left: 0, minWidth: 0, overflow: "hidden", height: paneMetrics?.contentHeight, width: paneMetrics?.contentWidth }}>{content}</View>
|
|
84
|
+
{hasList ? <View key="list" style={{ position: "absolute", top: 0, left: 0, minWidth: 0, height: paneMetrics?.listHeight, width: paneMetrics?.listWidth ?? listWidth ?? listMinWidth }}>{list}</View> : null}
|
|
85
|
+
</NativeSplitView>;
|
|
86
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Platform, UIManager } from "react-native";
|
|
2
|
+
import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
import type { ControlKind } from "./types";
|
|
4
|
+
export function getControlAvailability(control: ControlKind): Availability {
|
|
5
|
+
const names: Record<ControlKind, string> = { button: "SparkButton", "text-input": "SparkTextInput", select: Platform.OS === "windows" ? "SparkSelect" : "NativeSelect", "segmented-control": "NativeSegmentedControl" };
|
|
6
|
+
if (!Object.hasOwn(names, control)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown control kind");
|
|
7
|
+
if (Platform.OS !== "macos" && Platform.OS !== "windows") return { available: false, reason: "unsupported-platform" };
|
|
8
|
+
if (Platform.OS === "windows" && control === "segmented-control") return { available: false, reason: "unsupported-platform" };
|
|
9
|
+
return UIManager.hasViewManagerConfig(names[control]) ? { available: true } : { available: false, reason: "missing-module" };
|
|
10
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
import type { ButtonProps, ControlProps, ControlRef, TextInputProps } from "./types";
|
|
4
|
+
export type MeasureTarget = ControlRef | null;
|
|
5
|
+
export function useControl(props: ControlProps, availability: Availability = { available: true }) {
|
|
6
|
+
const { disabled = false, onError = console.error } = props;
|
|
7
|
+
if (typeof disabled !== "boolean" || typeof onError !== "function" || (props.accessibilityLabel !== undefined && typeof props.accessibilityLabel !== "string") || (props.testID !== undefined && typeof props.testID !== "string")) throw new SparkError("E_INVALID_ARGUMENT", "Invalid control options");
|
|
8
|
+
const target = useRef<MeasureTarget>(null), mounted = useRef(false), reported = useRef<string | undefined>(undefined);
|
|
9
|
+
const [failed, setFailed] = useState(false);
|
|
10
|
+
useLayoutEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
|
|
11
|
+
const reason = availability.available ? undefined : availability.reason;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (reason && reported.current !== reason) {
|
|
14
|
+
reported.current = reason;
|
|
15
|
+
onError(new SparkError(reason === "unsupported-platform" ? "E_UNSUPPORTED_PLATFORM" : reason === "missing-module" ? "E_MODULE_UNAVAILABLE" : "E_UNAVAILABLE", "Native control is unavailable"));
|
|
16
|
+
}
|
|
17
|
+
}, [reason, onError]);
|
|
18
|
+
useImperativeHandle(props.ref, () => ({ measureInWindow(callback) {
|
|
19
|
+
if (typeof callback !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected a measurement callback");
|
|
20
|
+
if (!target.current || !mounted.current) throw new SparkError("E_CLOSED", "Control is not mounted");
|
|
21
|
+
target.current.measureInWindow((...bounds) => { if (mounted.current) callback(...bounds); });
|
|
22
|
+
} }), []);
|
|
23
|
+
function error(error: SparkError) { if (mounted.current) onError(error); }
|
|
24
|
+
function unavailable(event: { nativeEvent: { message: string } }) {
|
|
25
|
+
if (!mounted.current) return;
|
|
26
|
+
if (typeof event?.nativeEvent?.message !== "string") { error(new SparkError("E_INVALID_DATA", "Invalid native control error")); return; }
|
|
27
|
+
setFailed(true); error(new SparkError("E_UNAVAILABLE", event.nativeEvent.message));
|
|
28
|
+
}
|
|
29
|
+
const ref = useCallback((value: MeasureTarget) => { target.current = value; }, []);
|
|
30
|
+
return { ref, disabled, failed: failed || !availability.available, error, unavailable, active: () => mounted.current && !disabled && !failed && availability.available };
|
|
31
|
+
}
|
|
32
|
+
export function validateButton(props: ButtonProps) {
|
|
33
|
+
if (typeof props.children !== "string" || !props.children.length || (props.onPress !== undefined && typeof props.onPress !== "function") || (props.variant !== undefined && !["default", "bordered", "borderless"].includes(props.variant))) throw new SparkError("E_INVALID_ARGUMENT", "Invalid button options");
|
|
34
|
+
}
|
|
35
|
+
export function useTextValue(props: TextInputProps) {
|
|
36
|
+
const controlled = props.value !== undefined;
|
|
37
|
+
const initialMode = useRef(controlled), initialText = useRef(props.defaultValue ?? ""), latestCount = useRef(0);
|
|
38
|
+
if (initialMode.current !== controlled) throw new SparkError("E_INVALID_ARGUMENT", "TextInput cannot switch controlled mode; remount it instead");
|
|
39
|
+
if ((controlled && (typeof props.value !== "string" || props.defaultValue !== undefined)) || (props.defaultValue !== undefined && typeof props.defaultValue !== "string") || (props.onChangeText !== undefined && typeof props.onChangeText !== "function")) throw new SparkError("E_INVALID_ARGUMENT", "TextInput requires a string value or defaultValue, not both");
|
|
40
|
+
const [eventCount, setEventCount] = useState(0);
|
|
41
|
+
return { controlled, text: props.value ?? "", defaultText: initialText.current, eventCount, acknowledge(count: number) { if (count <= latestCount.current) return false; latestCount.current = count; if (controlled) setEventCount(count); return true; } };
|
|
42
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Platform, Text, View, type NativeSyntheticEvent } from "react-native";
|
|
3
|
+
import NativeTextInput from "./SparkTextInputNativeComponent";
|
|
4
|
+
import NativeButton from "./SparkButtonNativeComponent";
|
|
5
|
+
import NativeSelect from "./native-select/NativeSelectNativeComponent";
|
|
6
|
+
import WindowsSelect from "./SparkSelectNativeComponent";
|
|
7
|
+
import NativeSegmentedControl from "./native-select/NativeSegmentedControlNativeComponent";
|
|
8
|
+
import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
|
|
9
|
+
import { useControl, useTextValue, validateButton } from "./control";
|
|
10
|
+
import { getControlAvailability } from "./availability";
|
|
11
|
+
import { selectionIndex } from "./select";
|
|
12
|
+
import type { ButtonProps, TextInputProps, SelectProps, SegmentedControlProps } from "./types";
|
|
13
|
+
export type { ButtonProps, TextInputProps, ControlledTextInputProps, UncontrolledTextInputProps, SelectProps, SelectOption, SegmentedControlProps, ControlProps, ControlRef, ControlKind } from "./types";
|
|
14
|
+
export { getControlAvailability } from "./availability";
|
|
15
|
+
|
|
16
|
+
export function Button(props: ButtonProps) {
|
|
17
|
+
validateButton(props);
|
|
18
|
+
const control = useControl(props, getControlAvailability("button"));
|
|
19
|
+
const { children, variant = "default", onPress, accessibilityLabel = children, style, testID } = props;
|
|
20
|
+
if (control.failed) return <View ref={control.ref} style={[{ width: 160, height: 36 }, style]} testID={testID} accessible accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }}><Text>{children}</Text></View>;
|
|
21
|
+
return <NativeButton ref={control.ref} title={children} disabled={control.disabled} variant={variant} accessibilityLabel={accessibilityLabel}
|
|
22
|
+
onButtonPress={() => { if (control.active()) onPress?.(); }} onUnavailable={control.unavailable} testID={testID} style={[{ width: 160, height: 36 }, style]} />;
|
|
23
|
+
}
|
|
24
|
+
export function TextInput(props: TextInputProps) {
|
|
25
|
+
const control = useControl(props, getControlAvailability("text-input"));
|
|
26
|
+
const value = useTextValue(props);
|
|
27
|
+
function changed(event: NativeSyntheticEvent<{ text: string; eventCount: number }>) {
|
|
28
|
+
if (!control.active()) return;
|
|
29
|
+
const data = event?.nativeEvent;
|
|
30
|
+
if (typeof data?.text !== "string" || !Number.isSafeInteger(data.eventCount) || data.eventCount < 1 || data.eventCount > 2147483647) { control.error(new SparkError("E_INVALID_DATA", "Invalid native text change")); return; }
|
|
31
|
+
if (value.acknowledge(data.eventCount)) props.onChangeText?.(data.text);
|
|
32
|
+
}
|
|
33
|
+
const { accessibilityLabel, style, testID } = props;
|
|
34
|
+
if (control.failed) return <View ref={control.ref} style={[{ width: 240, height: 36 }, style]} testID={testID} accessible accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }}><Text>{value.controlled ? value.text : value.defaultText}</Text></View>;
|
|
35
|
+
return <NativeTextInput ref={control.ref} text={value.text} defaultText={value.defaultText} controlled={value.controlled} eventCount={value.eventCount} disabled={control.disabled} onTextChange={changed} onUnavailable={control.unavailable} accessibilityLabel={accessibilityLabel} testID={testID} style={[{ width: 240, height: 36 }, style]} />;
|
|
36
|
+
}
|
|
37
|
+
function Selection({ segmented, ...props }: SelectProps & { segmented: boolean }) {
|
|
38
|
+
selectionIndex(props.options, props.value);
|
|
39
|
+
if (typeof props.onValueChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected onValueChange");
|
|
40
|
+
const control = useControl(props, getControlAvailability(segmented ? "segmented-control" : "select"));
|
|
41
|
+
const [selectionRevision, revise] = useState(0);
|
|
42
|
+
const { options, value, onValueChange, accessibilityLabel, style, testID } = props;
|
|
43
|
+
function changed(event: NativeSyntheticEvent<{ value: string }>) {
|
|
44
|
+
if (!control.active()) return;
|
|
45
|
+
const next = event?.nativeEvent?.value;
|
|
46
|
+
if (!options.some(option => option.value === next)) { control.error(new SparkError("E_INVALID_DATA", "Native selection is not an option")); return; }
|
|
47
|
+
revise(revision => revision + 1); onValueChange(next);
|
|
48
|
+
}
|
|
49
|
+
const common = { ref: control.ref, value, accessibilityLabel, testID, style: [{ width: 240, height: 36 }, style], selectionRevision };
|
|
50
|
+
if (control.failed) return <View ref={control.ref} style={common.style} testID={testID} accessible accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }}><Text>{options.find(option => option.value === value)!.label}</Text></View>;
|
|
51
|
+
if (segmented) return <NativeSegmentedControl {...common} segmentsJson={JSON.stringify(options)} enabled={!control.disabled} onValueChange={changed} />;
|
|
52
|
+
if (Platform.OS === "windows") return <WindowsSelect {...common} itemsJson={JSON.stringify(options)} disabled={control.disabled} onSelectionChange={changed} onUnavailable={control.unavailable} />;
|
|
53
|
+
return <NativeSelect {...common} itemsJson={JSON.stringify(options)} enabled={!control.disabled} onValueChange={changed} />;
|
|
54
|
+
}
|
|
55
|
+
export function Select(props: SelectProps) { return <Selection {...props} segmented={false} />; }
|
|
56
|
+
export function SegmentedControl(props: SegmentedControlProps) { return <Selection {...props} segmented />; }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { requireNativeComponent, View, type ColorValue } from "react-native";
|
|
2
|
+
import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
import { useControl } from "../control";
|
|
4
|
+
import { macosViewAvailability, type SpecializedViewProps } from "../specialized";
|
|
5
|
+
export type GlassStyle = "regular" | "clear";
|
|
6
|
+
export interface GlassViewProps extends SpecializedViewProps { glassStyle?: GlassStyle; tintColor?: ColorValue }
|
|
7
|
+
const NativeGlass = requireNativeComponent<GlassViewProps>("RNGlassEffectView");
|
|
8
|
+
export function getGlassAvailability() { return macosViewAvailability("RNGlassEffectView", 26); }
|
|
9
|
+
/** Native glass hosts its children; unsupported hosts preserve them without an effect. */
|
|
10
|
+
export function GlassView({ glassStyle = "regular", tintColor, ref, onError, ...props }: GlassViewProps) {
|
|
11
|
+
if (glassStyle !== "regular" && glassStyle !== "clear") throw new SparkError("E_INVALID_ARGUMENT", "Invalid glass style");
|
|
12
|
+
const control = useControl({ ref, onError }, getGlassAvailability());
|
|
13
|
+
if (control.failed) return <View {...props} ref={control.ref} />;
|
|
14
|
+
return <NativeGlass {...props} ref={control.ref} glassStyle={glassStyle} tintColor={tintColor} />;
|
|
15
|
+
}
|
|
@@ -1,25 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
function ExpoButton(props: ComponentProps<typeof import("@expo/ui/jetpack-compose").Button>) {
|
|
3
|
+
const Component = (require("@expo/ui/jetpack-compose") as typeof import("@expo/ui/jetpack-compose")).Button;
|
|
4
|
+
return <Component {...props} />;
|
|
5
|
+
}
|
|
6
|
+
import { View, Text } from "react-native";
|
|
7
|
+
import { requireOptionalNativeModule } from "expo-modules-core";
|
|
8
|
+
import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
|
|
2
9
|
import { selectionIndex } from "./select";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return
|
|
10
|
-
<ExpoButton style={styles.content} onPress={disabled ? undefined : onPress}
|
|
11
|
-
disabled={disabled} variant={variant}>{children}</ExpoButton>
|
|
12
|
-
</View>;
|
|
10
|
+
import { useControl, validateButton } from "./control";
|
|
11
|
+
import type { ButtonProps, SelectProps, SegmentedControlProps, ControlKind } from "./types";
|
|
12
|
+
export type { ButtonProps, TextInputProps, ControlledTextInputProps, UncontrolledTextInputProps, SelectProps, SelectOption, SegmentedControlProps, ControlProps, ControlRef, ControlKind } from "./types";
|
|
13
|
+
export { TextInput } from "./mobile-input";
|
|
14
|
+
export function getControlAvailability(control: ControlKind): Availability {
|
|
15
|
+
if (!["button", "text-input", "select", "segmented-control"].includes(control)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown control kind");
|
|
16
|
+
return control === "text-input" || requireOptionalNativeModule("ExpoUI") ? { available: true } : { available: false, reason: "missing-module" };
|
|
13
17
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
export function Button(props: ButtonProps) {
|
|
19
|
+
validateButton(props); const control = useControl(props, getControlAvailability("button"));
|
|
20
|
+
const { children, onPress, variant = "default", style, testID, accessibilityLabel = children } = props;
|
|
21
|
+
return <View ref={control.ref} style={[{ width: 160, height: 48 }, style]} testID={testID}>
|
|
22
|
+
{control.failed ? <Text accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }}>{children}</Text> :
|
|
23
|
+
<ExpoButton style={{ flex: 1 }} onPress={() => { if (control.active()) onPress?.(); }} disabled={control.disabled} variant={variant} {...{ accessibilityLabel }}>{children}</ExpoButton>}
|
|
24
|
+
</View>;
|
|
19
25
|
}
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
return <View style={[{ width: 280,
|
|
26
|
+
function Selection(props: SelectProps) {
|
|
27
|
+
const selected = selectionIndex(props.options, props.value);
|
|
28
|
+
if (typeof props.onValueChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected onValueChange");
|
|
29
|
+
const control = useControl(props, getControlAvailability("select"));
|
|
30
|
+
return <View ref={control.ref} style={[{ width: 280, minHeight: 48, flexDirection: "row" }, props.style]} testID={props.testID} accessibilityLabel={props.accessibilityLabel}>
|
|
31
|
+
{control.failed ? <Text accessibilityState={{ disabled: true }}>{props.options[selected].label}</Text> : props.options.map(option =>
|
|
32
|
+
<ExpoButton key={option.value} disabled={control.disabled} variant={option.value === props.value ? "bordered" : "borderless"} style={{ flex: 1 }}
|
|
33
|
+
{...{ accessibilityRole: "radio", accessibilityState: { checked: option.value === props.value, disabled: control.disabled } }}
|
|
34
|
+
onPress={() => { if (control.active()) props.onValueChange(option.value); }}>{option.label}</ExpoButton>)}
|
|
35
|
+
</View>;
|
|
25
36
|
}
|
|
37
|
+
/** Android presents its choices inline; there is no dropdown backend in the pinned Expo UI. */
|
|
38
|
+
export function Select(props: SelectProps) { return <Selection {...props} />; }
|
|
39
|
+
export function SegmentedControl(props: SegmentedControlProps) { return <Selection {...props} />; }
|
|
@@ -1,30 +1,59 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, type ComponentProps } from "react";
|
|
2
|
+
function ExpoButton(props: ComponentProps<typeof import("@expo/ui/swift-ui").Button>) {
|
|
3
|
+
const Component = (require("@expo/ui/swift-ui") as typeof import("@expo/ui/swift-ui")).Button;
|
|
4
|
+
return <Component {...props} />;
|
|
5
|
+
}
|
|
6
|
+
function Host(props: ComponentProps<typeof import("@expo/ui/swift-ui").Host>) {
|
|
7
|
+
const Component = (require("@expo/ui/swift-ui") as typeof import("@expo/ui/swift-ui")).Host;
|
|
8
|
+
return <Component {...props} />;
|
|
9
|
+
}
|
|
10
|
+
function Picker(props: ComponentProps<typeof import("@expo/ui/swift-ui").Picker>) {
|
|
11
|
+
const Component = (require("@expo/ui/swift-ui") as typeof import("@expo/ui/swift-ui")).Picker;
|
|
12
|
+
return <Component {...props} />;
|
|
13
|
+
}
|
|
14
|
+
import { frame, disabled as disabledModifier, accessibilityLabel as labelModifier } from "@expo/ui/swift-ui/modifiers";
|
|
15
|
+
import { View, Text } from "react-native";
|
|
16
|
+
import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
|
|
17
|
+
import { requireOptionalNativeModule } from "expo-modules-core";
|
|
18
|
+
import { useControl, validateButton } from "./control";
|
|
2
19
|
import { selectionIndex } from "./select";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const fill = [frame({ maxWidth: Infinity, maxHeight: Infinity })];
|
|
10
|
-
export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
|
|
11
|
-
return <Host style={[styles.button, style]}>
|
|
12
|
-
<ExpoButton onPress={disabled ? undefined : onPress} disabled={disabled}
|
|
13
|
-
variant={variant} modifiers={fill} testID={testID}>{children}</ExpoButton>
|
|
14
|
-
</Host>;
|
|
20
|
+
import type { ButtonProps, SelectProps, SegmentedControlProps, ControlKind } from "./types";
|
|
21
|
+
export type { ButtonProps, TextInputProps, ControlledTextInputProps, UncontrolledTextInputProps, SelectProps, SelectOption, SegmentedControlProps, ControlProps, ControlRef, ControlKind } from "./types";
|
|
22
|
+
export { TextInput } from "./mobile-input";
|
|
23
|
+
export function getControlAvailability(control: ControlKind): Availability {
|
|
24
|
+
if (!["button", "text-input", "select", "segmented-control"].includes(control)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown control kind");
|
|
25
|
+
return control === "text-input" || requireOptionalNativeModule("ExpoUI") ? { available: true } : { available: false, reason: "missing-module" };
|
|
15
26
|
}
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
const fill = [frame({ maxWidth: Infinity, maxHeight: Infinity })];
|
|
28
|
+
export function Button(props: ButtonProps) {
|
|
29
|
+
validateButton(props); const control = useControl(props, getControlAvailability("button"));
|
|
30
|
+
const { children, onPress, variant = "default", style, testID, accessibilityLabel = children } = props;
|
|
31
|
+
return <View ref={control.ref} style={[{ width: 160, height: 44 }, style]}>
|
|
32
|
+
{control.failed ? <Text accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }} testID={testID}>{children}</Text> :
|
|
33
|
+
<Host style={{ flex: 1 }}><ExpoButton onPress={() => { if (control.active()) onPress?.(); }} disabled={control.disabled}
|
|
34
|
+
variant={variant} modifiers={[...fill, labelModifier(accessibilityLabel)]} testID={testID}>{children}</ExpoButton></Host>}
|
|
35
|
+
</View>;
|
|
23
36
|
}
|
|
24
|
-
|
|
25
|
-
const selectedIndex = selectionIndex(options, value);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
37
|
+
function Selection({ segmented, ...props }: SelectProps & { segmented: boolean }) {
|
|
38
|
+
const selectedIndex = selectionIndex(props.options, props.value);
|
|
39
|
+
const [selectionRevision, revise] = useState(0);
|
|
40
|
+
if (typeof props.onValueChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected onValueChange");
|
|
41
|
+
const control = useControl(props, getControlAvailability(segmented ? "segmented-control" : "select"));
|
|
42
|
+
const { options, onValueChange, accessibilityLabel, style, testID } = props;
|
|
43
|
+
const modifiers = [disabledModifier(control.disabled), ...(accessibilityLabel ? [labelModifier(accessibilityLabel)] : [])];
|
|
44
|
+
return <View ref={control.ref} style={[{ width: 240, height: 44 }, style]}>
|
|
45
|
+
{control.failed ? <Text accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }} testID={testID}>{options[selectedIndex].label}</Text> :
|
|
46
|
+
<Host style={{ flex: 1 }}><Picker key={selectionRevision} variant={segmented ? "segmented" : "menu"} options={options.map(option => option.label)} selectedIndex={selectedIndex}
|
|
47
|
+
onOptionSelected={event => {
|
|
48
|
+
if (!control.active()) return;
|
|
49
|
+
const index = event?.nativeEvent?.index;
|
|
50
|
+
if (!Number.isInteger(index) || !options[index]) { control.error(new SparkError("E_INVALID_DATA", "Invalid native selection")); return; }
|
|
51
|
+
// Expo's SwiftUI picker retains local selection and ignores an unchanged
|
|
52
|
+
// selectedIndex. A fresh picker also restores a parent-vetoed selection.
|
|
53
|
+
revise(value => value + 1);
|
|
54
|
+
onValueChange(options[index].value);
|
|
55
|
+
}} modifiers={modifiers} testID={testID} /></Host>}
|
|
56
|
+
</View>;
|
|
30
57
|
}
|
|
58
|
+
export function Select(props: SelectProps) { return <Selection {...props} segmented={false} />; }
|
|
59
|
+
export function SegmentedControl(props: SegmentedControlProps) { return <Selection {...props} segmented />; }
|
|
@@ -1,27 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { NativeSyntheticEvent } from "react-native";
|
|
3
|
-
import NativeTextInput from "./SparkTextInputNativeComponent";
|
|
4
|
-
import NativeSelect from "./SparkSelectNativeComponent";
|
|
5
|
-
import { selectionIndex } from "./select";
|
|
6
|
-
import { StyleSheet } from "react-native";
|
|
7
|
-
import NativeButton from "./SparkButtonNativeComponent";
|
|
8
|
-
import type { ButtonProps, TextInputProps, SelectProps } from "./types";
|
|
9
|
-
export type { ButtonProps, TextInputProps, SelectProps } from "./types";
|
|
10
|
-
|
|
11
|
-
export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
|
|
12
|
-
return <NativeButton title={children} disabled={disabled} variant={variant}
|
|
13
|
-
onButtonPress={disabled ? undefined : onPress} testID={testID}
|
|
14
|
-
style={[styles.button, style]} />;
|
|
15
|
-
}
|
|
16
|
-
const styles = StyleSheet.create({ button: { width: 160, height: 36 } });
|
|
17
|
-
|
|
18
|
-
export function TextInput({ defaultValue = "", onChangeText, style, ...props }: TextInputProps) {
|
|
19
|
-
const changed = useCallback((event: NativeSyntheticEvent<{ text: string }>) => onChangeText?.(event.nativeEvent.text), [onChangeText]);
|
|
20
|
-
return <NativeTextInput {...props} defaultText={defaultValue} onTextChange={changed} style={[{ width: 240, height: 36 }, style]} />;
|
|
21
|
-
}
|
|
22
|
-
export function Select({ options, value, onValueChange, style, ...props }: SelectProps) {
|
|
23
|
-
selectionIndex(options, value);
|
|
24
|
-
const itemsJson = useMemo(() => JSON.stringify(options), [options]);
|
|
25
|
-
const changed = useCallback((event: NativeSyntheticEvent<{ value: string }>) => onValueChange(event.nativeEvent.value), [onValueChange]);
|
|
26
|
-
return <NativeSelect {...props} itemsJson={itemsJson} value={value} onSelectionChange={changed} style={[{ width: 240, height: 36 }, style]} />;
|
|
27
|
-
}
|
|
1
|
+
export * from "./desktop";
|
|
@@ -1,23 +1,54 @@
|
|
|
1
1
|
import { selectionIndex } from "./select";
|
|
2
2
|
import type { CSSProperties } from "react";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
|
|
5
|
+
import { useControl, useTextValue, validateButton } from "./control";
|
|
6
|
+
import type { ButtonProps, TextInputProps, SelectProps, SegmentedControlProps, ControlKind } from "./types";
|
|
7
|
+
export type { ButtonProps, TextInputProps, ControlledTextInputProps, UncontrolledTextInputProps, SelectProps, SelectOption, SegmentedControlProps, ControlProps, ControlRef, ControlKind } from "./types";
|
|
8
|
+
export function getControlAvailability(control: ControlKind): Availability {
|
|
9
|
+
if (!["button", "text-input", "select", "segmented-control"].includes(control)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown control kind");
|
|
10
|
+
return { available: true };
|
|
11
|
+
}
|
|
7
12
|
const nativeStyle: CSSProperties = { width: "100%", height: "100%", boxSizing: "border-box", font: "14px system-ui" };
|
|
8
13
|
const borderlessStyle: CSSProperties = { ...nativeStyle, border: "none", background: "transparent" };
|
|
9
|
-
export function Button(
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
export function Button(props: ButtonProps) {
|
|
15
|
+
validateButton(props); const control = useControl(props);
|
|
16
|
+
const { children, onPress, variant = "default", accessibilityLabel = children, style, testID } = props;
|
|
17
|
+
return <View ref={control.ref} style={[{ width: 160, height: 36 }, style]} testID={testID}>
|
|
18
|
+
<button type="button" disabled={control.disabled} onClick={() => { if (control.active()) onPress?.(); }} aria-label={accessibilityLabel}
|
|
12
19
|
style={variant === "borderless" ? borderlessStyle : nativeStyle}>{children}</button>
|
|
13
20
|
</View>;
|
|
14
21
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
export function TextInput(props: TextInputProps) {
|
|
23
|
+
const control = useControl(props), state = useTextValue(props);
|
|
24
|
+
return <View ref={control.ref} style={[{ width: 240, height: 36 }, props.style]} testID={props.testID}>
|
|
25
|
+
<input type="text" value={state.controlled ? state.text : undefined} defaultValue={state.controlled ? undefined : state.defaultText} disabled={control.disabled}
|
|
26
|
+
onChange={event => { if (control.active()) props.onChangeText?.(event.currentTarget.value); }} aria-label={props.accessibilityLabel} style={nativeStyle} />
|
|
27
|
+
</View>;
|
|
28
|
+
}
|
|
29
|
+
function useSelection(props: SelectProps) {
|
|
30
|
+
selectionIndex(props.options, props.value);
|
|
31
|
+
if (typeof props.onValueChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected onValueChange");
|
|
32
|
+
const control = useControl(props);
|
|
33
|
+
return { ...control, change(value: string) {
|
|
34
|
+
if (!control.active()) return;
|
|
35
|
+
if (!props.options.some(option => option.value === value)) { control.error(new SparkError("E_INVALID_DATA", "Invalid native selection")); return; }
|
|
36
|
+
props.onValueChange(value);
|
|
37
|
+
} };
|
|
19
38
|
}
|
|
20
|
-
export function Select(
|
|
21
|
-
|
|
22
|
-
return <View style={[{ width: 240, height: 36 }, style]} testID={testID}
|
|
39
|
+
export function Select(props: SelectProps) {
|
|
40
|
+
const control = useSelection(props);
|
|
41
|
+
return <View ref={control.ref} style={[{ width: 240, height: 36 }, props.style]} testID={props.testID}>
|
|
42
|
+
<select value={props.value} disabled={control.disabled} onChange={event => control.change(event.currentTarget.value)} aria-label={props.accessibilityLabel} style={nativeStyle}>
|
|
43
|
+
{props.options.map(option => <option key={option.value} value={option.value}>{option.label}</option>)}
|
|
44
|
+
</select>
|
|
45
|
+
</View>;
|
|
46
|
+
}
|
|
47
|
+
export function SegmentedControl(props: SegmentedControlProps) {
|
|
48
|
+
const control = useSelection(props);
|
|
49
|
+
return <View ref={control.ref} style={[{ width: 240, height: 36 }, props.style]} testID={props.testID}>
|
|
50
|
+
<div role="group" aria-label={props.accessibilityLabel} style={{ display: "flex", width: "100%", height: "100%" }}>
|
|
51
|
+
{props.options.map(option => <button type="button" key={option.value} disabled={control.disabled} aria-pressed={option.value === props.value} onClick={() => control.change(option.value)} style={{ ...nativeStyle, flex: 1 }}>{option.label}</button>)}
|
|
52
|
+
</div>
|
|
53
|
+
</View>;
|
|
23
54
|
}
|
|
@@ -1,42 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Text, View, TurboModuleRegistry } from "react-native";
|
|
3
|
-
import type { NativeSyntheticEvent, TurboModule, StyleProp, ViewStyle } from "react-native";
|
|
4
|
-
import NativeButton from "./SparkButtonNativeComponent";
|
|
5
|
-
import NativeTextInput from "./SparkTextInputNativeComponent";
|
|
6
|
-
import NativeSelect from "./SparkSelectNativeComponent";
|
|
7
|
-
import { selectionIndex } from "./select";
|
|
8
|
-
import type { ButtonProps, TextInputProps, SelectProps } from "./types";
|
|
9
|
-
export type { ButtonProps, TextInputProps, SelectProps } from "./types";
|
|
10
|
-
interface Availability extends TurboModule { isAvailable(): boolean }
|
|
11
|
-
const available = TurboModuleRegistry.get<Availability>("NativeSparkUI")?.isAvailable() === true;
|
|
12
|
-
function useAvailability() {
|
|
13
|
-
const [failed, setFailed] = useState(!available);
|
|
14
|
-
const unavailable = useCallback((event: NativeSyntheticEvent<{ message: string }>) => {
|
|
15
|
-
console.warn(`Windows native control unavailable: ${event.nativeEvent.message}`); setFailed(true);
|
|
16
|
-
}, []);
|
|
17
|
-
return { failed, onUnavailable: unavailable };
|
|
18
|
-
}
|
|
19
|
-
function Placeholder({ label, style, testID }: { label: string; style?: StyleProp<ViewStyle>; testID?: string }) {
|
|
20
|
-
return <View style={[{ minHeight: 36, padding: 8, borderWidth: 1, borderColor: "#999" }, style]} testID={testID} accessible accessibilityLabel={label} accessibilityState={{ disabled: true }}>
|
|
21
|
-
<Text>{label} — Windows control unavailable; rebuild the development client.</Text>
|
|
22
|
-
</View>;
|
|
23
|
-
}
|
|
24
|
-
export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
|
|
25
|
-
const { failed, onUnavailable } = useAvailability();
|
|
26
|
-
return failed ? <Placeholder label={children} style={style} testID={testID} /> :
|
|
27
|
-
<NativeButton title={children} disabled={disabled} variant={variant} onButtonPress={disabled ? undefined : onPress} onUnavailable={onUnavailable} testID={testID} style={[{ width: 160, height: 36 }, style]} />;
|
|
28
|
-
}
|
|
29
|
-
export function TextInput({ defaultValue = "", onChangeText, style, ...props }: TextInputProps) {
|
|
30
|
-
const { failed, onUnavailable } = useAvailability();
|
|
31
|
-
const changed = useCallback((event: NativeSyntheticEvent<{ text: string }>) => onChangeText?.(event.nativeEvent.text), [onChangeText]);
|
|
32
|
-
return failed ? <Placeholder label={props.accessibilityLabel ?? "Text input"} style={style} testID={props.testID} /> :
|
|
33
|
-
<NativeTextInput {...props} defaultText={defaultValue} onTextChange={changed} onUnavailable={onUnavailable} style={[{ width: 240, height: 36 }, style]} />;
|
|
34
|
-
}
|
|
35
|
-
export function Select({ options, value, onValueChange, style, ...props }: SelectProps) {
|
|
36
|
-
const selected = selectionIndex(options, value);
|
|
37
|
-
const { failed, onUnavailable } = useAvailability();
|
|
38
|
-
const itemsJson = useMemo(() => JSON.stringify(options), [options]);
|
|
39
|
-
const changed = useCallback((event: NativeSyntheticEvent<{ value: string }>) => onValueChange(event.nativeEvent.value), [onValueChange]);
|
|
40
|
-
return failed ? <Placeholder label={`${props.accessibilityLabel ?? "Select"}: ${options[selected]!.label}`} style={style} testID={props.testID} /> :
|
|
41
|
-
<NativeSelect {...props} itemsJson={itemsJson} value={value} onSelectionChange={changed} onUnavailable={onUnavailable} style={[{ width: 240, height: 36 }, style]} />;
|
|
42
|
-
}
|
|
1
|
+
export * from "./desktop";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TextInput as RNTextInput } from "react-native";
|
|
2
|
+
import { useControl, useTextValue } from "./control";
|
|
3
|
+
import type { TextInputProps } from "./types";
|
|
4
|
+
/** RN owns text editing, IME, controlled-value reconciliation and selection on mobile. */
|
|
5
|
+
export function TextInput(props: TextInputProps) {
|
|
6
|
+
const control = useControl(props), state = useTextValue(props);
|
|
7
|
+
return <RNTextInput ref={control.ref} value={state.controlled ? state.text : undefined} defaultValue={state.defaultText}
|
|
8
|
+
onChangeText={text => { if (control.active()) props.onChangeText?.(text); }} editable={!control.disabled} multiline={false}
|
|
9
|
+
accessibilityLabel={props.accessibilityLabel} accessibilityState={{ disabled: control.disabled }} testID={props.testID}
|
|
10
|
+
style={[{ width: 240, height: 44, borderWidth: 1, borderColor: "#8e8e93", borderRadius: 6, paddingHorizontal: 8 }, props.style]} />;
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HostComponent, ViewProps } from "react-native";
|
|
2
|
+
import { codegenNativeComponent } from "react-native";
|
|
3
|
+
import type { DirectEventHandler, Int32 } from "react-native/Libraries/Types/CodegenTypes";
|
|
4
|
+
|
|
5
|
+
export type NativeSegmentedControlChangeEvent = {
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface NativeProps extends ViewProps {
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
selectionRevision?: Int32;
|
|
12
|
+
segmentsJson: string;
|
|
13
|
+
onValueChange?: DirectEventHandler<NativeSegmentedControlChangeEvent>;
|
|
14
|
+
value: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default codegenNativeComponent<NativeProps>("NativeSegmentedControl") as HostComponent<NativeProps>;
|