@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.
Files changed (422) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -4
  3. package/ai-codex.ts +1 -0
  4. package/ai.ts +1 -0
  5. package/app-documents.ts +1 -0
  6. package/camera.ts +13 -0
  7. package/config-plugin.d.cts +2 -0
  8. package/contracts.ts +2 -0
  9. package/diagnostics.ts +1 -0
  10. package/expo-config.d.cts +1 -0
  11. package/metro.cjs +4 -1
  12. package/metro.d.cts +12 -0
  13. package/native.cjs +3 -1
  14. package/native.d.cts +6 -0
  15. package/package.json +93 -15
  16. package/patches/camera/react-native-nitro-image.patch +320 -0
  17. package/patches/camera/react-native-nitro-modules.patch +50 -0
  18. package/patches/camera/react-native-vision-camera.patch +2662 -0
  19. package/patches/camera/upstream.json +22 -0
  20. package/patches/dependencies.json +8 -0
  21. package/patches/react-native-enriched-markdown@1.0.2.patch +8684 -0
  22. package/postinstall.cjs +1 -0
  23. package/schema.json +276 -58
  24. package/settings-observable.ts +1 -0
  25. package/settings-window.ts +1 -0
  26. package/shortcuts-commands.ts +1 -0
  27. package/shortcuts-keyboard.ts +3 -0
  28. package/ui-classnames.ts +1 -0
  29. package/ui-glass.ts +1 -0
  30. package/ui-search.ts +1 -0
  31. package/ui-sidebar.ts +1 -0
  32. package/ui-split-view.ts +1 -0
  33. package/ui-swipe.ts +1 -0
  34. package/ui-symbol.ts +1 -0
  35. package/vendor/node_modules/@legendapp/spark-ai/package.json +19 -0
  36. package/vendor/node_modules/@legendapp/spark-ai/src/availability.ts +17 -0
  37. package/vendor/node_modules/@legendapp/spark-ai/src/index.ts +15 -0
  38. package/vendor/node_modules/@legendapp/spark-ai/src/invocations.ts +34 -0
  39. package/vendor/node_modules/@legendapp/spark-ai/src/output.ts +62 -0
  40. package/vendor/node_modules/@legendapp/spark-ai/src/run.ts +12 -0
  41. package/vendor/node_modules/@legendapp/spark-ai/src/types.ts +16 -0
  42. package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.h +2 -1
  43. package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.mm +126 -24
  44. package/vendor/node_modules/@legendapp/spark-audio/package.json +5 -2
  45. package/vendor/node_modules/@legendapp/spark-audio/src/NativeSparkAudio.ts +5 -1
  46. package/vendor/node_modules/@legendapp/spark-audio/src/desktop.ts +36 -32
  47. package/vendor/node_modules/@legendapp/spark-audio/src/events.ts +11 -0
  48. package/vendor/node_modules/@legendapp/spark-audio/src/hooks.ts +65 -0
  49. package/vendor/node_modules/@legendapp/spark-audio/src/index.web.ts +92 -33
  50. package/vendor/node_modules/@legendapp/spark-audio/src/media-session-unavailable.ts +6 -4
  51. package/vendor/node_modules/@legendapp/spark-audio/src/media-session.ts +52 -19
  52. package/vendor/node_modules/@legendapp/spark-audio/src/media-session.web.ts +18 -10
  53. package/vendor/node_modules/@legendapp/spark-audio/src/media-types.ts +40 -13
  54. package/vendor/node_modules/@legendapp/spark-audio/src/mobile.ts +40 -32
  55. package/vendor/node_modules/@legendapp/spark-audio/src/player.ts +97 -0
  56. package/vendor/node_modules/@legendapp/spark-audio/src/status-listeners.ts +21 -15
  57. package/vendor/node_modules/@legendapp/spark-audio/src/types.ts +9 -4
  58. package/vendor/node_modules/@legendapp/spark-audio/windows/SparkAudio/SparkAudio.h +67 -20
  59. package/vendor/node_modules/@legendapp/spark-auth-session/package.json +4 -3
  60. package/vendor/node_modules/@legendapp/spark-auth-session/src/core.ts +60 -42
  61. package/vendor/node_modules/@legendapp/spark-auth-session/src/index.ts +28 -12
  62. package/vendor/node_modules/@legendapp/spark-auth-session/src/mobile.ts +97 -41
  63. package/vendor/node_modules/@legendapp/spark-auth-session/src/types.ts +20 -9
  64. package/vendor/node_modules/@legendapp/spark-cli/dist/add-desktop.js +50 -7
  65. package/vendor/node_modules/@legendapp/spark-cli/dist/build-mode.js +1 -1
  66. package/vendor/node_modules/@legendapp/spark-cli/dist/build.js +145 -59
  67. package/vendor/node_modules/@legendapp/spark-cli/dist/cli-arguments.js +61 -0
  68. package/vendor/node_modules/@legendapp/spark-cli/dist/commands.js +10 -4
  69. package/vendor/node_modules/@legendapp/spark-cli/dist/create.js +37 -8
  70. package/vendor/node_modules/@legendapp/spark-cli/dist/credentials.js +86 -25
  71. package/vendor/node_modules/@legendapp/spark-cli/dist/dependency-pins.js +132 -0
  72. package/vendor/node_modules/@legendapp/spark-cli/dist/dev-command.js +13 -4
  73. package/vendor/node_modules/@legendapp/spark-cli/dist/dev.js +13 -10
  74. package/vendor/node_modules/@legendapp/spark-cli/dist/errors.js +100 -0
  75. package/vendor/node_modules/@legendapp/spark-cli/dist/examples.js +2 -2
  76. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-dev-patch.cjs +4 -2
  77. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-metro.cjs +1 -1
  78. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-native.cjs +5 -1
  79. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-node.js +3 -3
  80. package/vendor/node_modules/@legendapp/spark-cli/dist/helpers.js +1 -1
  81. package/vendor/node_modules/@legendapp/spark-cli/dist/index.js +52 -44
  82. package/vendor/node_modules/@legendapp/spark-cli/dist/json.js +16 -0
  83. package/vendor/node_modules/@legendapp/spark-cli/dist/local.js +1 -1
  84. package/vendor/node_modules/@legendapp/spark-cli/dist/metro.cjs +26 -5
  85. package/vendor/node_modules/@legendapp/spark-cli/dist/native-metadata.js +26 -0
  86. package/vendor/node_modules/@legendapp/spark-cli/dist/native-patch-preflight.js +86 -0
  87. package/vendor/node_modules/@legendapp/spark-cli/dist/native-preparation.js +88 -0
  88. package/vendor/node_modules/@legendapp/spark-cli/dist/notary-profiles.js +75 -0
  89. package/vendor/node_modules/@legendapp/spark-cli/dist/package.js +4 -2
  90. package/vendor/node_modules/@legendapp/spark-cli/dist/platform.js +16 -2
  91. package/vendor/node_modules/@legendapp/spark-cli/dist/process.js +7 -0
  92. package/vendor/node_modules/@legendapp/spark-cli/dist/project.js +90 -32
  93. package/vendor/node_modules/@legendapp/spark-cli/dist/release.js +86 -5
  94. package/vendor/node_modules/@legendapp/spark-cli/dist/release.json +23 -18
  95. package/vendor/node_modules/@legendapp/spark-cli/dist/runner-install.js +145 -31
  96. package/vendor/node_modules/@legendapp/spark-cli/dist/signing.js +4 -3
  97. package/vendor/node_modules/@legendapp/spark-cli/dist/universal.cjs +2 -1
  98. package/vendor/node_modules/@legendapp/spark-cli/dist/updates.js +41 -4
  99. package/vendor/node_modules/@legendapp/spark-cli/dist/windows.js +5 -9
  100. package/vendor/node_modules/@legendapp/spark-cli/package.json +7 -6
  101. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/App.tsx +6 -12
  102. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/desktop.config.json +5 -3
  103. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/package.json +12 -10
  104. package/vendor/node_modules/@legendapp/spark-cli/templates/diff-lite/Git.macos.tsx +2 -2
  105. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.macos.tsx +23 -21
  106. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.windows.tsx +23 -21
  107. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.desktop.ts +11 -8
  108. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.macos.ts +3 -3
  109. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/Lifecycle.desktop.tsx +8 -14
  110. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/OpenFiles.desktop.tsx +5 -10
  111. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.desktop.ts +11 -8
  112. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.macos.ts +3 -3
  113. package/vendor/node_modules/@legendapp/spark-cli/templates/music-lite/assets.desktop.ts +2 -2
  114. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Activation.desktop.tsx +2 -2
  115. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Desktop.desktop.ts +37 -15
  116. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/session.ts +5 -6
  117. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/window-session.ts +5 -4
  118. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/desktop.config.json +5 -3
  119. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/metro.config.js +1 -1
  120. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/package.json +14 -12
  121. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/react-native.config.js +1 -1
  122. package/vendor/node_modules/@legendapp/spark-cli/templates/windows/package.json +14 -12
  123. package/vendor/node_modules/@legendapp/spark-cli/templates/windows/react-native.config.js +1 -1
  124. package/vendor/node_modules/@legendapp/spark-clipboard/macos/RNDesktopClipboard.mm +10 -16
  125. package/vendor/node_modules/@legendapp/spark-clipboard/package.json +2 -2
  126. package/vendor/node_modules/@legendapp/spark-clipboard/src/NativeDesktopClipboard.ts +1 -1
  127. package/vendor/node_modules/@legendapp/spark-clipboard/src/desktop.ts +55 -31
  128. package/vendor/node_modules/@legendapp/spark-clipboard/src/expo.ts +21 -11
  129. package/vendor/node_modules/@legendapp/spark-clipboard/src/options.ts +8 -0
  130. package/vendor/node_modules/@legendapp/spark-clipboard/src/types.ts +10 -0
  131. package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.h +38 -15
  132. package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.vcxproj +2 -0
  133. package/vendor/node_modules/@legendapp/spark-codex/RNCodex.podspec +22 -0
  134. package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.hpp +23 -0
  135. package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.mm +1529 -0
  136. package/vendor/node_modules/@legendapp/spark-codex/nitro.json +21 -0
  137. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/.gitattributes +1 -0
  138. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex+autolinking.rb +62 -0
  139. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.cpp +17 -0
  140. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.hpp +27 -0
  141. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Umbrella.hpp +38 -0
  142. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.mm +35 -0
  143. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.swift +16 -0
  144. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexAvailability.hpp +95 -0
  145. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexRunResult.hpp +99 -0
  146. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.cpp +24 -0
  147. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.hpp +71 -0
  148. package/vendor/node_modules/@legendapp/spark-codex/package.json +35 -0
  149. package/vendor/node_modules/@legendapp/spark-codex/react-native.config.js +11 -0
  150. package/vendor/node_modules/@legendapp/spark-codex/src/Codex.nitro.ts +30 -0
  151. package/vendor/node_modules/@legendapp/spark-codex/src/index.ts +65 -0
  152. package/vendor/node_modules/@legendapp/spark-codex/src/native.ts +6 -0
  153. package/vendor/node_modules/@legendapp/spark-commands/package.json +21 -0
  154. package/vendor/node_modules/@legendapp/spark-commands/src/bindings.ts +90 -0
  155. package/vendor/node_modules/@legendapp/spark-commands/src/index.tsx +400 -0
  156. package/vendor/node_modules/@legendapp/spark-commands/src/router.ts +138 -0
  157. package/vendor/node_modules/@legendapp/spark-commands/src/storage.ts +20 -0
  158. package/vendor/node_modules/@legendapp/spark-context-menu/macos/RNContextMenu.mm +7 -8
  159. package/vendor/node_modules/@legendapp/spark-context-menu/package.json +4 -3
  160. package/vendor/node_modules/@legendapp/spark-context-menu/src/NativeContextMenu.ts +1 -1
  161. package/vendor/node_modules/@legendapp/spark-context-menu/src/index.ts +26 -26
  162. package/vendor/node_modules/@legendapp/spark-context-menu/windows/SparkContextMenu/SparkContextMenu.h +3 -2
  163. package/vendor/node_modules/@legendapp/spark-desktop-app/RNDesktopApp.podspec +2 -1
  164. package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryJSI.hpp +89 -0
  165. package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryWindows.hpp +22 -0
  166. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/RNDesktopApp.mm +13 -7
  167. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkBinaryJSI.h +48 -0
  168. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.h +4 -0
  169. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.mm +33 -33
  170. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktopError.h +20 -0
  171. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.h +26 -0
  172. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.mm +49 -0
  173. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.h +9 -0
  174. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.mm +70 -0
  175. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkWindow.mm +9 -6
  176. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/recent-documents/RNRecentDocumentController.mm +55 -0
  177. package/vendor/node_modules/@legendapp/spark-desktop-app/package.json +5 -3
  178. package/vendor/node_modules/@legendapp/spark-desktop-app/src/NativeDesktopApp.ts +1 -1
  179. package/vendor/node_modules/@legendapp/spark-desktop-app/src/api.ts +86 -40
  180. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/accelerator.ts +40 -0
  181. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/index.ts +56 -0
  182. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/menu.ts +116 -0
  183. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/native-buffer.ts +22 -0
  184. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/path.ts +24 -0
  185. package/vendor/node_modules/@legendapp/spark-desktop-app/src/events.ts +75 -0
  186. package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.ts +2 -0
  187. package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.windows.ts +2 -0
  188. package/vendor/node_modules/@legendapp/spark-desktop-app/src/open-requests.ts +43 -0
  189. package/vendor/node_modules/@legendapp/spark-desktop-app/src/restoration.ts +11 -0
  190. package/vendor/node_modules/@legendapp/spark-desktop-app/src/transport.ts +10 -0
  191. package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.cjs +10 -5
  192. package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.d.cts +3 -0
  193. package/vendor/node_modules/@legendapp/spark-desktop-config/autolinking.cjs +35 -0
  194. package/vendor/node_modules/@legendapp/spark-desktop-config/config.cjs +18 -3
  195. package/vendor/node_modules/@legendapp/spark-desktop-config/config.d.cts +89 -9
  196. package/vendor/node_modules/@legendapp/spark-desktop-config/expo.cjs +1 -0
  197. package/vendor/node_modules/@legendapp/spark-desktop-config/expo.d.cts +3 -0
  198. package/vendor/node_modules/@legendapp/spark-desktop-config/identity.cjs +3 -2
  199. package/vendor/node_modules/@legendapp/spark-desktop-config/lifecycle.cjs +20 -0
  200. package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.cjs +106 -0
  201. package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.d.cts +1 -0
  202. package/vendor/node_modules/@legendapp/spark-desktop-config/package.json +7 -5
  203. package/vendor/node_modules/@legendapp/spark-desktop-config/schema.json +276 -58
  204. package/vendor/node_modules/@legendapp/spark-desktop-config/updates.cjs +1 -0
  205. package/vendor/node_modules/@legendapp/spark-desktop-config/validation.cjs +35 -0
  206. package/vendor/node_modules/@legendapp/spark-desktop-config/windows.plugin.cjs +2 -1
  207. package/vendor/node_modules/@legendapp/spark-desktop-host/AppDelegate.mm +129 -11
  208. package/vendor/node_modules/@legendapp/spark-desktop-host/package.json +2 -2
  209. package/vendor/node_modules/@legendapp/spark-desktop-host/windows/application.inc +277 -121
  210. package/vendor/node_modules/@legendapp/spark-desktop-links/common/AuthLoopback.h +5 -7
  211. package/vendor/node_modules/@legendapp/spark-desktop-links/macos/RNDesktopLinks.mm +10 -9
  212. package/vendor/node_modules/@legendapp/spark-desktop-links/package.json +2 -2
  213. package/vendor/node_modules/@legendapp/spark-desktop-links/src/NativeDesktopLinks.ts +1 -1
  214. package/vendor/node_modules/@legendapp/spark-desktop-links/src/api.ts +27 -33
  215. package/vendor/node_modules/@legendapp/spark-desktop-links/src/expo.ts +3 -4
  216. package/vendor/node_modules/@legendapp/spark-desktop-links/src/native.ts +9 -0
  217. package/vendor/node_modules/@legendapp/spark-desktop-links/windows/SparkLinks/SparkLinks.h +22 -22
  218. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/RNDesktopShortcuts.podspec +1 -0
  219. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/RNDesktopShortcuts.mm +1 -1
  220. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.h +9 -0
  221. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.mm +307 -0
  222. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/package.json +8 -5
  223. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/NativeDesktopShortcuts.ts +1 -1
  224. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/api.ts +39 -14
  225. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/NativeKeyboardManager.ts +12 -0
  226. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/codes.ts +108 -0
  227. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/index.ts +99 -0
  228. package/vendor/node_modules/@legendapp/spark-desktop-windows/RNDesktopWindows.podspec +2 -0
  229. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/RNDesktopWindows.mm +229 -103
  230. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/SparkWindowGeometry.h +63 -0
  231. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.h +20 -0
  232. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.mm +27 -0
  233. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.h +12 -0
  234. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.mm +3169 -0
  235. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManagerStartup.mm +31 -0
  236. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/SidebarStartupFallbacks.mm +14 -0
  237. package/vendor/node_modules/@legendapp/spark-desktop-windows/package.json +10 -6
  238. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/NativeDesktopWindowManager.ts +1 -1
  239. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/api.ts +146 -70
  240. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/diagnostics.ts +17 -0
  241. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.ts +3 -1
  242. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.windows.ts +3 -1
  243. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos-adapter.ts +53 -0
  244. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos.ts +51 -0
  245. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/transport.ts +41 -0
  246. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/types.ts +140 -0
  247. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/validation.ts +162 -0
  248. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/window-manager/NativeWindowManager.ts +28 -0
  249. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/WindowProvider.tsx +20 -0
  250. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/createWindowsNavigator.tsx +78 -0
  251. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/index.ts +6 -0
  252. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle.ts +34 -0
  253. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/types.ts +11 -0
  254. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/usePrimaryWindowLifecycle.ts +18 -0
  255. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/useWindowFocusEffect.ts +17 -0
  256. package/vendor/node_modules/@legendapp/spark-documents/package.json +22 -0
  257. package/vendor/node_modules/@legendapp/spark-documents/src/controller.ts +97 -0
  258. package/vendor/node_modules/@legendapp/spark-documents/src/documentTransition.ts +13 -0
  259. package/vendor/node_modules/@legendapp/spark-documents/src/hooks.ts +139 -0
  260. package/vendor/node_modules/@legendapp/spark-documents/src/index.tsx +50 -0
  261. package/vendor/node_modules/@legendapp/spark-documents/src/reload.ts +39 -0
  262. package/vendor/node_modules/@legendapp/spark-documents/src/requests.ts +15 -0
  263. package/vendor/node_modules/@legendapp/spark-drag-drop/package.json +4 -3
  264. package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts +1 -1
  265. package/vendor/node_modules/@legendapp/spark-drag-drop/src/contracts.ts +73 -18
  266. package/vendor/node_modules/@legendapp/spark-drag-drop/src/index.tsx +58 -15
  267. package/vendor/node_modules/@legendapp/spark-drag-drop/windows/SparkDragDrop/SparkDragDrop.h +14 -8
  268. package/vendor/node_modules/@legendapp/spark-file-dialog/ios/RNFileDialog.mm +34 -121
  269. package/vendor/node_modules/@legendapp/spark-file-dialog/package.json +12 -5
  270. package/vendor/node_modules/@legendapp/spark-file-dialog/src/NativeFileDialog.ts +1 -5
  271. package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.ts +19 -84
  272. package/vendor/node_modules/@legendapp/spark-file-dialog/src/native.ts +12 -0
  273. package/vendor/node_modules/@legendapp/spark-file-dialog/src/options.ts +34 -14
  274. package/vendor/node_modules/@legendapp/spark-file-dialog/src/types.ts +26 -0
  275. package/vendor/node_modules/@legendapp/spark-file-dialog/windows/SparkFileDialog/SparkFileDialog.h +42 -58
  276. package/vendor/node_modules/@legendapp/spark-file-system/RNDesktopFileSystem.podspec +1 -0
  277. package/vendor/node_modules/@legendapp/spark-file-system/macos/RNDesktopFileSystem.mm +32 -21
  278. package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.h +24 -0
  279. package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.mm +215 -0
  280. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.h +9 -0
  281. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.mm +82 -0
  282. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.h +47 -0
  283. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm +306 -0
  284. package/vendor/node_modules/@legendapp/spark-file-system/package.json +8 -6
  285. package/vendor/node_modules/@legendapp/spark-file-system/src/NativeDesktopFileSystem.ts +1 -1
  286. package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts +11 -0
  287. package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/index.ts +93 -0
  288. package/vendor/node_modules/@legendapp/spark-file-system/src/handles.ts +48 -14
  289. package/vendor/node_modules/@legendapp/spark-file-system/src/index.ts +134 -45
  290. package/vendor/node_modules/@legendapp/spark-file-system/src/path.ts +1 -9
  291. package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.h +102 -26
  292. package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.vcxproj +2 -0
  293. package/vendor/node_modules/@legendapp/spark-global-shortcuts/RNDesktopGlobalShortcuts.podspec +1 -0
  294. package/vendor/node_modules/@legendapp/spark-global-shortcuts/macos/RNDesktopGlobalShortcuts.mm +7 -4
  295. package/vendor/node_modules/@legendapp/spark-global-shortcuts/package.json +4 -3
  296. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/NativeDesktopGlobalShortcuts.ts +1 -1
  297. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/index.ts +39 -10
  298. package/vendor/node_modules/@legendapp/spark-global-shortcuts/windows/SparkGlobalShortcuts/SparkGlobalShortcuts.h +5 -4
  299. package/vendor/node_modules/@legendapp/spark-message-dialog/macos/RNDesktopMessageDialog.mm +2 -2
  300. package/vendor/node_modules/@legendapp/spark-message-dialog/package.json +2 -2
  301. package/vendor/node_modules/@legendapp/spark-message-dialog/src/NativeDesktopMessageDialog.ts +1 -1
  302. package/vendor/node_modules/@legendapp/spark-message-dialog/src/index.ts +48 -11
  303. package/vendor/node_modules/@legendapp/spark-native-menu/ios/RNNativeMenu.mm +141 -609
  304. package/vendor/node_modules/@legendapp/spark-native-menu/package.json +9 -4
  305. package/vendor/node_modules/@legendapp/spark-native-menu/src/NativeMenu.ts +2 -7
  306. package/vendor/node_modules/@legendapp/spark-native-menu/src/api.ts +76 -121
  307. package/vendor/node_modules/@legendapp/spark-native-menu/src/hooks.ts +97 -0
  308. package/vendor/node_modules/@legendapp/spark-native-menu/src/windows-menus.ts +43 -37
  309. package/vendor/node_modules/@legendapp/spark-notifications/macos/RNDesktopNotifications.mm +75 -30
  310. package/vendor/node_modules/@legendapp/spark-notifications/package.json +2 -2
  311. package/vendor/node_modules/@legendapp/spark-notifications/src/NativeDesktopNotifications.ts +1 -1
  312. package/vendor/node_modules/@legendapp/spark-notifications/src/index.ts +130 -42
  313. package/vendor/node_modules/@legendapp/spark-notifications/windows/SparkNotifications/SparkNotifications.h +51 -8
  314. package/vendor/node_modules/@legendapp/spark-processes/macos/RNDesktopProcesses.mm +94 -21
  315. package/vendor/node_modules/@legendapp/spark-processes/package.json +4 -3
  316. package/vendor/node_modules/@legendapp/spark-processes/src/NativeDesktopProcesses.ts +1 -1
  317. package/vendor/node_modules/@legendapp/spark-processes/src/index.ts +124 -28
  318. package/vendor/node_modules/@legendapp/spark-processes/src/types.ts +34 -0
  319. package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.h +83 -34
  320. package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.vcxproj +2 -0
  321. package/vendor/node_modules/@legendapp/spark-secure-storage/macos/RNDesktopSecureStorage.mm +49 -40
  322. package/vendor/node_modules/@legendapp/spark-secure-storage/package.json +2 -2
  323. package/vendor/node_modules/@legendapp/spark-secure-storage/src/NativeDesktopSecureStorage.ts +1 -1
  324. package/vendor/node_modules/@legendapp/spark-secure-storage/src/desktop.ts +16 -14
  325. package/vendor/node_modules/@legendapp/spark-secure-storage/src/expo.ts +0 -1
  326. package/vendor/node_modules/@legendapp/spark-secure-storage/src/options.ts +3 -2
  327. package/vendor/node_modules/@legendapp/spark-secure-storage/src/unavailable.ts +6 -3
  328. package/vendor/node_modules/@legendapp/spark-settings/package.json +10 -3
  329. package/vendor/node_modules/@legendapp/spark-settings/src/fileStorage.ts +11 -0
  330. package/vendor/node_modules/@legendapp/spark-settings/src/index.ts +7 -9
  331. package/vendor/node_modules/@legendapp/spark-settings/src/storage/index.ts +142 -0
  332. package/vendor/node_modules/@legendapp/spark-settings/src/store.ts +63 -21
  333. package/vendor/node_modules/@legendapp/spark-settings-ui/package.json +20 -0
  334. package/vendor/node_modules/@legendapp/spark-settings-ui/src/index.tsx +436 -0
  335. package/vendor/node_modules/@legendapp/spark-settings-ui/src/options.ts +10 -0
  336. package/vendor/node_modules/@legendapp/spark-sqlite/package.json +3 -3
  337. package/vendor/node_modules/@legendapp/spark-sqlite/src/database.ts +182 -0
  338. package/vendor/node_modules/@legendapp/spark-sqlite/src/index.ts +19 -6
  339. package/vendor/node_modules/@legendapp/spark-sqlite/src/types.ts +22 -0
  340. package/vendor/node_modules/@legendapp/spark-system/macos/RNDesktopSystem.mm +36 -11
  341. package/vendor/node_modules/@legendapp/spark-system/package.json +2 -2
  342. package/vendor/node_modules/@legendapp/spark-system/src/NativeDesktopSystem.ts +1 -1
  343. package/vendor/node_modules/@legendapp/spark-system/src/index.ts +89 -32
  344. package/vendor/node_modules/@legendapp/spark-system/windows/SparkSystem/SparkSystem.h +8 -4
  345. package/vendor/node_modules/@legendapp/spark-tray/macos/RNDesktopTray.mm +20 -8
  346. package/vendor/node_modules/@legendapp/spark-tray/package.json +2 -2
  347. package/vendor/node_modules/@legendapp/spark-tray/src/NativeDesktopTray.ts +1 -1
  348. package/vendor/node_modules/@legendapp/spark-tray/src/index.ts +91 -34
  349. package/vendor/node_modules/@legendapp/spark-tray/windows/SparkTray/SparkTray.h +45 -15
  350. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkButton.mm +2 -1
  351. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkTextInput.mm +10 -2
  352. package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.h +15 -0
  353. package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.mm +1419 -0
  354. package/vendor/node_modules/@legendapp/spark-ui/macos/glass-effect-view/RNGlassEffectView.mm +72 -0
  355. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.h +15 -0
  356. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.mm +194 -0
  357. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.h +15 -0
  358. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.mm +180 -0
  359. package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.h +15 -0
  360. package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.mm +155 -0
  361. package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.h +18 -0
  362. package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.mm +645 -0
  363. package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.h +10 -0
  364. package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.mm +422 -0
  365. package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.h +15 -0
  366. package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.mm +164 -0
  367. package/vendor/node_modules/@legendapp/spark-ui/package.json +17 -4
  368. package/vendor/node_modules/@legendapp/spark-ui/src/SparkSelectNativeComponent.ts +3 -1
  369. package/vendor/node_modules/@legendapp/spark-ui/src/SparkTextInputNativeComponent.ts +6 -2
  370. package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/SidebarSplitViewNativeComponent.ts +37 -0
  371. package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/index.tsx +86 -0
  372. package/vendor/node_modules/@legendapp/spark-ui/src/availability.ts +10 -0
  373. package/vendor/node_modules/@legendapp/spark-ui/src/classnames/index.ts +8 -0
  374. package/vendor/node_modules/@legendapp/spark-ui/src/control.ts +42 -0
  375. package/vendor/node_modules/@legendapp/spark-ui/src/desktop.tsx +56 -0
  376. package/vendor/node_modules/@legendapp/spark-ui/src/glass-effect-view/index.tsx +15 -0
  377. package/vendor/node_modules/@legendapp/spark-ui/src/index.android.tsx +35 -21
  378. package/vendor/node_modules/@legendapp/spark-ui/src/index.ios.tsx +55 -26
  379. package/vendor/node_modules/@legendapp/spark-ui/src/index.tsx +1 -27
  380. package/vendor/node_modules/@legendapp/spark-ui/src/index.web.tsx +45 -14
  381. package/vendor/node_modules/@legendapp/spark-ui/src/index.windows.tsx +1 -42
  382. package/vendor/node_modules/@legendapp/spark-ui/src/mobile-input.tsx +11 -0
  383. package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSegmentedControlNativeComponent.ts +17 -0
  384. package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSelectNativeComponent.ts +17 -0
  385. package/vendor/node_modules/@legendapp/spark-ui/src/select.ts +5 -3
  386. package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/SFSymbolNativeComponent.ts +13 -0
  387. package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/index.tsx +27 -0
  388. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarItemNativeComponent.ts +25 -0
  389. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarNativeComponent.ts +24 -0
  390. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/index.tsx +104 -0
  391. package/vendor/node_modules/@legendapp/spark-ui/src/specialized.ts +22 -0
  392. package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/SwipeActionsNativeComponent.ts +11 -0
  393. package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/index.tsx +41 -0
  394. package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/TextInputSearchNativeComponent.ts +33 -0
  395. package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/index.tsx +34 -0
  396. package/vendor/node_modules/@legendapp/spark-ui/src/types.ts +30 -19
  397. package/vendor/node_modules/@legendapp/spark-ui/uniwind.ts +3 -1
  398. package/vendor/node_modules/@legendapp/spark-ui/uniwind.web.ts +3 -1
  399. package/vendor/node_modules/@legendapp/spark-ui/windows/SparkUI/SparkUI.h +16 -11
  400. package/vendor/node_modules/@legendapp/spark-updates/macos/RNDesktopUpdates.mm +21 -8
  401. package/vendor/node_modules/@legendapp/spark-updates/package.json +2 -2
  402. package/vendor/node_modules/@legendapp/spark-updates/src/NativeDesktopUpdates.ts +3 -2
  403. package/vendor/node_modules/@legendapp/spark-updates/src/index.ts +71 -15
  404. package/vendor/node_modules/@legendapp/spark-webview/package.json +2 -2
  405. package/vendor/node_modules/@legendapp/spark-webview/src/WebView.tsx +11 -0
  406. package/vendor/node_modules/@legendapp/spark-webview/src/adapter.ts +55 -0
  407. package/vendor/node_modules/@legendapp/spark-webview/src/index.ts +2 -2
  408. package/vendor/node_modules/@legendapp/spark-webview/src/types.ts +32 -0
  409. package/vendor/node_modules/@legendapp/spark-webview/src/view-props.ts +28 -0
  410. package/vendor/node_modules/@legendapp/spark-window-options/index.cjs +51 -14
  411. package/vendor/node_modules/@legendapp/spark-window-options/index.d.ts +21 -8
  412. package/vendor/node_modules/@legendapp/spark-window-options/package.json +1 -1
  413. package/windows-macos.ts +1 -0
  414. package/expo-metro.cjs +0 -1
  415. package/message-dialog.ts +0 -1
  416. package/universal.cjs +0 -1
  417. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/accelerator.ts +0 -22
  418. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows-options.ts +0 -11
  419. package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.windows.ts +0 -15
  420. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/accelerator.ts +0 -22
  421. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.h +0 -4
  422. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.mm +0 -53
@@ -78,7 +78,11 @@ struct DragView : implements<DragView, Windows::Foundation::IInspectable> {
78
78
  }
79
79
  return Operation::None;
80
80
  }
81
- void Fail(hresult_error const &error) { failure = to_string(error.message()); Json::JsonObject value; value.SetNamedValue(L"message", Json::JsonValue::CreateStringValue(error.message())); Emit(L"unavailable", value); }
81
+ void Fail(hresult_error const &error, bool unavailable = false) {
82
+ if (unavailable) failure = to_string(error.message());
83
+ Json::JsonObject value; value.SetNamedValue(L"message", Json::JsonValue::CreateStringValue(error.message()));
84
+ value.SetNamedValue(L"unavailable", Json::JsonValue::CreateBooleanValue(unavailable)); Emit(L"error", value);
85
+ }
82
86
  fire_and_forget Start(Microsoft::UI::Input::PointerPoint point, Composition::Input::Pointer pointer) {
83
87
  auto keepAlive = get_strong();
84
88
  Operation resultOperation = Operation::None;
@@ -103,7 +107,7 @@ struct DragView : implements<DragView, Windows::Foundation::IInspectable> {
103
107
  data.SetStorageItems(items);
104
108
  }
105
109
  if (mounted && !disabled && root == session) resultOperation = co_await operation.StartAsync(session->manager, point);
106
- } catch (hresult_error const &error) { /* Failed or cancelled sources report accepted=false. */ }
110
+ } catch (hresult_error const &error) { if (error.code() != E_ABORT && error.code() != HRESULT_FROM_WIN32(ERROR_CANCELLED)) Fail(error); }
107
111
  if (auto strong = view.get()) strong.ReleasePointerCapture(pointer);
108
112
  if (operation) { try { operation.Close(); } catch (...) {} operation = nullptr; }
109
113
  dragging = false; Json::JsonObject result; result.SetNamedValue(L"accepted", Json::JsonValue::CreateBooleanValue(resultOperation != Operation::None)); result.SetNamedValue(L"operation", Json::JsonValue::CreateStringValue(OperationName(resultOperation))); Emit(L"dragEnd", result);
@@ -146,8 +150,9 @@ struct DropTarget : implements<DropTarget, Drag::IDropOperationTarget> {
146
150
  DropTarget(std::shared_ptr<RootState> value) : root(std::move(value)) {}
147
151
  IAsyncOperation<Operation> OverAsync(Drag::DragInfo info, Drag::DragUIOverride) {
148
152
  auto keepAlive = get_strong(); co_await root->ui;
153
+ com_ptr<DragView> target;
149
154
  try {
150
- auto target = root->Target(info.Position());
155
+ target = root->Target(info.Position());
151
156
  auto operation = target ? target->Accept(info) : Operation::None;
152
157
  if (operation == Operation::None) target = nullptr;
153
158
  auto previous = current.get();
@@ -160,19 +165,20 @@ struct DropTarget : implements<DropTarget, Drag::IDropOperationTarget> {
160
165
  over.SetNamedValue(L"x", Json::JsonValue::CreateNumberValue(point.X)); over.SetNamedValue(L"y", Json::JsonValue::CreateNumberValue(point.Y));
161
166
  over.SetNamedValue(L"operation", Json::JsonValue::CreateStringValue(OperationName(operation))); target->Emit(L"dragOver", over);
162
167
  co_return operation;
163
- } catch (...) { co_return Operation::None; }
168
+ } catch (hresult_error const &error) { if (target) target->Fail(error); co_return Operation::None; }
164
169
  }
165
170
  IAsyncOperation<Operation> EnterAsync(Drag::DragInfo info, Drag::DragUIOverride ui) { return OverAsync(info, ui); }
166
171
  IAsyncAction LeaveAsync(Drag::DragInfo) { auto keepAlive = get_strong(); co_await root->ui; if (auto previous = current.get()) previous->Emit(L"dragLeave"); current = {}; co_return; }
167
172
  IAsyncOperation<Operation> DropAsync(Drag::DragInfo info) {
168
173
  auto keepAlive = get_strong(); co_await root->ui;
174
+ com_ptr<DragView> target;
169
175
  try {
170
- auto target = root->Target(info.Position());
176
+ target = root->Target(info.Position());
171
177
  auto operation = target ? target->Accept(info) : Operation::None; if (operation == Operation::None) co_return operation;
172
178
  auto payload = co_await Payload(info, target->Local(info.Position()), target->Types(), operation);
173
179
  if (target->Accept(info) != operation) co_return Operation::None;
174
180
  target->Emit(L"drop", payload); current = {}; co_return operation;
175
- } catch (...) { co_return Operation::None; }
181
+ } catch (hresult_error const &error) { if (target) target->Fail(error); co_return Operation::None; }
176
182
  }
177
183
  };
178
184
  inline std::shared_ptr<RootState> ForRoot(Composition::RootComponentView const &root) {
@@ -189,7 +195,7 @@ inline void Register(React::IReactPackageBuilder const &package) {
189
195
  builder.SetCreateProps([](React::ViewProps const &view, React::IComponentProps const &previous) { auto props = make_self<Props>(); if (previous) { auto old = get_self<Props>(previous); props->source = old->source; props->options = old->options; props->disabled = old->disabled; } props->view = view; return props.as<React::IComponentProps>(); });
190
196
  builder.as<Composition::IReactCompositionViewComponentBuilder>().SetViewComponentViewInitializer([](Composition::ViewComponentView const &view) {
191
197
  auto state = make_self<DragView>(); state->view = view; view.UserData(state.as<Windows::Foundation::IInspectable>()); auto weak = state->get_weak();
192
- view.Mounted([weak](auto const &, React::ComponentView const &) { if (auto self = weak.get()) try { self->mounted = true; auto view = self->view.get(); self->root = ForRoot(view.Root()); self->root->views[view.Tag()] = self->get_weak(); } catch (hresult_error const &error) { self->Fail(error); } });
198
+ view.Mounted([weak](auto const &, React::ComponentView const &) { if (auto self = weak.get()) try { self->mounted = true; auto view = self->view.get(); self->root = ForRoot(view.Root()); self->root->views[view.Tag()] = self->get_weak(); } catch (hresult_error const &error) { self->Fail(error, true); } });
193
199
  view.Unmounted([weak](auto const &, auto const &) { if (auto self = weak.get()) self->Close(); });
194
200
  view.Destroying([weak](auto const &, auto const &) { if (auto self = weak.get()) self->Close(true); });
195
201
  view.PointerPressed([weak](auto const &, Composition::Input::PointerRoutedEventArgs const &args) { if (auto self = weak.get(); self && !args.Handled() && !self->disabled && !self->source.empty()) { auto point = args.GetCurrentPoint(self->view.get().Tag()); self->pressed = point.Properties().IsLeftButtonPressed(); self->origin = point.Position(); } });
@@ -203,7 +209,7 @@ inline void Register(React::IReactPackageBuilder const &package) {
203
209
  });
204
210
  });
205
211
  builder.SetUpdatePropsHandler([](React::ComponentView const &view, React::IComponentProps const &props, React::IComponentProps const &) { auto state = get_self<DragView>(view.UserData()); auto value = get_self<Props>(props); state->source = value->source; state->options = value->options; state->disabled = value->disabled; });
206
- builder.SetUpdateEventEmitterHandler([](React::ComponentView const &view, React::EventEmitter const &emitter) { auto state = get_self<DragView>(view.UserData()); state->emitter = emitter; if (!state->failure.empty()) { Json::JsonObject error; error.SetNamedValue(L"message", Json::JsonValue::CreateStringValue(to_hstring(state->failure))); state->Emit(L"unavailable", error); } });
212
+ builder.SetUpdateEventEmitterHandler([](React::ComponentView const &view, React::EventEmitter const &emitter) { auto state = get_self<DragView>(view.UserData()); state->emitter = emitter; if (!state->failure.empty()) { Json::JsonObject error; error.SetNamedValue(L"message", Json::JsonValue::CreateStringValue(to_hstring(state->failure))); error.SetNamedValue(L"unavailable", Json::JsonValue::CreateBooleanValue(true)); state->Emit(L"error", error); } });
207
213
  });
208
214
  }
209
215
  }
@@ -47,6 +47,12 @@ RCT_EXPORT_MODULE(NativeFileDialog)
47
47
  RCTExecuteOnMainQueue(^{
48
48
  if (self.activePanel) { reject(@"E_BUSY", @"A file dialog is already open", nil); return; }
49
49
  NSDictionary *options = [self parseObjectJSON:optionsJson];
50
+ NSWindow *parent = nil;
51
+ if (options[@"windowId"]) {
52
+ for (NSWindow *candidate in NSApp.windows) if ([candidate.identifier isEqual:options[@"windowId"]] || [candidate.identifier isEqual:[@"spark." stringByAppendingString:options[@"windowId"]]]) { parent = candidate; break; }
53
+ if (!parent) { reject(@"E_NOT_FOUND", @"Dialog owner does not exist", nil); return; }
54
+ if (parent.attachedSheet) { reject(@"E_BUSY", @"Dialog owner already has a sheet", nil); return; }
55
+ }
50
56
  NSOpenPanel *panel = [NSOpenPanel openPanel];
51
57
  self.activePanel = panel;
52
58
  panel.canChooseFiles = options[@"canChooseFiles"] ? [options[@"canChooseFiles"] boolValue] : YES;
@@ -84,13 +90,15 @@ RCT_EXPORT_MODULE(NativeFileDialog)
84
90
  }
85
91
  }
86
92
 
87
- [panel beginWithCompletionHandler:^(NSModalResponse result) {
93
+ void (^complete)(NSModalResponse) = ^(NSModalResponse result) {
88
94
  self.activePanel = nil;
89
95
  if (result != NSModalResponseOK) { resolve(@"null"); return; }
90
96
  NSMutableArray<NSString *> *paths = [NSMutableArray arrayWithCapacity:panel.URLs.count];
91
97
  for (NSURL *url in panel.URLs) if (url.path.length > 0) [paths addObject:url.path];
92
98
  resolve([self jsonStringFromObject:paths]);
93
- }];
99
+ };
100
+ if (parent) [panel beginSheetModalForWindow:parent completionHandler:complete];
101
+ else [panel beginWithCompletionHandler:complete];
94
102
  });
95
103
  #else
96
104
  resolve(@"null");
@@ -103,34 +111,51 @@ RCT_EXPORT_MODULE(NativeFileDialog)
103
111
  RCTExecuteOnMainQueue(^{
104
112
  if (self.activePanel) { reject(@"E_BUSY", @"A file dialog is already open", nil); return; }
105
113
  NSDictionary *options = [self parseObjectJSON:optionsJson];
114
+ NSWindow *parent = nil;
115
+ if (options[@"windowId"]) {
116
+ for (NSWindow *candidate in NSApp.windows) if ([candidate.identifier isEqual:options[@"windowId"]] || [candidate.identifier isEqual:[@"spark." stringByAppendingString:options[@"windowId"]]]) { parent = candidate; break; }
117
+ if (!parent) { reject(@"E_NOT_FOUND", @"Dialog owner does not exist", nil); return; }
118
+ if (parent.attachedSheet) { reject(@"E_BUSY", @"Dialog owner already has a sheet", nil); return; }
119
+ }
106
120
  NSSavePanel *panel = [NSSavePanel savePanel];
107
121
  self.activePanel = panel;
108
122
  panel.canCreateDirectories = YES;
109
123
  panel.showsTagField = NO;
110
124
 
111
- NSString *defaultName = [options[@"defaultName"] isKindOfClass:[NSString class]] ? options[@"defaultName"] : nil;
112
- if (defaultName.length > 0) {
113
- panel.nameFieldStringValue = defaultName;
114
- }
125
+ NSString *defaultName = [options[@"defaultName"] isKindOfClass:[NSString class]] && [(NSString *)options[@"defaultName"] length] > 0 ? options[@"defaultName"] : nil;
115
126
 
116
127
  NSArray *allowedFileTypes = [options[@"allowedFileTypes"] isKindOfClass:[NSArray class]] ? options[@"allowedFileTypes"] : nil;
117
128
  if (allowedFileTypes.count > 0) {
118
129
  panel.allowedFileTypes = allowedFileTypes;
119
130
  }
120
131
 
132
+ // defaultPath may name a file: a live directory starts the panel, otherwise the
133
+ // last component suggests the name (an explicit defaultName wins) and the parent starts it.
121
134
  NSString *directory = [options[@"directory"] isKindOfClass:[NSString class]] ? options[@"directory"] : nil;
122
135
  if (directory.length > 0) {
123
- panel.directoryURL = [NSURL fileURLWithPath:directory isDirectory:YES];
136
+ BOOL isDirectory = NO;
137
+ if ([[NSFileManager defaultManager] fileExistsAtPath:directory isDirectory:&isDirectory] && isDirectory) {
138
+ panel.directoryURL = [NSURL fileURLWithPath:directory isDirectory:YES];
139
+ } else {
140
+ NSString *parent = [directory stringByDeletingLastPathComponent];
141
+ if (defaultName.length == 0) defaultName = [directory lastPathComponent];
142
+ if (parent.length > 0) panel.directoryURL = [NSURL fileURLWithPath:parent isDirectory:YES];
143
+ }
144
+ }
145
+ if (defaultName.length > 0) {
146
+ panel.nameFieldStringValue = defaultName;
124
147
  }
125
148
 
126
- [panel beginWithCompletionHandler:^(NSModalResponse result) {
149
+ void (^complete)(NSModalResponse) = ^(NSModalResponse result) {
127
150
  self.activePanel = nil;
128
151
  if (result == NSModalResponseOK && panel.URL.path.length > 0) {
129
152
  resolve([self jsonStringFromObject:panel.URL.path]);
130
153
  } else {
131
154
  resolve(@"null");
132
155
  }
133
- }];
156
+ };
157
+ if (parent) [panel beginSheetModalForWindow:parent completionHandler:complete];
158
+ else [panel beginWithCompletionHandler:complete];
134
159
  });
135
160
  #else
136
161
  resolve(@"null");
@@ -144,116 +169,4 @@ RCT_EXPORT_MODULE(NativeFileDialog)
144
169
  #endif
145
170
  }
146
171
 
147
- - (void)revealInFinder:(NSString *)path resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
148
- {
149
- #if TARGET_OS_OSX
150
- RCTExecuteOnMainQueue(^{
151
- if (path.length == 0) {
152
- resolve(@NO);
153
- return;
154
- }
155
-
156
- NSString *expandedPath = [path stringByExpandingTildeInPath];
157
- NSURL *inputURL = [NSURL URLWithString:expandedPath];
158
- NSURL *fileURL = inputURL.isFileURL ? inputURL : [NSURL fileURLWithPath:expandedPath];
159
- if (!fileURL.path.length || ![[NSFileManager defaultManager] fileExistsAtPath:fileURL.path]) {
160
- resolve(@NO);
161
- return;
162
- }
163
-
164
- [[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[fileURL]];
165
- resolve(@YES);
166
- });
167
- #else
168
- resolve(@NO);
169
- #endif
170
- }
171
-
172
- - (void)readTextFile:(NSString *)path resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
173
- {
174
- #if TARGET_OS_OSX
175
- RCTExecuteOnMainQueue(^{
176
- if (path.length == 0) {
177
- reject(@"invalid_path", @"Cannot read file without a path.", nil);
178
- return;
179
- }
180
-
181
- NSString *expandedPath = [path stringByExpandingTildeInPath];
182
- NSError *error = nil;
183
- NSString *contents = [NSString stringWithContentsOfFile:expandedPath encoding:NSUTF8StringEncoding error:&error];
184
- if (!contents) {
185
- reject(@"read_failed", error.localizedDescription ?: @"Failed to read file.", error);
186
- return;
187
- }
188
-
189
- resolve(contents);
190
- });
191
- #else
192
- resolve(@"");
193
- #endif
194
- }
195
-
196
- - (void)writeTextFile:(NSString *)path contents:(NSString *)contents resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
197
- {
198
- #if TARGET_OS_OSX
199
- RCTExecuteOnMainQueue(^{
200
- if (path.length == 0) {
201
- reject(@"invalid_path", @"Cannot write file without a path.", nil);
202
- return;
203
- }
204
-
205
- NSString *expandedPath = [path stringByExpandingTildeInPath];
206
- NSError *error = nil;
207
- BOOL ok = [contents writeToFile:expandedPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
208
- if (!ok) {
209
- reject(@"write_failed", error.localizedDescription ?: @"Failed to write file.", error);
210
- return;
211
- }
212
-
213
- resolve(nil);
214
- });
215
- #else
216
- resolve(nil);
217
- #endif
218
- }
219
-
220
- - (void)writeTextFileIfUnchanged:(NSString *)path
221
- expectedContents:(NSString *)expectedContents
222
- contents:(NSString *)contents
223
- resolve:(RCTPromiseResolveBlock)resolve
224
- reject:(RCTPromiseRejectBlock)reject
225
- {
226
- #if TARGET_OS_OSX
227
- RCTExecuteOnMainQueue(^{
228
- if (path.length == 0) {
229
- reject(@"invalid_path", @"Cannot write file without a path.", nil);
230
- return;
231
- }
232
-
233
- NSString *expandedPath = [path stringByExpandingTildeInPath];
234
- NSError *readError = nil;
235
- NSString *currentContents = [NSString stringWithContentsOfFile:expandedPath encoding:NSUTF8StringEncoding error:&readError];
236
- if (!currentContents) {
237
- reject(@"read_failed", readError.localizedDescription ?: @"Failed to read file.", readError);
238
- return;
239
- }
240
- if (![currentContents isEqualToString:expectedContents ?: @""]) {
241
- resolve(@NO);
242
- return;
243
- }
244
-
245
- NSError *writeError = nil;
246
- BOOL ok = [contents writeToFile:expandedPath atomically:YES encoding:NSUTF8StringEncoding error:&writeError];
247
- if (!ok) {
248
- reject(@"write_failed", writeError.localizedDescription ?: @"Failed to write file.", writeError);
249
- return;
250
- }
251
-
252
- resolve(@YES);
253
- });
254
- #else
255
- resolve(@NO);
256
- #endif
257
- }
258
-
259
172
  @end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/spark-file-dialog",
3
- "version": "0.0.1-next.2",
3
+ "version": "0.0.1-next.4",
4
4
  "main": "src/index",
5
5
  "react-native": "src/index",
6
6
  "codegenConfig": {
@@ -13,7 +13,8 @@
13
13
  "ios": {
14
14
  "modulesProvider": {
15
15
  "NativeFileDialog": "RNFileDialog"
16
- }
16
+ },
17
+ "componentProvider": {}
17
18
  }
18
19
  },
19
20
  "peerDependencies": {
@@ -25,7 +26,8 @@
25
26
  "src",
26
27
  "ios",
27
28
  "*.podspec",
28
- "windows"
29
+ "windows",
30
+ "macos"
29
31
  ],
30
32
  "spark": {
31
33
  "sdk": true,
@@ -37,7 +39,12 @@
37
39
  "macos",
38
40
  "windows"
39
41
  ],
40
- "requires": []
42
+ "requires": [
43
+ "@legendapp/spark-desktop-app"
44
+ ]
41
45
  },
42
- "private": true
46
+ "private": true,
47
+ "dependencies": {
48
+ "@legendapp/spark-desktop-app": "0.0.1-next.4"
49
+ }
43
50
  }
@@ -3,11 +3,7 @@ import { TurboModuleRegistry } from "react-native";
3
3
 
4
4
  export interface Spec extends TurboModule {
5
5
  open(optionsJson: string): Promise<string>;
6
- readTextFile(path: string): Promise<string>;
7
6
  save(optionsJson: string): Promise<string>;
8
- revealInFinder(path: string): Promise<boolean>;
9
- writeTextFile(path: string, contents: string): Promise<void>;
10
- writeTextFileIfUnchanged(path: string, expectedContents: string, contents: string): Promise<boolean>;
11
7
  }
12
8
 
13
- export default TurboModuleRegistry.getEnforcing<Spec>("NativeFileDialog");
9
+ export default TurboModuleRegistry.get<Spec>("NativeFileDialog");
@@ -1,89 +1,24 @@
1
- import { validateDialogOptions } from "./options";
1
+ import { absolutePath } from "@legendapp/spark-desktop-app/src/contracts/path";
2
2
  import { Platform } from "react-native";
3
- import NativeFileDialog from "./NativeFileDialog";
4
-
5
- export type FileDialogOpenOptions = {
6
- canChooseFiles?: boolean;
7
- canChooseDirectories?: boolean;
8
- allowsMultipleSelection?: boolean;
9
- directoryURL?: string | null;
10
- allowedFileTypes?: string[];
11
- message?: string;
12
- prompt?: string;
13
- title?: string;
14
- };
15
-
16
- export type FileDialogSaveOptions = {
17
- defaultName?: string;
18
- directory?: string;
19
- allowedFileTypes?: string[];
20
- };
21
-
22
- function parseJsonResult<T>(value: string, fallback: T): T {
23
- if (!value) {
24
- return fallback;
25
- }
26
-
27
- try {
28
- return JSON.parse(value) as T;
29
- } catch {
30
- return fallback;
31
- }
3
+ import { parseNativeResult, invokeNative } from "@legendapp/spark-desktop-app/src/contracts";
4
+ import { dialogOptions } from "./options";
5
+ import { fileDialogNative } from "./native";
6
+ import type { OpenFileDialogOptions, OpenFileDialogResult, SaveFileDialogOptions, SaveFileDialogResult } from "./types";
7
+ export type { FileFilter, FileDialogOptions, OpenFileDialogOptions, OpenFileDialogResult, SaveFileDialogOptions, SaveFileDialogResult } from "./types";
8
+ export { getFileDialogAvailability } from "./native";
9
+
10
+ function isNativePath(value: unknown): value is string {
11
+ if (typeof value !== "string" || value.startsWith("file://")) return false;
12
+ try { absolutePath(value, Platform.OS); return true; } catch { return false; }
32
13
  }
33
14
 
34
- export async function openFileDialog(options: FileDialogOpenOptions = {}) {
35
- validateDialogOptions(options, false);
36
- if (Platform.OS !== "macos") {
37
- return null;
38
- }
39
-
40
- const result = await NativeFileDialog.open(JSON.stringify(options));
41
- return parseJsonResult<string[] | null>(result, null);
15
+ export async function openFileDialog(options: OpenFileDialogOptions = {}): Promise<OpenFileDialogResult> {
16
+ const args = dialogOptions(options, "open", Platform.OS);
17
+ const paths = parseNativeResult(await invokeNative(() => fileDialogNative().open(JSON.stringify(args))), (value): value is string[] | null => value === null || (Array.isArray(value) && value.length > 0 && value.every(isNativePath)));
18
+ return paths === null ? { canceled: true } : { canceled: false, paths };
42
19
  }
43
-
44
- export async function saveFileDialog(options: FileDialogSaveOptions = {}) {
45
- validateDialogOptions(options, false);
46
- if (Platform.OS !== "macos") {
47
- return null;
48
- }
49
-
50
- const result = await NativeFileDialog.save(JSON.stringify(options));
51
- return parseJsonResult<string | null>(result, null);
20
+ export async function saveFileDialog(options: SaveFileDialogOptions = {}): Promise<SaveFileDialogResult> {
21
+ const args = dialogOptions(options, "save", Platform.OS);
22
+ const path = parseNativeResult(await invokeNative(() => fileDialogNative().save(JSON.stringify(args))), (value): value is string | null => value === null || isNativePath(value));
23
+ return path === null ? { canceled: true } : { canceled: false, path };
52
24
  }
53
-
54
- export function revealInFinder(path: string) {
55
- if (Platform.OS !== "macos") {
56
- return Promise.resolve(false);
57
- }
58
-
59
- return NativeFileDialog.revealInFinder(path);
60
- }
61
-
62
- export function readTextFile(path: string) {
63
- if (Platform.OS !== "macos") {
64
- return Promise.resolve("");
65
- }
66
-
67
- return NativeFileDialog.readTextFile(path);
68
- }
69
-
70
- export function writeTextFile(path: string, contents: string) {
71
- if (Platform.OS !== "macos") {
72
- return Promise.resolve();
73
- }
74
-
75
- return NativeFileDialog.writeTextFile(path, contents);
76
- }
77
-
78
- export function writeTextFileIfUnchanged(path: string, expectedContents: string, contents: string) {
79
- if (Platform.OS !== "macos") {
80
- return Promise.resolve(false);
81
- }
82
-
83
- return NativeFileDialog.writeTextFileIfUnchanged(path, expectedContents, contents);
84
- }
85
-
86
- export { default as NativeFileDialog } from "./NativeFileDialog";
87
-
88
- /** Reveal a file in the platform file manager (Finder or Explorer). */
89
- export const revealInFileManager = revealInFinder;
@@ -0,0 +1,12 @@
1
+ import { Platform } from "react-native";
2
+ import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
3
+ import Native from "./NativeFileDialog";
4
+ export function getFileDialogAvailability(): Availability {
5
+ if (Platform.OS !== "macos" && Platform.OS !== "windows") return { available: false, reason: "unsupported-platform" };
6
+ return Native ? { available: true } : { available: false, reason: "missing-module" };
7
+ }
8
+ export function fileDialogNative() {
9
+ const availability = getFileDialogAvailability();
10
+ if (!availability.available) throw new SparkError(availability.reason === "unsupported-platform" ? "E_UNSUPPORTED_PLATFORM" : "E_MODULE_UNAVAILABLE", "File dialogs require a desktop host with NativeFileDialog installed");
11
+ return Native!;
12
+ }
@@ -1,16 +1,36 @@
1
- import type { FileDialogOpenOptions, FileDialogSaveOptions } from "./index";
2
- function invalid(message: string, code = "E_INVALID_ARGUMENT"): never { throw Object.assign(new Error(message), { code }); }
3
- export function validateDialogOptions(options: FileDialogOpenOptions | FileDialogSaveOptions, windows: boolean) {
4
- for (const [name, value] of Object.entries(options)) {
5
- if (value === undefined || value === null) continue;
6
- if (["canChooseFiles", "canChooseDirectories", "allowsMultipleSelection"].includes(name)) {
7
- if (typeof value !== "boolean") invalid(`${name} must be boolean`);
8
- } else if (name === "allowedFileTypes") {
9
- if (!Array.isArray(value) || value.some(type => typeof type !== "string" || !type || /[\0*;\\/]/.test(type))) invalid("Invalid file type filter");
10
- } else if (!["directoryURL", "directory", "prompt", "message", "title", "defaultName"].includes(name) || typeof value !== "string" || value.includes("\0")) invalid(`Invalid dialog option: ${name}`);
1
+ import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
2
+ import { nativePath } from "@legendapp/spark-desktop-app/src/contracts/path";
3
+ import type { OpenFileDialogOptions, SaveFileDialogOptions } from "./types";
4
+
5
+ export function dialogOptions(options: OpenFileDialogOptions | SaveFileDialogOptions, kind: "open" | "save", platform: string) {
6
+ if (!options || typeof options !== "object" || Array.isArray(options)) throw new SparkError("E_INVALID_ARGUMENT", "Expected dialog options");
7
+ const allowed = new Set(["windowId", "defaultPath", "filters", ...(kind === "open" ? ["selection", "multiple", "title", "message", "prompt", "macos"] : ["defaultName"])]);
8
+ for (const [key, value] of Object.entries(options)) {
9
+ if (!allowed.has(key)) throw new SparkError("E_UNSUPPORTED_OPTION", `Unsupported dialog option: ${key}`);
10
+ if (value === undefined) continue;
11
+ if (["defaultPath", "title", "message", "prompt", "defaultName"].includes(key) && (typeof value !== "string" || value.includes("\0"))) throw new SparkError("E_INVALID_ARGUMENT", `${key} must be a string without NUL characters`);
11
12
  }
12
- const open = options as FileDialogOpenOptions;
13
- if (open.canChooseFiles === false && !open.canChooseDirectories) invalid("Choose files or directories");
14
- if (windows && open.canChooseDirectories && open.canChooseFiles !== false)
15
- invalid("Windows cannot select files and directories together; set canChooseFiles: false for folders", "E_UNSUPPORTED_OPTION");
13
+ if (options.windowId !== undefined && (typeof options.windowId !== "string" || !/^[a-zA-Z0-9_-]{1,100}$/.test(options.windowId))) throw new SparkError("E_INVALID_ARGUMENT", "Invalid dialog owner window ID");
14
+ const windowId = options.windowId;
15
+ // defaultPath may name a file for save dialogs. Only native hosts can tell a
16
+ // live directory from a proposed filename, so JS forwards the decoded path and
17
+ // each bridge splits it: the file part suggests defaultName unless one is given.
18
+ const directory = options.defaultPath === undefined ? undefined : nativePath(options.defaultPath, platform);
19
+ let filters: { name?: string; extensions: string[] }[] | undefined;
20
+ if (options.filters !== undefined) {
21
+ if (!Array.isArray(options.filters)) throw new SparkError("E_INVALID_ARGUMENT", "filters must be an array");
22
+ filters = [];
23
+ for (const filter of options.filters) {
24
+ if (!filter || Object.keys(filter).some(key => key !== "name" && key !== "extensions") || (filter.name !== undefined && (typeof filter.name !== "string" || !filter.name.trim() || filter.name.includes("\0"))) || !Array.isArray(filter.extensions) || !filter.extensions.length || filter.extensions.some((ext: unknown) => typeof ext !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(ext))) throw new SparkError("E_INVALID_ARGUMENT", "Filters need file extensions without dots, MIME types, or wildcards, and a name without NULs when given");
25
+ filters.push({ ...(filter.name === undefined ? {} : { name: filter.name }), extensions: [...filter.extensions] });
26
+ }
27
+ }
28
+ const allowedFileTypes = filters?.flatMap(filter => filter.extensions);
29
+ if (kind === "save") return { windowId, directory, filters, allowedFileTypes, defaultName: (options as SaveFileDialogOptions).defaultName };
30
+ const open = options as OpenFileDialogOptions;
31
+ if (open.selection !== undefined && !["files", "directories"].includes(open.selection)) throw new SparkError("E_INVALID_ARGUMENT", "selection must be files or directories");
32
+ if (open.multiple !== undefined && typeof open.multiple !== "boolean") throw new SparkError("E_INVALID_ARGUMENT", "multiple must be boolean");
33
+ if (platform === "macos" && open.macos !== undefined && (!open.macos || typeof open.macos !== "object" || Object.keys(open.macos).some(key => key !== "mixedSelection") || (open.macos.mixedSelection !== undefined && typeof open.macos.mixedSelection !== "boolean"))) throw new SparkError("E_INVALID_ARGUMENT", "Invalid macOS dialog options");
34
+ const mixed = platform === "macos" && open.macos?.mixedSelection === true;
35
+ return { windowId, directoryURL: directory, filters, allowedFileTypes, canChooseFiles: mixed || open.selection !== "directories", canChooseDirectories: mixed || open.selection === "directories", allowsMultipleSelection: open.multiple ?? false, title: open.title, message: open.message, prompt: open.prompt };
16
36
  }
@@ -0,0 +1,26 @@
1
+ /** Filters accept extensions without a dot (for example "txt"). MIME types and UTIs are not supported. */
2
+ export interface FileFilter {
3
+ /** Display label for the filter group. Windows presents one labeled group per filter; macOS combines all extensions into one allowed set, so the label is ignored there. */
4
+ name?: string;
5
+ extensions: readonly string[];
6
+ }
7
+ export interface FileDialogOptions {
8
+ /** Attach to this live Spark window. Omitted presents an unowned dialog. */
9
+ windowId?: string;
10
+ /** Absolute starting path. A directory starts there; for save it may name a file, which also suggests `defaultName`. */
11
+ defaultPath?: string;
12
+ /** macOS combines filters into one allowed-extension set; Windows keeps each labeled group. An empty array allows all files. */
13
+ filters?: readonly FileFilter[];
14
+ }
15
+ export interface OpenFileDialogOptions extends FileDialogOptions {
16
+ selection?: "files" | "directories";
17
+ multiple?: boolean;
18
+ title?: string;
19
+ message?: string;
20
+ prompt?: string;
21
+ /** macOS can select files and directories in the same panel. Ignored on other targets. */
22
+ macos?: { mixedSelection?: boolean };
23
+ }
24
+ export interface SaveFileDialogOptions extends FileDialogOptions { defaultName?: string }
25
+ export type OpenFileDialogResult = { canceled: true } | { canceled: false; paths: string[] };
26
+ export type SaveFileDialogResult = { canceled: true } | { canceled: false; path: string };