@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
@@ -1,34 +1,38 @@
1
1
  #import "RNDesktopWindows.h"
2
+ #import "window-manager/LegendWindowRegistry.h"
3
+ #import "SparkWindowGeometry.h"
4
+ #import <objc/runtime.h>
2
5
  #import <RNDesktopApp/SparkDesktop.h>
3
6
  #import <React-RCTAppDelegate/RCTRootViewFactory.h>
4
7
  #import <React/RCTSurfaceHostingView.h>
5
8
 
6
- // Overlay controls accept mouse input without taking keyboard focus from an app.
7
- @interface SparkOverlayPanel : NSPanel
8
- @end
9
- @implementation SparkOverlayPanel
10
- - (BOOL)canBecomeKeyWindow { return NO; }
11
- - (BOOL)canBecomeMainWindow { return NO; }
12
- @end
13
9
  static void Show(NSWindow *window) {
14
- if ([window isKindOfClass:SparkOverlayPanel.class]) [window orderFrontRegardless];
10
+ if ([window isKindOfClass:NSPanel.class] && (window.styleMask & NSWindowStyleMaskNonactivatingPanel)) [window orderFrontRegardless];
15
11
  else [window makeKeyAndOrderFront:nil];
16
12
  }
17
- @protocol SparkRootFactory
18
- - (RCTRootViewFactory *)rootViewFactory;
19
- @end
20
13
  @interface SparkWindowDelegate : NSObject <NSWindowDelegate>
21
14
  @property NSString *windowID;
15
+ @property (nonatomic, weak) NSWindow *window;
16
+ @property (nonatomic, weak) id<NSWindowDelegate> previousDelegate;
22
17
  @property BOOL guarded;
23
18
  @property BOOL allowingClose;
24
19
  @property NSUInteger request;
25
20
  @property BOOL pending;
21
+ @property NSString *instanceId;
22
+ @property NSString *guardId;
23
+ @property NSMutableArray *closeWaiters;
24
+ @property NSMutableArray *fullscreenWaiters;
25
+ @property NSNumber *fullscreenTarget;
26
+ @property BOOL restoreBounds;
27
+ - (void)finishClose:(BOOL)closed;
28
+ - (void)finishFullscreen:(BOOL)success;
29
+
26
30
  - (void)requestClose;
27
31
  @end
28
32
  static NSMutableDictionary<NSString *, NSWindow *> *windows;
29
33
  static NSMutableDictionary<NSString *, SparkWindowDelegate *> *delegates;
30
34
  static NSWindow *Window(NSString *key) {
31
- if (!windows) windows = [NSMutableDictionary new];
35
+ if (!windows) windows = LegendWindowRegistry.sharedRegistry.windows;
32
36
  NSWindow *window = windows[key];
33
37
  if (!window && [key isEqual:@"main"]) {
34
38
  for (NSWindow *candidate in NSApp.windows) {
@@ -38,71 +42,182 @@ static NSWindow *Window(NSString *key) {
38
42
  }
39
43
  return window;
40
44
  }
41
- static void Event(NSString *type, NSString *key) { SparkEmit(@{ @"type": type, @"windowId": key }); }
45
+ static void Event(NSString *type, NSString *key) {
46
+ NSWindow *window = Window(key);
47
+ NSMutableDictionary *event = [@{ @"type": type, @"windowId": key, @"instanceId": delegates[key].instanceId ?: @"" } mutableCopy];
48
+ if ([type isEqual:@"move"] || [type isEqual:@"resize"] || [type isEqual:@"screenChanged"]) {
49
+ event[@"type"] = @"boundsChanged"; event[@"bounds"] = SparkBoundsForWindow(window);
50
+ if (delegates[key].restoreBounds && !window.miniaturized && !(window.styleMask & NSWindowStyleMaskFullScreen)) {
51
+ NSScreen *screen = SparkOwningScreen(window.frame);
52
+ [NSUserDefaults.standardUserDefaults setObject:@{ @"version": @1, @"bounds": event[@"bounds"], @"persistentId": SparkPersistentScreenId(screen) ?: @"" }
53
+ forKey:[NSString stringWithFormat:@"%@.bounds.%@", SparkNamespace(), key]];
54
+ }
55
+ } else if ([type isEqual:@"focus"] || [type isEqual:@"blur"]) { event[@"type"] = @"focusChanged"; event[@"focused"] = @([type isEqual:@"focus"]); }
56
+ else if ([type isEqual:@"enterFullscreen"] || [type isEqual:@"leaveFullscreen"]) { event[@"type"] = @"fullscreenChanged"; event[@"fullscreen"] = @([type isEqual:@"enterFullscreen"]); }
57
+ else if ([type isEqual:@"visibilityChanged"]) event[@"visible"] = @(window.visible && !NSApp.hidden);
58
+ SparkEmit(event);
59
+ }
42
60
  @implementation SparkWindowDelegate
61
+ - (void)finishClose:(BOOL)closed {
62
+ NSArray *waiters = [self.closeWaiters copy]; [self.closeWaiters removeAllObjects];
63
+ for (RCTPromiseResolveBlock waiter in waiters) waiter(closed ? @"{\"closed\":true}" : @"{\"closed\":false,\"reason\":\"vetoed\"}");
64
+ }
65
+ - (void)finishFullscreen:(BOOL)success {
66
+ NSArray *waiters = [self.fullscreenWaiters copy]; [self.fullscreenWaiters removeAllObjects]; self.fullscreenTarget = nil;
67
+ for (NSDictionary *waiter in waiters) {
68
+ if (success) ((RCTPromiseResolveBlock)waiter[@"resolve"])(@"null");
69
+ else ((RCTPromiseRejectBlock)waiter[@"reject"])(@"E_NATIVE", @"Fullscreen transition failed", nil);
70
+ }
71
+ }
72
+
73
+ - (BOOL)respondsToSelector:(SEL)selector { return [super respondsToSelector:selector] || [self.previousDelegate respondsToSelector:selector]; }
74
+ - (id)forwardingTargetForSelector:(SEL)selector { return [self.previousDelegate respondsToSelector:selector] ? self.previousDelegate : [super forwardingTargetForSelector:selector]; }
43
75
  - (void)requestClose {
44
76
  if (self.pending) return;
45
77
  self.pending = YES; NSUInteger request = ++self.request;
46
- SparkEmit(@{ @"type": @"beforeClose", @"windowId": self.windowID, @"requestId": @(request) });
78
+ SparkEmit(@{ @"type": @"beforeClose", @"windowId": self.windowID, @"instanceId": self.instanceId, @"guardId": self.guardId ?: @"", @"requestId": @(request) });
47
79
  __weak SparkWindowDelegate *weakSelf = self;
48
80
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
49
81
  SparkWindowDelegate *delegate = weakSelf;
50
- if (delegate.request == request) delegate.pending = NO;
82
+ if (delegate.pending && delegate.request == request) { delegate.pending = NO; [delegate finishClose:NO]; SparkEmit(@{ @"type": @"closeGuardTimeout", @"windowId": delegate.windowID, @"instanceId": delegate.instanceId, @"guardId": delegate.guardId ?: @"" }); }
51
83
  });
52
84
  }
53
85
  - (BOOL)windowShouldClose:(NSWindow *)sender {
54
86
  if (self.guarded && !self.allowingClose) { [self requestClose]; return NO; }
55
- return YES;
87
+ return [self.previousDelegate respondsToSelector:@selector(windowShouldClose:)] ? [self.previousDelegate windowShouldClose:sender] : YES;
56
88
  }
57
89
  - (void)windowWillClose:(NSNotification *)note {
90
+ [self finishClose:YES]; [self finishFullscreen:NO];
91
+ BOOL managed = LegendWindowRegistry.sharedRegistry.moduleNames[self.windowID] != nil;
92
+ if ([self.previousDelegate respondsToSelector:@selector(windowWillClose:)]) [self.previousDelegate windowWillClose:note];
58
93
  NSWindow *closing = note.object;
59
94
  if (closing.sheetParent) [closing.sheetParent endSheet:closing];
60
95
  if (closing.parentWindow) [closing.parentWindow removeChildWindow:closing];
61
96
  Event(@"closed", self.windowID);
62
- if (![self.windowID isEqual:@"main"]) {
97
+ if (![self.windowID isEqual:@"main"] && !managed) {
63
98
  NSWindow *window = note.object;
64
99
  NSView *root = [window.contentView isKindOfClass:NSVisualEffectView.class] ? window.contentView.subviews.firstObject : window.contentView;
65
100
  if ([root isKindOfClass:RCTSurfaceHostingView.class]) [((RCTSurfaceHostingView *)root).surface stop];
66
101
  [root removeFromSuperview];
67
102
  window.contentView = [[NSView alloc] initWithFrame:root.frame];
68
103
  [windows removeObjectForKey:self.windowID];
69
- // Retain self until the delegate callback returns.
70
- dispatch_async(dispatch_get_main_queue(), ^{ [delegates removeObjectForKey:self.windowID]; });
104
+ [LegendWindowRegistry.sharedRegistry.rootViews removeObjectForKey:self.windowID];
105
+ }
106
+ [windows removeObjectForKey:self.windowID];
107
+ {
108
+ // Retain the proxy until its delegate callback returns.
109
+ dispatch_async(dispatch_get_main_queue(), ^{
110
+ if (delegates[self.windowID] == self) [delegates removeObjectForKey:self.windowID];
111
+ });
71
112
  }
72
113
  }
73
- - (void)windowDidMove:(NSNotification *)note { Event(@"move", self.windowID); }
74
- - (void)windowDidResize:(NSNotification *)note { Event(@"resize", self.windowID); }
75
- - (void)windowDidChangeScreen:(NSNotification *)note { Event(@"screenChanged", self.windowID); }
76
- - (void)windowDidEnterFullScreen:(NSNotification *)note { Event(@"enterFullscreen", self.windowID); }
77
- - (void)windowDidExitFullScreen:(NSNotification *)note { Event(@"leaveFullscreen", self.windowID); }
78
- - (void)windowDidBecomeKey:(NSNotification *)note { Event(@"focus", self.windowID); }
79
- - (void)windowDidResignKey:(NSNotification *)note { Event(@"blur", self.windowID); }
114
+ - (void)windowDidMove:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidMove:)]) [self.previousDelegate windowDidMove:note]; Event(@"move", self.windowID); }
115
+ - (void)windowDidResize:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidResize:)]) [self.previousDelegate windowDidResize:note]; Event(@"resize", self.windowID); }
116
+ - (void)windowDidChangeScreen:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidChangeScreen:)]) [self.previousDelegate windowDidChangeScreen:note]; Event(@"screenChanged", self.windowID); }
117
+ - (void)windowDidEnterFullScreen:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidEnterFullScreen:)]) [self.previousDelegate windowDidEnterFullScreen:note]; Event(@"enterFullscreen", self.windowID); [self finishFullscreen:YES]; }
118
+ - (void)windowDidExitFullScreen:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidExitFullScreen:)]) [self.previousDelegate windowDidExitFullScreen:note]; Event(@"leaveFullscreen", self.windowID); [self finishFullscreen:YES]; }
119
+ - (void)windowDidFailToEnterFullScreen:(NSWindow *)window { [self finishFullscreen:NO]; }
120
+ - (void)windowDidFailToExitFullScreen:(NSWindow *)window { [self finishFullscreen:NO]; }
121
+ - (void)windowDidMiniaturize:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:_cmd]) [self.previousDelegate windowDidMiniaturize:note]; Event(@"visibilityChanged", self.windowID); }
122
+ - (void)windowDidDeminiaturize:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:_cmd]) [self.previousDelegate windowDidDeminiaturize:note]; Event(@"visibilityChanged", self.windowID); }
123
+ - (void)windowDidBecomeKey:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidBecomeKey:)]) [self.previousDelegate windowDidBecomeKey:note]; Event(@"focus", self.windowID); }
124
+ - (void)windowDidResignKey:(NSNotification *)note { if ([self.previousDelegate respondsToSelector:@selector(windowDidResignKey:)]) [self.previousDelegate windowDidResignKey:note]; Event(@"blur", self.windowID); }
80
125
  @end
81
126
  static void InstallDelegate(NSWindow *window, NSString *key) {
82
127
  if (!delegates) delegates = [NSMutableDictionary new];
83
- if (delegates[key]) return;
128
+ if (delegates[key] && delegates[key].window == window) return;
84
129
  SparkWindowDelegate *delegate = [SparkWindowDelegate new];
85
- delegate.windowID = key;
130
+ delegate.window = window; delegate.windowID = key; delegate.instanceId = objc_getAssociatedObject(window, NSSelectorFromString(@"sparkWindowInstanceId")) ?: NSUUID.UUID.UUIDString;
131
+ objc_setAssociatedObject(window, NSSelectorFromString(@"sparkWindowInstanceId"), delegate.instanceId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
132
+ delegate.closeWaiters = [NSMutableArray new]; delegate.fullscreenWaiters = [NSMutableArray new];
86
133
  delegates[key] = delegate;
134
+ delegate.previousDelegate = window.delegate;
87
135
  window.delegate = delegate;
88
136
  }
137
+ extern "C" void SparkRebindWindowDelegate(NSWindow *window, NSString *key, id<NSWindowDelegate> delegate) {
138
+ SparkWindowDelegate *guard = delegates[key];
139
+ if (guard && guard.window == window) { guard.previousDelegate = delegate; window.delegate = guard; }
140
+ else window.delegate = delegate;
141
+ }
89
142
  static void RequestClose(NSWindow *window, NSString *key) {
90
143
  SparkWindowDelegate *delegate = delegates[key];
91
144
  if (delegate.guarded && !delegate.allowingClose) { [delegate requestClose]; return; }
145
+ BOOL allow = ![delegate.previousDelegate respondsToSelector:@selector(windowShouldClose:)] || [delegate.previousDelegate windowShouldClose:window];
146
+ if (!allow) { [delegate finishClose:NO]; return; }
92
147
  if (window.sheetParent) [window.sheetParent endSheet:window];
93
148
  [window close];
94
149
  }
95
- static NSDictionary *Frame(NSRect frame) {
96
- return @{ @"x": @(frame.origin.x), @"y": @(frame.origin.y), @"width": @(frame.size.width), @"height": @(frame.size.height) };
97
- }
98
150
  static NSDictionary *Info(NSString *key, NSWindow *window) {
99
- return @{ @"id": key, @"kind": [window isKindOfClass:SparkOverlayPanel.class] ? @"overlay" : @"window", @"title": window.title, @"visible": @(window.visible), @"focused": @(window.keyWindow),
100
- @"resizable": @((window.styleMask & NSWindowStyleMaskResizable) != 0), @"alwaysOnTop": @(window.level >= NSFloatingWindowLevel),
101
- @"minWidth": @(window.contentMinSize.width), @"maxWidth": @(window.contentMaxSize.width),
102
- @"minimized": @(window.miniaturized), @"fullscreen": @((window.styleMask & NSWindowStyleMaskFullScreen) != 0), @"frame": Frame(window.frame) };
151
+ InstallDelegate(window, key);
152
+ NSDictionary *opening = objc_getAssociatedObject(window, @selector(call:args:resolve:reject:));
153
+ NSString *parentId = opening[@"parentId"];
154
+ NSWindow *parent = window.sheetParent ?: window.parentWindow;
155
+ for (NSString *candidate in windows) if (windows[candidate] == parent) { parentId = candidate; break; }
156
+ return @{ @"id": key, @"instanceId": delegates[key].instanceId, @"kind": opening[@"kind"] ?: @"window",
157
+ @"title": window.title, @"parentId": parentId ?: NSNull.null, @"modal": @([opening[@"modal"] boolValue]), @"visible": @(window.visible && !NSApp.hidden), @"focused": @(window.keyWindow),
158
+ @"minimized": @(window.miniaturized), @"maximized": @(window.zoomed), @"fullscreen": @((window.styleMask & NSWindowStyleMaskFullScreen) != 0), @"bounds": SparkBoundsForWindow(window) };
159
+ }
160
+ static BOOL ApplyCommon(NSWindow *window, NSDictionary *options, RCTPromiseRejectBlock reject) {
161
+ NSSize minimum = options[@"minSize"] ? (options[@"minSize"] == NSNull.null ? NSMakeSize(100, 100) : NSMakeSize([options[@"minSize"][@"width"] doubleValue], [options[@"minSize"][@"height"] doubleValue])) : window.minSize;
162
+ NSSize maximum = options[@"maxSize"] ? (options[@"maxSize"] == NSNull.null ? NSMakeSize(20000, 20000) : NSMakeSize([options[@"maxSize"][@"width"] doubleValue], [options[@"maxSize"][@"height"] doubleValue])) : window.maxSize;
163
+ if (minimum.width > maximum.width || minimum.height > maximum.height) { reject(@"E_INVALID_ARGUMENT", @"Conflicting window constraints", nil); return NO; }
164
+ if (options[@"title"]) window.title = options[@"title"];
165
+ if (options[@"appearance"]) {
166
+ NSString *appearance = options[@"appearance"];
167
+ window.appearance = [appearance isEqual:@"dark"] ? [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua] : [appearance isEqual:@"light"] ? [NSAppearance appearanceNamed:NSAppearanceNameAqua] : nil;
168
+ }
169
+ NSWindowStyleMask mask = window.styleMask;
170
+ if (options[@"titleBarStyle"]) {
171
+ NSString *style = options[@"titleBarStyle"];
172
+ mask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView);
173
+ if (![style isEqual:@"borderless"]) mask |= NSWindowStyleMaskTitled;
174
+ if ([style isEqual:@"overlay"] || [style isEqual:@"hidden"]) mask |= NSWindowStyleMaskFullSizeContentView;
175
+ window.titlebarAppearsTransparent = ![style isEqual:@"default"];
176
+ window.titleVisibility = [style isEqual:@"default"] ? NSWindowTitleVisible : NSWindowTitleHidden;
177
+ }
178
+ for (NSString *key in @[@"resizable", @"closable", @"minimizable"]) if (options[key]) {
179
+ NSWindowStyleMask bit = [key isEqual:@"resizable"] ? NSWindowStyleMaskResizable : [key isEqual:@"closable"] ? NSWindowStyleMaskClosable : NSWindowStyleMaskMiniaturizable;
180
+ mask = [options[key] boolValue] ? mask | bit : mask & ~bit;
181
+ }
182
+ window.styleMask = mask;
183
+ if (options[@"titleBarStyle"]) for (NSNumber *button in @[@(NSWindowCloseButton), @(NSWindowMiniaturizeButton), @(NSWindowZoomButton)]) [window standardWindowButton:(NSWindowButton)button.integerValue].hidden = [options[@"titleBarStyle"] isEqual:@"hidden"];
184
+ if (options[@"alwaysOnTop"]) window.level = [options[@"alwaysOnTop"] boolValue] ? NSFloatingWindowLevel : NSNormalWindowLevel;
185
+ if (options[@"hasShadow"]) window.hasShadow = [options[@"hasShadow"] boolValue];
186
+ if (options[@"transparent"]) { window.opaque = ![options[@"transparent"] boolValue]; window.backgroundColor = window.opaque ? NSColor.windowBackgroundColor : NSColor.clearColor; }
187
+ if (options[@"backgroundColor"]) {
188
+ NSString *color = options[@"backgroundColor"]; unsigned long long rgba = 0;
189
+ [[NSScanner scannerWithString:[color substringFromIndex:1]] scanHexLongLong:&rgba]; if (color.length == 7) rgba = (rgba << 8) | 255;
190
+ window.backgroundColor = [NSColor colorWithSRGBRed:((rgba >> 24) & 255) / 255.0 green:((rgba >> 16) & 255) / 255.0 blue:((rgba >> 8) & 255) / 255.0 alpha:(rgba & 255) / 255.0];
191
+ window.opaque = (rgba & 255) == 255;
192
+ }
193
+ window.minSize = minimum; window.maxSize = maximum;
194
+ NSRect frame = window.frame;
195
+ frame.size.width = MIN(MAX(frame.size.width, minimum.width), maximum.width);
196
+ frame.size.height = MIN(MAX(frame.size.height, minimum.height), maximum.height);
197
+ [window setFrame:frame display:YES];
198
+ return YES;
199
+ }
200
+ static BOOL SetBounds(NSWindow *window, NSDictionary *bounds, double durationMs, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject) {
201
+ NSScreen *screen = SparkScreenWithId(bounds[@"displayId"]);
202
+ if (!screen) { reject(@"E_NOT_FOUND", @"Display is disconnected", nil); return NO; }
203
+ NSRect frame = SparkAppKitFrame(bounds, screen.frame);
204
+ if (frame.size.width < window.minSize.width || frame.size.height < window.minSize.height || frame.size.width > window.maxSize.width || frame.size.height > window.maxSize.height) { reject(@"E_INVALID_ARGUMENT", @"Bounds are outside window constraints", nil); return NO; }
205
+ if (durationMs > 0) [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { context.duration = durationMs / 1000.0; [[window animator] setFrame:frame display:YES]; } completionHandler:^{ resolve(@"null"); }];
206
+ else { [window setFrame:frame display:YES]; resolve(@"null"); }
207
+ return YES;
103
208
  }
104
209
  @implementation RNDesktopWindows
105
210
  RCT_EXPORT_MODULE(NativeDesktopWindowManager)
211
+ - (instancetype)init {
212
+ if ((self = [super init])) {
213
+ [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationVisibilityChanged:) name:NSApplicationDidHideNotification object:nil];
214
+ [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationVisibilityChanged:) name:NSApplicationDidUnhideNotification object:nil];
215
+ }
216
+ return self;
217
+ }
218
+ - (void)applicationVisibilityChanged:(NSNotification *)notification {
219
+ for (NSString *key in windows.allKeys) Event(@"visibilityChanged", key);
220
+ }
106
221
  + (BOOL)requiresMainQueueSetup { return YES; }
107
222
  - (void)call:(NSString *)method args:(NSString *)json resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
108
223
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -110,11 +225,10 @@ RCT_EXPORT_MODULE(NativeDesktopWindowManager)
110
225
  NSString *key = [args[@"id"] isKindOfClass:NSString.class] ? args[@"id"] : @"main";
111
226
  NSWindow *main = Window(@"main");
112
227
  if (main) InstallDelegate(main, @"main");
113
- if ([method isEqual:@"displays"]) {
114
- NSMutableArray *result = [NSMutableArray new];
115
- for (NSScreen *screen in NSScreen.screens) [result addObject:@{ @"id": [screen.deviceDescription[@"NSScreenNumber"] stringValue],
116
- @"name": screen.localizedName, @"frame": Frame(screen.frame), @"workArea": Frame(screen.visibleFrame), @"scale": @(screen.backingScaleFactor) }];
117
- resolve(SparkJSON(result)); return;
228
+ if ([method isEqual:@"displays"]) { resolve(SparkJSON(SparkDisplayInfo())); return; }
229
+ if ([method isEqual:@"cursorPoint"]) {
230
+ resolve(SparkJSON(SparkCursorPoint()));
231
+ return;
118
232
  }
119
233
  if ([method isEqual:@"list"]) {
120
234
  NSMutableArray *result = [NSMutableArray new];
@@ -122,86 +236,98 @@ RCT_EXPORT_MODULE(NativeDesktopWindowManager)
122
236
  resolve(SparkJSON(result)); return;
123
237
  }
124
238
  NSWindow *window = Window(key);
125
- if ([method isEqual:@"open"]) {
126
- if (!key.length || [key isEqual:@"main"]) { SparkInvalid(reject, @"Secondary windows need a non-main id"); return; }
239
+ if (!window) { reject(@"E_NOT_FOUND", @"Window does not exist", nil); return; }
240
+ InstallDelegate(window, key);
241
+ SparkWindowDelegate *delegate = delegates[key];
242
+ if (args[@"instanceId"] && ![args[@"instanceId"] isEqual:delegate.instanceId]) { reject(@"E_NOT_FOUND", @"Window instance has closed", nil); return; }
243
+ if ([method isEqual:@"info"] || [method isEqual:@"observe"]) { resolve(SparkJSON(Info(key, window))); return; }
244
+ if ([method isEqual:@"completeOpen"]) {
127
245
  NSWindow *parent = args[@"parentId"] ? Window(args[@"parentId"]) : nil;
128
246
  if (args[@"parentId"] && !parent) { reject(@"E_NOT_FOUND", @"Parent window not found", nil); return; }
129
- if (parent && parent == window) { SparkInvalid(reject, @"Invalid parent window"); return; }
130
- if ([args[@"modal"] boolValue] && (!parent || parent.attachedSheet)) { reject(@"E_BUSY", @"Modal window requires an available parent", nil); return; }
131
- if (!window) {
132
- id delegate = NSApp.delegate;
133
- if (![delegate respondsToSelector:@selector(rootViewFactory)]) { reject(@"E_HOST", @"Host has no React root factory", nil); return; }
134
- CGFloat width = args[@"width"] ? [args[@"width"] doubleValue] : 640;
135
- CGFloat height = args[@"height"] ? [args[@"height"] doubleValue] : 480;
136
- BOOL overlay = [args[@"kind"] isEqual:@"overlay"];
137
- if (overlay && [args[@"modal"] boolValue]) { SparkInvalid(reject, @"An overlay cannot be modal"); return; }
138
- window = [[(overlay ? SparkOverlayPanel.class : NSWindow.class) alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
139
- styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | (overlay ? NSWindowStyleMaskNonactivatingPanel : 0)
140
- backing:NSBackingStoreBuffered defer:NO];
141
- if (overlay) {
142
- ((NSPanel *)window).hidesOnDeactivate = NO;
143
- window.collectionBehavior = NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorFullScreenAuxiliary;
144
- }
145
- window.releasedWhenClosed = NO;
146
- window.identifier = [@"spark." stringByAppendingString:key];
147
- window.title = args[@"title"] ?: SparkContext()[@"name"];
148
- window.contentView = [(id<SparkRootFactory>)delegate rootViewFactory] ? [[(id<SparkRootFactory>)delegate rootViewFactory]
149
- viewWithModuleName:@"main" initialProperties:SparkInitialProps(key, args[@"props"])] : nil;
150
- window.contentView = SparkWindowContent(window.contentView);
151
- SparkApplyWindowOptions(window, args);
152
- SparkRestoreWindow(window, key, args);
153
- windows[key] = window;
154
- InstallDelegate(window, key);
155
- Event(@"opened", key);
247
+ if ([args[@"modal"] boolValue] && parent.attachedSheet) { reject(@"E_BUSY", @"Parent already has a sheet", nil); return; }
248
+ window.minSize = NSMakeSize(100, 100); window.maxSize = NSMakeSize(20000, 20000);
249
+ if (!ApplyCommon(window, args, reject)) return;
250
+ NSDictionary *saved = [args[@"restoreBounds"] boolValue] ? [NSUserDefaults.standardUserDefaults dictionaryForKey:[NSString stringWithFormat:@"%@.bounds.%@", SparkNamespace(), key]] : nil;
251
+ if (![saved[@"version"] isEqual:@1]) saved = nil;
252
+ BOOL restoredShell = [objc_getAssociatedObject(window, NSSelectorFromString(@"sparkRestoredShell")) boolValue];
253
+ if (!saved && restoredShell) {
254
+ NSScreen *restoredScreen = SparkOwningScreen(window.frame);
255
+ saved = @{ @"bounds": SparkLogicalBounds(window.frame, restoredScreen.frame, SparkScreenId(restoredScreen)), @"persistentId": SparkPersistentScreenId(restoredScreen) ?: @"" };
256
+ }
257
+ NSScreen *screen = args[@"position"] ? SparkScreenWithId(args[@"position"][@"displayId"]) : nil;
258
+ if (args[@"position"] && !screen) { reject(@"E_NOT_FOUND", @"Display is disconnected", nil); return; }
259
+ if (!screen && saved) for (NSScreen *candidate in NSScreen.screens) if ([SparkPersistentScreenId(candidate) isEqual:saved[@"persistentId"]]) { screen = candidate; break; }
260
+ if (!screen) screen = parent ? SparkOwningScreen(parent.frame) : SparkPrimaryScreen();
261
+ NSDictionary *size = args[@"size"] ?: saved[@"bounds"];
262
+ CGFloat width = size ? [size[@"width"] doubleValue] : 640, height = size ? [size[@"height"] doubleValue] : 480;
263
+ width = MIN(MAX(width, window.minSize.width), window.maxSize.width); height = MIN(MAX(height, window.minSize.height), window.maxSize.height);
264
+ NSRect frame = NSMakeRect(NSMidX(screen.visibleFrame) - width / 2, NSMidY(screen.visibleFrame) - height / 2, width, height);
265
+ if (args[@"position"] || saved) {
266
+ NSMutableDictionary *bounds = [(args[@"position"] ?: saved[@"bounds"]) mutableCopy]; bounds[@"width"] = @(width); bounds[@"height"] = @(height);
267
+ frame = SparkAppKitFrame(bounds, screen.frame);
268
+ if (!args[@"position"]) frame = [window constrainFrameRect:frame toScreen:screen];
156
269
  }
157
- if ([args[@"modal"] boolValue]) [parent beginSheet:window completionHandler:nil];
158
- else { NSInteger level = window.level; if (parent) [parent addChildWindow:window ordered:NSWindowAbove]; Show(window); window.level = level; }
159
- resolve(SparkJSON(Info(key, window))); return;
270
+ [window setFrame:frame display:NO]; delegate.restoreBounds = [args[@"restoreBounds"] boolValue];
271
+ if (parent && ![args[@"modal"] boolValue]) [parent addChildWindow:window ordered:NSWindowAbove];
272
+ objc_setAssociatedObject(window, @selector(call:args:resolve:reject:), [args copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
273
+ if (![args[@"show"] isEqual:@NO]) {
274
+ if ([args[@"modal"] boolValue]) [parent beginSheet:window completionHandler:nil]; else Show(window);
275
+ } else [window orderOut:nil];
276
+ Event(@"opened", key); Event(@"visibilityChanged", key); resolve(SparkJSON(Info(key, window))); return;
160
277
  }
161
- if (!window) { reject(@"E_NOT_FOUND", @"Window does not exist", nil); return; }
162
- if ([method isEqual:@"info"]) { resolve(SparkJSON(Info(key, window))); return; }
163
- if ([method isEqual:@"close"]) RequestClose(window, key);
164
- else if ([method isEqual:@"closeGuard"]) { delegates[key].guarded = [args[@"enabled"] boolValue]; delegates[key].pending = NO; delegates[key].request++; }
165
- else if ([method isEqual:@"replyClose"]) {
166
- SparkWindowDelegate *delegate = delegates[key];
167
- if (delegate.pending && delegate.request == [args[@"requestId"] unsignedIntegerValue]) {
278
+ if ([method isEqual:@"discard"]) { delegate.guarded = NO; [window close]; return resolve(@"null"); }
279
+ if ([method isEqual:@"close"]) { [delegate.closeWaiters addObject:[resolve copy]]; RequestClose(window, key); return; }
280
+ if ([method isEqual:@"closeGuard"]) {
281
+ BOOL enable = [args[@"enabled"] boolValue];
282
+ if (enable && delegate.guarded && ![delegate.guardId isEqual:args[@"guardId"]]) { reject(@"E_BUSY", @"Window already has a close guard", nil); return; }
283
+ if (!enable && ![delegate.guardId isEqual:args[@"guardId"]]) return resolve(@"null");
284
+ delegate.guarded = enable; delegate.guardId = enable ? args[@"guardId"] : nil; delegate.pending = NO; delegate.request++; [delegate finishClose:NO];
285
+ } else if ([method isEqual:@"replyClose"]) {
286
+ if (delegate.pending && delegate.request == [args[@"requestId"] unsignedIntegerValue] && [delegate.guardId isEqual:args[@"guardId"]]) {
168
287
  delegate.pending = NO;
169
288
  if ([args[@"allow"] boolValue]) { delegate.allowingClose = YES; RequestClose(window, key); delegate.allowingClose = NO; }
289
+ else [delegate finishClose:NO];
170
290
  }
171
- }
172
- else if ([method isEqual:@"show"]) { [window deminiaturize:nil]; Show(window); }
173
- else if ([method isEqual:@"options"]) SparkApplyWindowOptions(window, args[@"options"]);
291
+ } else if ([method isEqual:@"show"]) {
292
+ [window deminiaturize:nil]; NSDictionary *opening = objc_getAssociatedObject(window, @selector(call:args:resolve:reject:));
293
+ if ([opening[@"modal"] boolValue] && !window.sheetParent) {
294
+ NSWindow *parent = Window(opening[@"parentId"]);
295
+ if (!parent) { reject(@"E_NOT_FOUND", @"Parent window has closed", nil); return; }
296
+ if (parent.attachedSheet) { reject(@"E_BUSY", @"Parent already has a sheet", nil); return; }
297
+ [parent beginSheet:window completionHandler:nil];
298
+ } else if ([args[@"focus"] isEqual:@NO]) [window orderFront:nil]; else Show(window);
299
+ Event(@"visibilityChanged", key);
300
+ } else if ([method isEqual:@"options"]) { if (!ApplyCommon(window, args[@"options"], reject)) return; }
174
301
  else if ([method isEqual:@"maximize"]) { if (!window.zoomed) [window zoom:nil]; }
175
302
  else if ([method isEqual:@"unmaximize"]) { if (window.zoomed) [window zoom:nil]; }
176
- else if ([method isEqual:@"center"]) [window center];
177
- else if ([method isEqual:@"hide"]) [window orderOut:nil];
178
- else if ([method isEqual:@"minimize"]) [window miniaturize:nil];
303
+ else if ([method isEqual:@"center"]) {
304
+ NSScreen *screen = args[@"displayId"] ? SparkScreenWithId(args[@"displayId"]) : SparkOwningScreen(window.frame);
305
+ if (!screen) { reject(@"E_NOT_FOUND", @"Display is disconnected", nil); return; }
306
+ NSRect frame = window.frame; frame.origin = NSMakePoint(NSMidX(screen.visibleFrame) - NSWidth(frame)/2, NSMidY(screen.visibleFrame) - NSHeight(frame)/2); [window setFrame:frame display:YES];
307
+ } else if ([method isEqual:@"hide"]) {
308
+ if (window.sheetParent) [window.sheetParent endSheet:window]; [window orderOut:nil]; Event(@"visibilityChanged", key);
309
+ } else if ([method isEqual:@"minimize"]) [window miniaturize:nil];
179
310
  else if ([method isEqual:@"fullscreen"]) {
180
- BOOL current = (window.styleMask & NSWindowStyleMaskFullScreen) != 0;
181
- if (current != [args[@"enabled"] boolValue]) [window toggleFullScreen:nil];
182
- }
183
- else if ([method isEqual:@"title"]) window.title = args[@"title"] ?: @"";
184
- else if ([method isEqual:@"frame"]) {
185
- NSDictionary *frame = args[@"frame"];
186
- [window setFrame:NSMakeRect([frame[@"x"] doubleValue], [frame[@"y"] doubleValue], [frame[@"width"] doubleValue], [frame[@"height"] doubleValue]) display:YES];
187
- }
311
+ BOOL target = [args[@"enabled"] boolValue];
312
+ if (delegate.fullscreenTarget && delegate.fullscreenTarget.boolValue != target) { reject(@"E_BUSY", @"Another fullscreen transition is pending", nil); return; }
313
+ if (delegate.fullscreenTarget || ((window.styleMask & NSWindowStyleMaskFullScreen) != 0) != target) {
314
+ [delegate.fullscreenWaiters addObject:@{ @"resolve": [resolve copy], @"reject": [reject copy] }];
315
+ if (!delegate.fullscreenTarget) { delegate.fullscreenTarget = @(target); [window toggleFullScreen:nil]; }
316
+ return;
317
+ }
318
+ } else if ([method isEqual:@"bounds"]) { SetBounds(window, args[@"bounds"], [args[@"durationMs"] doubleValue], resolve, reject); return; }
188
319
  else { SparkInvalid(reject, @"Unknown window operation"); return; }
189
320
  resolve(@"null");
190
321
  });
191
322
  }
192
323
  - (void)invalidate {
324
+ [NSNotificationCenter.defaultCenter removeObserver:self];
193
325
  dispatch_async(dispatch_get_main_queue(), ^{
194
- for (NSString *key in [windows.allKeys copy]) {
195
- NSWindow *window = windows[key];
196
- window.delegate = nil;
197
- if (![key isEqual:@"main"]) {
198
- NSView *root = [window.contentView isKindOfClass:NSVisualEffectView.class] ? window.contentView.subviews.firstObject : window.contentView;
199
- if ([root isKindOfClass:RCTSurfaceHostingView.class]) [((RCTSurfaceHostingView *)root).surface stop];
200
- [root removeFromSuperview]; window.contentView = nil;
201
- [window close];
202
- }
326
+ // Windows and Fabric surfaces belong to the application. Retire only guards
327
+ // whose JavaScript handlers went away; the next runtime may register again.
328
+ for (SparkWindowDelegate *delegate in delegates.allValues) {
329
+ delegate.guarded = NO; delegate.pending = NO; delegate.request++; [delegate finishClose:NO]; [delegate finishFullscreen:NO];
203
330
  }
204
- [windows removeAllObjects]; [delegates removeAllObjects];
205
331
  });
206
332
  }
207
333
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
@@ -0,0 +1,63 @@
1
+ #pragma once
2
+ #import <AppKit/AppKit.h>
3
+ #import <CoreGraphics/CoreGraphics.h>
4
+
5
+ // AppKit screen frames are already logical units, with an upward-positive Y axis.
6
+ static inline NSDictionary *SparkLogicalBounds(NSRect frame, NSRect screen, NSString *displayId) {
7
+ return @{ @"displayId": displayId, @"x": @(NSMinX(frame) - NSMinX(screen)), @"y": @(NSMaxY(screen) - NSMaxY(frame)), @"width": @(NSWidth(frame)), @"height": @(NSHeight(frame)) };
8
+ }
9
+ static inline NSRect SparkAppKitFrame(NSDictionary *bounds, NSRect screen) {
10
+ const CGFloat height = [bounds[@"height"] doubleValue];
11
+ return NSMakeRect(NSMinX(screen) + [bounds[@"x"] doubleValue], NSMaxY(screen) - [bounds[@"y"] doubleValue] - height, [bounds[@"width"] doubleValue], height);
12
+ }
13
+ static inline NSString *SparkScreenId(NSScreen *screen) { return [screen.deviceDescription[@"NSScreenNumber"] stringValue]; }
14
+ static inline NSScreen *SparkPrimaryScreen(void) {
15
+ for (NSScreen *screen in NSScreen.screens) if ([screen.deviceDescription[@"NSScreenNumber"] unsignedIntValue] == CGMainDisplayID()) return screen;
16
+ return NSScreen.screens.firstObject;
17
+ }
18
+ static inline NSScreen *SparkScreenWithId(NSString *identifier) {
19
+ for (NSScreen *screen in NSScreen.screens) if ([SparkScreenId(screen) isEqual:identifier]) return screen;
20
+ return nil;
21
+ }
22
+ static inline NSScreen *SparkOwningScreen(NSRect frame) {
23
+ NSScreen *best = SparkPrimaryScreen(); CGFloat area = -1;
24
+ for (NSScreen *screen in NSScreen.screens) {
25
+ NSRect intersection = NSIntersectionRect(frame, screen.frame);
26
+ CGFloat next = NSWidth(intersection) * NSHeight(intersection);
27
+ if (next > area || (next == area && screen == SparkPrimaryScreen())) { best = screen; area = next; }
28
+ }
29
+ return best;
30
+ }
31
+ static inline NSDictionary *SparkBoundsForWindow(NSWindow *window) {
32
+ NSScreen *screen = SparkOwningScreen(window.frame);
33
+ return SparkLogicalBounds(window.frame, screen.frame, SparkScreenId(screen) ?: @"");
34
+ }
35
+ static inline NSString *SparkPersistentScreenId(NSScreen *screen) {
36
+ CFUUIDRef uuid = CGDisplayCreateUUIDFromDisplayID([screen.deviceDescription[@"NSScreenNumber"] unsignedIntValue]);
37
+ NSString *value = uuid ? CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)) : nil;
38
+ if (uuid) CFRelease(uuid);
39
+ return value;
40
+ }
41
+ // The pointer in Spark's coordinate vocabulary: the display containing the
42
+ // point, with display-relative logical units (top-left origin, Y downward).
43
+ static inline NSDictionary *SparkCursorPoint(void) {
44
+ NSPoint point = NSEvent.mouseLocation;
45
+ for (NSScreen *screen in NSScreen.screens) {
46
+ NSRect frame = screen.frame;
47
+ if (point.x >= NSMinX(frame) && point.x < NSMaxX(frame) && point.y >= NSMinY(frame) && point.y < NSMaxY(frame))
48
+ return @{ @"displayId": SparkScreenId(screen) ?: @"", @"x": @(point.x - NSMinX(frame)), @"y": @(NSMaxY(frame) - point.y) };
49
+ }
50
+ NSScreen *primary = SparkPrimaryScreen();
51
+ return @{ @"displayId": SparkScreenId(primary) ?: @"", @"x": @(point.x - NSMinX(primary.frame)), @"y": @(NSMaxY(primary.frame) - point.y) };
52
+ }
53
+ static inline NSArray<NSDictionary *> *SparkDisplayInfo(void) {
54
+ NSMutableArray *result = [NSMutableArray new];
55
+ for (NSScreen *screen in NSScreen.screens) {
56
+ NSMutableDictionary *workArea = [SparkLogicalBounds(screen.visibleFrame, screen.frame, SparkScreenId(screen)) mutableCopy];
57
+ [workArea removeObjectForKey:@"displayId"];
58
+ [result addObject:@{ @"id": SparkScreenId(screen), @"persistentId": SparkPersistentScreenId(screen) ?: NSNull.null,
59
+ @"name": screen.localizedName, @"primary": @(screen == SparkPrimaryScreen()),
60
+ @"size": @{ @"width": @(NSWidth(screen.frame)), @"height": @(NSHeight(screen.frame)) }, @"workArea": workArea, @"scaleFactor": @(screen.backingScaleFactor) }];
61
+ }
62
+ return result;
63
+ }
@@ -0,0 +1,20 @@
1
+ #import <TargetConditionals.h>
2
+ #if TARGET_OS_OSX
3
+ #import <AppKit/AppKit.h>
4
+ #import <CoreImage/CoreImage.h>
5
+
6
+ // Windows and their React surfaces outlive an individual TurboModule on reload.
7
+ // Runtime-specific listeners and delegates remain owned by RNWindowManager.
8
+ @interface LegendWindowRegistry : NSObject
9
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, NSWindow *> *windows;
10
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, id> *rootViews;
11
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, NSString *> *moduleNames;
12
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, NSArray<NSTitlebarAccessoryViewController *> *> *titlebarAccessoryControllers;
13
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, NSView *> *titlebarMaterialViews;
14
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, NSArray<NSDictionary *> *> *toolbarItemConfigs;
15
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, CIFilter *> *windowBlurFilters;
16
+ @property (nonatomic, readonly) NSMutableDictionary<NSString *, NSDictionary *> *windowOptions;
17
+ @property (nonatomic, readonly) NSMutableSet<NSString *> *closeRequestIdentifiers;
18
+ + (instancetype)sharedRegistry;
19
+ @end
20
+ #endif
@@ -0,0 +1,27 @@
1
+ #import "LegendWindowRegistry.h"
2
+ #if TARGET_OS_OSX
3
+ @implementation LegendWindowRegistry
4
+ + (instancetype)sharedRegistry
5
+ {
6
+ static LegendWindowRegistry *registry;
7
+ static dispatch_once_t once;
8
+ dispatch_once(&once, ^{ registry = [self new]; });
9
+ return registry;
10
+ }
11
+ - (instancetype)init
12
+ {
13
+ if (self = [super init]) {
14
+ _windows = [NSMutableDictionary new];
15
+ _rootViews = [NSMutableDictionary new];
16
+ _moduleNames = [NSMutableDictionary new];
17
+ _titlebarAccessoryControllers = [NSMutableDictionary new];
18
+ _titlebarMaterialViews = [NSMutableDictionary new];
19
+ _toolbarItemConfigs = [NSMutableDictionary new];
20
+ _windowBlurFilters = [NSMutableDictionary new];
21
+ _windowOptions = [NSMutableDictionary new];
22
+ _closeRequestIdentifiers = [NSMutableSet new];
23
+ }
24
+ return self;
25
+ }
26
+ @end
27
+ #endif
@@ -0,0 +1,12 @@
1
+ #import <React/RCTEventEmitter.h>
2
+ #import <RNDesktopWindowsSpec/RNDesktopWindowsSpec.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @class NSWindow;
7
+
8
+ @interface RNWindowManager : RCTEventEmitter <NativeWindowManagerSpec>
9
+ + (nullable NSWindow *)getMainWindow;
10
+ @end
11
+
12
+ NS_ASSUME_NONNULL_END