@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
@@ -0,0 +1,1419 @@
1
+ #import "RNSidebarSplitViewComponent.h"
2
+
3
+ #import <react/renderer/components/RNSparkUISpec/ComponentDescriptors.h>
4
+ #import <react/renderer/components/RNSparkUISpec/EventEmitters.h>
5
+ #import <react/renderer/components/RNSparkUISpec/Props.h>
6
+ #import <react/renderer/components/RNSparkUISpec/RCTComponentViewHelpers.h>
7
+
8
+ #if TARGET_OS_OSX
9
+ #import <CoreImage/CoreImage.h>
10
+ #import <QuartzCore/QuartzCore.h>
11
+ #import <objc/runtime.h>
12
+ #endif
13
+
14
+ using namespace facebook::react;
15
+
16
+ #if TARGET_OS_OSX
17
+ @interface RNSidebarSplitViewTitlebarMaterialContainerView : NSView
18
+ @end
19
+
20
+ @implementation RNSidebarSplitViewTitlebarMaterialContainerView
21
+ - (nullable NSView *)hitTest:(NSPoint)point
22
+ {
23
+ return nil;
24
+ }
25
+ @end
26
+
27
+ static NSAppearance *RNSidebarSplitViewAppearanceForName(NSString *appearanceName)
28
+ {
29
+ if ([appearanceName isEqualToString:@"light"]) {
30
+ return [NSAppearance appearanceNamed:NSAppearanceNameAqua];
31
+ }
32
+
33
+ if ([appearanceName isEqualToString:@"dark"]) {
34
+ return [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
35
+ }
36
+
37
+ return nil;
38
+ }
39
+
40
+ static NSColor *RNSidebarSplitViewColorFromHexString(NSString *value)
41
+ {
42
+ if (![value isKindOfClass:NSString.class] || value.length == 0) {
43
+ return nil;
44
+ }
45
+
46
+ NSString *hex = [value hasPrefix:@"#"] ? [value substringFromIndex:1] : value;
47
+ if (hex.length != 6 && hex.length != 8) {
48
+ return nil;
49
+ }
50
+
51
+ unsigned long long raw = 0;
52
+ NSScanner *scanner = [NSScanner scannerWithString:hex];
53
+ if (![scanner scanHexLongLong:&raw]) {
54
+ return nil;
55
+ }
56
+
57
+ CGFloat red = 0;
58
+ CGFloat green = 0;
59
+ CGFloat blue = 0;
60
+ CGFloat alpha = 1;
61
+ if (hex.length == 8) {
62
+ red = ((raw >> 24) & 0xff) / 255.0;
63
+ green = ((raw >> 16) & 0xff) / 255.0;
64
+ blue = ((raw >> 8) & 0xff) / 255.0;
65
+ alpha = (raw & 0xff) / 255.0;
66
+ } else {
67
+ red = ((raw >> 16) & 0xff) / 255.0;
68
+ green = ((raw >> 8) & 0xff) / 255.0;
69
+ blue = (raw & 0xff) / 255.0;
70
+ }
71
+
72
+ return [NSColor colorWithSRGBRed:red green:green blue:blue alpha:alpha];
73
+ }
74
+
75
+ static CGFloat RNSidebarSplitViewClampedUnitValue(CGFloat value)
76
+ {
77
+ return MIN(MAX(0, value), 1);
78
+ }
79
+
80
+ static NSVisualEffectMaterial RNSidebarSplitViewMaterialForName(NSString *value)
81
+ {
82
+ if ([value isEqualToString:@"hudWindow"]) {
83
+ return NSVisualEffectMaterialHUDWindow;
84
+ }
85
+ if ([value isEqualToString:@"sidebar"]) {
86
+ return NSVisualEffectMaterialSidebar;
87
+ }
88
+ if ([value isEqualToString:@"windowBackground"]) {
89
+ return NSVisualEffectMaterialWindowBackground;
90
+ }
91
+ if ([value isEqualToString:@"titlebar"]) {
92
+ return NSVisualEffectMaterialTitlebar;
93
+ }
94
+ if ([value isEqualToString:@"glass"] || [value isEqualToString:@"headerView"]) {
95
+ if (@available(macOS 10.14, *)) {
96
+ return NSVisualEffectMaterialHeaderView;
97
+ }
98
+ return NSVisualEffectMaterialTitlebar;
99
+ }
100
+ return NSVisualEffectMaterialTitlebar;
101
+ }
102
+
103
+ static NSView *RNSidebarSplitViewCreateColorOverlay(NSRect frame, NSColor *color, CGFloat opacity)
104
+ {
105
+ NSView *overlayView = [[NSView alloc] initWithFrame:frame];
106
+ overlayView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
107
+ overlayView.wantsLayer = YES;
108
+ overlayView.layer.backgroundColor = [color colorWithAlphaComponent:opacity].CGColor;
109
+ return overlayView;
110
+ }
111
+
112
+ static NSView *RNSidebarSplitViewCreateMaterialContainer(NSRect frame, NSView *materialView, NSColor *overlayColor, CGFloat overlayOpacity)
113
+ {
114
+ RNSidebarSplitViewTitlebarMaterialContainerView *containerView =
115
+ [[RNSidebarSplitViewTitlebarMaterialContainerView alloc] initWithFrame:frame];
116
+ containerView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
117
+ containerView.wantsLayer = YES;
118
+ containerView.layer.backgroundColor = NSColor.clearColor.CGColor;
119
+ containerView.layer.masksToBounds = YES;
120
+
121
+ [containerView addSubview:materialView];
122
+ if (overlayColor && overlayOpacity > 0) {
123
+ [containerView addSubview:RNSidebarSplitViewCreateColorOverlay(containerView.bounds, overlayColor, overlayOpacity)];
124
+ }
125
+
126
+ return containerView;
127
+ }
128
+
129
+ API_AVAILABLE(macos(26.0))
130
+ static NSView *RNSidebarSplitViewCreateGlassMaterialView(NSRect frame, NSColor *overlayColor, CGFloat overlayOpacity)
131
+ {
132
+ CGFloat overscan = 48;
133
+ NSRect glassFrame = NSMakeRect(-overscan, 0, NSWidth(frame) + (overscan * 2), NSHeight(frame) + overscan);
134
+ NSGlassEffectView *glassView = [[NSGlassEffectView alloc] initWithFrame:glassFrame];
135
+ glassView.cornerRadius = 0;
136
+ glassView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
137
+ glassView.wantsLayer = YES;
138
+ glassView.layer.backgroundColor = NSColor.clearColor.CGColor;
139
+ return RNSidebarSplitViewCreateMaterialContainer(frame, glassView, overlayColor, overlayOpacity);
140
+ }
141
+
142
+ static NSView *RNSidebarSplitViewCreateTitlebarMaterialView(NSString *materialName,
143
+ NSRect frame,
144
+ NSColor *overlayColor,
145
+ CGFloat overlayOpacity)
146
+ {
147
+ if ([materialName isEqualToString:@"glass"]) {
148
+ if (@available(macOS 26.0, *)) {
149
+ return RNSidebarSplitViewCreateGlassMaterialView(frame, overlayColor, overlayOpacity);
150
+ }
151
+ }
152
+
153
+ NSVisualEffectView *effectView = [[NSVisualEffectView alloc] initWithFrame:NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame))];
154
+ effectView.material = RNSidebarSplitViewMaterialForName(materialName);
155
+ effectView.blendingMode = NSVisualEffectBlendingModeWithinWindow;
156
+ effectView.state = NSVisualEffectStateFollowsWindowActiveState;
157
+ effectView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
158
+ effectView.wantsLayer = YES;
159
+ effectView.layer.backgroundColor = NSColor.clearColor.CGColor;
160
+ return RNSidebarSplitViewCreateMaterialContainer(frame, effectView, overlayColor, overlayOpacity);
161
+ }
162
+
163
+ static NSView *RNSidebarSplitViewCreateBackgroundBlurView(NSRect frame, CGFloat radius)
164
+ {
165
+ RNSidebarSplitViewTitlebarMaterialContainerView *blurView =
166
+ [[RNSidebarSplitViewTitlebarMaterialContainerView alloc] initWithFrame:frame];
167
+ blurView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
168
+ blurView.wantsLayer = YES;
169
+ blurView.layerUsesCoreImageFilters = YES;
170
+ blurView.layer.backgroundColor = NSColor.clearColor.CGColor;
171
+
172
+ CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
173
+ [blurFilter setDefaults];
174
+ [blurFilter setValue:@(radius) forKey:kCIInputRadiusKey];
175
+ blurView.layer.backgroundFilters = @[blurFilter];
176
+ return blurView;
177
+ }
178
+
179
+ static void RNSidebarSplitViewApplySoftBottomEdgeMask(NSView *view)
180
+ {
181
+ CAGradientLayer *maskLayer = [CAGradientLayer layer];
182
+ maskLayer.frame = view.bounds;
183
+ maskLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
184
+ maskLayer.colors = @[
185
+ (id)NSColor.whiteColor.CGColor,
186
+ (id)NSColor.whiteColor.CGColor,
187
+ (id)NSColor.clearColor.CGColor,
188
+ ];
189
+ maskLayer.locations = @[@0, @0.7, @1];
190
+ maskLayer.startPoint = CGPointMake(0.5, 1);
191
+ maskLayer.endPoint = CGPointMake(0.5, 0);
192
+ view.layer.mask = maskLayer;
193
+ }
194
+
195
+ static void RNSidebarSplitViewApplyColorOverlay(NSView *view, NSColor *color, CGFloat opacity)
196
+ {
197
+ if (color && opacity > 0) {
198
+ CALayer *overlayLayer = [CALayer layer];
199
+ overlayLayer.frame = view.bounds;
200
+ overlayLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
201
+ overlayLayer.backgroundColor = [color colorWithAlphaComponent:opacity].CGColor;
202
+ [view.layer addSublayer:overlayLayer];
203
+ }
204
+ }
205
+
206
+ // Pane containers are transparent, so a thin divider showed the window's (white) background through it,
207
+ // which is invisible in light mode and a bright stripe in dark mode. Paint it opaquely with semantic colors
208
+ // that resolve against the drawing appearance.
209
+ @interface RNSidebarSplitViewNativeSplitView : NSSplitView
210
+ /// YES while the user drags a divider.
211
+ @property (nonatomic, readonly) BOOL trackingDivider;
212
+ @end
213
+
214
+ @implementation RNSidebarSplitViewNativeSplitView
215
+
216
+ // NSSplitView only receives mouseDown: on a divider, and tracks the whole drag inside it.
217
+ - (void)mouseDown:(NSEvent *)event
218
+ {
219
+ _trackingDivider = YES;
220
+ [super mouseDown:event];
221
+ _trackingDivider = NO;
222
+ }
223
+
224
+ // While a divider drags, panes resize under a still cursor and pane edges pass beneath it. React views take
225
+ // hover from a window hit test, so claiming the hit here keeps rows from flickering hover states (and starting
226
+ // their hover animations) every frame of the drag.
227
+ - (NSView *)hitTest:(NSPoint)point
228
+ {
229
+ if (_trackingDivider) {
230
+ return NSPointInRect([self convertPoint:point fromView:self.superview], self.bounds) ? self : nil;
231
+ }
232
+ return [super hitTest:point];
233
+ }
234
+
235
+ - (NSColor *)dividerColor
236
+ {
237
+ return NSColor.separatorColor;
238
+ }
239
+
240
+ - (void)drawDividerInRect:(NSRect)rect
241
+ {
242
+ [NSColor.windowBackgroundColor setFill];
243
+ NSRectFill(rect);
244
+ [self.dividerColor setFill];
245
+ NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver);
246
+ }
247
+ @end
248
+
249
+ // List and content panes are opaque in the window background color, as AppKit panes are. React content
250
+ // follows a native resize one commit later; until then the newly exposed strip matches the window instead
251
+ // of showing a white stripe. The sidebar container stays clear so its native material shows.
252
+ @interface RNSidebarSplitViewPaneView : NSView
253
+ @end
254
+
255
+ @implementation RNSidebarSplitViewPaneView
256
+ - (BOOL)wantsUpdateLayer
257
+ {
258
+ return YES;
259
+ }
260
+
261
+ - (void)updateLayer
262
+ {
263
+ self.layer.backgroundColor = NSColor.windowBackgroundColor.CGColor;
264
+ }
265
+
266
+ - (void)viewDidChangeEffectiveAppearance
267
+ {
268
+ [super viewDidChangeEffectiveAppearance];
269
+ self.needsDisplay = YES;
270
+ }
271
+ @end
272
+
273
+ static char RNSidebarSplitViewStartupKey;
274
+
275
+ // Startup must stay entirely in AppKit: constructing a Fabric view here would
276
+ // read React feature flags before RCTReactNativeFactory configures them.
277
+ @interface RNSidebarSplitViewStartupView : NSView
278
+ - (instancetype)initWithFrame:(NSRect)frame configuration:(NSDictionary *)configuration;
279
+ @property (nonatomic, copy) void (^installReactRoot)(void);
280
+ - (void)finish;
281
+ @end
282
+
283
+ @implementation RNSidebarSplitViewStartupView {
284
+ NSSplitViewController *_controller;
285
+ NSView *_sidebar;
286
+ NSView *_content;
287
+ NSView *_titlebarMaterial;
288
+ CGFloat _sidebarWidth;
289
+ CGFloat _contentMinWidth;
290
+ BOOL _layingOut;
291
+ CGFloat _titlebarHeight;
292
+ }
293
+
294
+ - (instancetype)initWithFrame:(NSRect)frame configuration:(NSDictionary *)configuration
295
+ {
296
+ if (self = [super initWithFrame:frame]) {
297
+ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
298
+ self.appearance = RNSidebarSplitViewAppearanceForName(configuration[@"appearance"]);
299
+ _sidebarWidth = [configuration[@"sidebarWidth"] doubleValue];
300
+ _contentMinWidth = [configuration[@"contentMinWidth"] doubleValue];
301
+ NSColor *background = RNSidebarSplitViewColorFromHexString(configuration[@"backgroundColor"]);
302
+ self.wantsLayer = YES;
303
+ self.layer.backgroundColor = background.CGColor;
304
+
305
+ _sidebar = [NSView new];
306
+ _content = [NSView new];
307
+ _sidebar.wantsLayer = YES;
308
+ _content.wantsLayer = YES;
309
+ // AppKit supplies the sidebar material; an opaque fill hides its backdrop.
310
+ _sidebar.layer.backgroundColor = NSColor.clearColor.CGColor;
311
+ _content.layer.backgroundColor = background.CGColor;
312
+ _sidebar.layer.zPosition = 10;
313
+ NSViewController *sidebarController = [NSViewController new];
314
+ NSViewController *contentController = [NSViewController new];
315
+ sidebarController.view = _sidebar;
316
+ contentController.view = _content;
317
+ NSSplitViewItem *sidebarItem = [NSSplitViewItem sidebarWithViewController:sidebarController];
318
+ NSSplitViewItem *contentItem = [NSSplitViewItem splitViewItemWithViewController:contentController];
319
+ sidebarItem.minimumThickness = [configuration[@"sidebarMinWidth"] doubleValue];
320
+ sidebarItem.preferredThicknessFraction = 0.26;
321
+ sidebarItem.canCollapse = YES;
322
+ sidebarItem.collapsed = [configuration[@"sidebarCollapsed"] boolValue];
323
+ contentItem.minimumThickness = _contentMinWidth;
324
+ contentItem.canCollapse = NO;
325
+ sidebarItem.allowsFullHeightLayout = YES;
326
+ contentItem.allowsFullHeightLayout = YES;
327
+
328
+ _controller = [NSSplitViewController new];
329
+ _controller.minimumThicknessForInlineSidebars = 0;
330
+ _controller.splitView.vertical = YES;
331
+ _controller.splitView.dividerStyle = NSSplitViewDividerStyleThin;
332
+ [_controller addSplitViewItem:sidebarItem];
333
+ [_controller addSplitViewItem:contentItem];
334
+ _controller.view.frame = self.bounds;
335
+ _controller.view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
336
+ [self addSubview:_controller.view];
337
+
338
+ _titlebarHeight = [configuration[@"contentTitlebarHeight"] doubleValue];
339
+ if (_titlebarHeight > 0) {
340
+ _titlebarMaterial = RNSidebarSplitViewCreateTitlebarMaterialView(
341
+ @"glass", NSMakeRect(0, 0, NSWidth(frame), _titlebarHeight), background,
342
+ [configuration[@"appearance"] isEqualToString:@"dark"] ? 0 : 0.1);
343
+ [_content addSubview:_titlebarMaterial];
344
+ }
345
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(splitViewDidMount:)
346
+ name:@"LegendSidebarSplitViewDidMount" object:nil];
347
+ [self layout];
348
+ }
349
+ return self;
350
+ }
351
+
352
+ - (void)layout
353
+ {
354
+ [super layout];
355
+ if (!_controller || _layingOut) {
356
+ return;
357
+ }
358
+ _layingOut = YES;
359
+ _controller.view.frame = self.bounds;
360
+ CGFloat sidebarWidth = MIN(_sidebarWidth,
361
+ MAX(0, NSWidth(self.bounds) - _contentMinWidth - _controller.splitView.dividerThickness));
362
+ [_controller.splitView setPosition:sidebarWidth ofDividerAtIndex:0];
363
+ [_controller.splitView adjustSubviews];
364
+ [_controller.view layoutSubtreeIfNeeded];
365
+ NSRect contentFrame = [_controller.view convertRect:_controller.view.bounds toView:_content];
366
+ CGFloat height = MIN(_titlebarHeight, NSHeight(contentFrame));
367
+ _titlebarMaterial.frame = NSMakeRect(NSMinX(contentFrame),
368
+ _content.isFlipped ? NSMinY(contentFrame) : NSMaxY(contentFrame) - height,
369
+ NSWidth(contentFrame), height);
370
+ _layingOut = NO;
371
+ }
372
+
373
+ - (void)splitViewDidMount:(NSNotification *)notification
374
+ {
375
+ NSView *mountedView = notification.object;
376
+ if (self.window && mountedView.window == self.window) {
377
+ // Leave the Fabric/AppKit layout transaction before reparenting its root.
378
+ dispatch_async(dispatch_get_main_queue(), ^{ [self finish]; });
379
+ }
380
+ }
381
+
382
+ - (void)finish
383
+ {
384
+ if (!self.installReactRoot) {
385
+ return;
386
+ }
387
+ NSWindow *window = self.window;
388
+ NSResponder *firstResponder = window.firstResponder;
389
+ void (^installRoot)(void) = self.installReactRoot;
390
+ self.installReactRoot = nil;
391
+ [self removeFromSuperview];
392
+ objc_setAssociatedObject(window, &RNSidebarSplitViewStartupKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
393
+ // Removing the placeholder split clears AppKit's sidebar association. Reattach
394
+ // the live root before the next draw so its split registers with the window.
395
+ installRoot();
396
+ // Installing a content view controller in a visible window can focus its first
397
+ // key view. Preserve the previous focus, including an unfocused window, so the
398
+ // handoff does not introduce a focus ring or steal focus from an input.
399
+ if ([firstResponder isKindOfClass:NSView.class] && ((NSView *)firstResponder).window != window) {
400
+ firstResponder = nil;
401
+ }
402
+ [window makeFirstResponder:firstResponder];
403
+ }
404
+
405
+ - (void)dealloc
406
+ {
407
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
408
+ }
409
+
410
+ @end
411
+ #endif
412
+
413
+ #if TARGET_OS_OSX
414
+ @interface RNSidebarSplitViewComponent () <RCTSidebarSplitViewViewProtocol>
415
+ @end
416
+ #else
417
+ @interface RNSidebarSplitViewComponent () <RCTSidebarSplitViewViewProtocol>
418
+ @end
419
+ #endif
420
+
421
+ @implementation RNSidebarSplitViewComponent {
422
+ #if TARGET_OS_OSX
423
+ NSSplitViewController *_splitViewController;
424
+ NSViewController *_sidebarViewController;
425
+ NSViewController *_contentViewController;
426
+ NSViewController *_listViewController;
427
+ NSSplitViewItem *_sidebarItem;
428
+ NSSplitViewItem *_contentItem;
429
+ NSSplitViewItem *_listItem;
430
+ NSView *_sidebarContainer;
431
+ NSView *_contentContainer;
432
+ NSView *_listContainer;
433
+ RCTUIView<RCTComponentViewProtocol> *_sidebarReactView;
434
+ RCTUIView<RCTComponentViewProtocol> *_contentReactView;
435
+ RCTUIView<RCTComponentViewProtocol> *_listReactView;
436
+ id _resizeObserver;
437
+ LayoutMetrics _currentLayoutMetrics;
438
+ LayoutMetrics _sidebarReactLayoutMetrics;
439
+ LayoutMetrics _contentReactLayoutMetrics;
440
+ LayoutMetrics _listReactLayoutMetrics;
441
+ CGFloat _sidebarMinWidth;
442
+ CGFloat _sidebarWidth;
443
+ CGFloat _contentMinWidth;
444
+ CGFloat _listMinWidth;
445
+ CGFloat _listWidth;
446
+ BOOL _hasList;
447
+ BOOL _sidebarCollapsed;
448
+ // Preferred widths seed the dividers once; afterwards the user's drag owns them.
449
+ BOOL _needsPreferredDividerPositions;
450
+ // Our own layout pass resizes subviews several times; only its final state is published.
451
+ BOOL _layingOutSplitView;
452
+ CGFloat _lastSidebarWidth;
453
+ CGFloat _lastContentWidth;
454
+ CGFloat _lastListWidth;
455
+ CGFloat _lastHeight;
456
+ BOOL _lastLayoutReady;
457
+ BOOL _didPublishMount;
458
+ NSString *_appearanceName;
459
+ CGFloat _contentTitlebarHeight;
460
+ NSString *_contentTitlebarMaterialName;
461
+ NSString *_contentTitlebarOverlayColorValue;
462
+ CGFloat _contentTitlebarOverlayOpacity;
463
+ NSView *_contentTitlebarMaterialView;
464
+ NSString *_sidebarTitlebarOverlayColorValue;
465
+ CGFloat _sidebarTitlebarOverlayOpacity;
466
+ NSView *_sidebarTitlebarMaterialView;
467
+ NSSplitViewItemAccessoryViewController *_sidebarScrollEdgeAccessory API_AVAILABLE(macos(26.0));
468
+ NSLayoutConstraint *_sidebarScrollEdgeHeight;
469
+ #else
470
+ UIView *_sidebarContainer;
471
+ UIView *_contentContainer;
472
+ #endif
473
+ }
474
+
475
+ - (instancetype)initWithFrame:(CGRect)frame
476
+ {
477
+ if (self = [super initWithFrame:frame]) {
478
+ _props = std::make_shared<const SidebarSplitViewProps>();
479
+
480
+ #if TARGET_OS_OSX
481
+ _currentLayoutMetrics = EmptyLayoutMetrics;
482
+ _sidebarReactLayoutMetrics = EmptyLayoutMetrics;
483
+ _contentReactLayoutMetrics = EmptyLayoutMetrics;
484
+ _listReactLayoutMetrics = EmptyLayoutMetrics;
485
+ _sidebarMinWidth = 180;
486
+ _sidebarWidth = 0;
487
+ _contentMinWidth = 320;
488
+ _listMinWidth = 240;
489
+ _listWidth = 0;
490
+ _hasList = NO;
491
+ _sidebarCollapsed = NO;
492
+ _needsPreferredDividerPositions = YES;
493
+ _layingOutSplitView = NO;
494
+ _lastSidebarWidth = -1;
495
+ _lastContentWidth = -1;
496
+ _lastListWidth = -1;
497
+ _lastHeight = -1;
498
+ _lastLayoutReady = NO;
499
+ _appearanceName = @"system";
500
+ _contentTitlebarHeight = 0;
501
+ _contentTitlebarMaterialName = @"none";
502
+ _contentTitlebarOverlayOpacity = 0;
503
+ _sidebarTitlebarOverlayOpacity = 0;
504
+ _sidebarContainer = [NSView new];
505
+ _contentContainer = [RNSidebarSplitViewPaneView new];
506
+ _listContainer = [RNSidebarSplitViewPaneView new];
507
+ _sidebarContainer.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
508
+ _contentContainer.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
509
+ _listContainer.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
510
+ _sidebarContainer.wantsLayer = YES;
511
+ _contentContainer.wantsLayer = YES;
512
+ _listContainer.wantsLayer = YES;
513
+ _sidebarContainer.layer.masksToBounds = NO;
514
+ _contentContainer.layer.masksToBounds = NO;
515
+ _listContainer.layer.masksToBounds = YES;
516
+ _sidebarContainer.layer.zPosition = 10;
517
+ _contentContainer.layer.zPosition = 0;
518
+ _listContainer.layer.zPosition = 0;
519
+
520
+ _sidebarViewController = [NSViewController new];
521
+ _contentViewController = [NSViewController new];
522
+ _listViewController = [NSViewController new];
523
+ _sidebarViewController.view = _sidebarContainer;
524
+ _contentViewController.view = _contentContainer;
525
+ _listViewController.view = _listContainer;
526
+
527
+ _sidebarItem = [NSSplitViewItem sidebarWithViewController:_sidebarViewController];
528
+ _contentItem = [NSSplitViewItem splitViewItemWithViewController:_contentViewController];
529
+ // Mail-style middle column. Inserted between sidebar and content only while a list pane is supplied.
530
+ _listItem = [NSSplitViewItem contentListWithViewController:_listViewController];
531
+ _sidebarItem.canCollapse = YES;
532
+ _contentItem.canCollapse = NO;
533
+ _listItem.canCollapse = NO;
534
+ // Window resizes go to the content column; sidebar (260) and list keep their widths.
535
+ _listItem.holdingPriority = NSLayoutPriorityDefaultLow + 1;
536
+ [self updateSplitItemSizing];
537
+
538
+ if (@available(macOS 11.0, *)) {
539
+ _sidebarItem.allowsFullHeightLayout = YES;
540
+ _contentItem.allowsFullHeightLayout = YES;
541
+ _listItem.allowsFullHeightLayout = YES;
542
+ }
543
+
544
+ _splitViewController = [NSSplitViewController new];
545
+ _splitViewController.splitView = [RNSidebarSplitViewNativeSplitView new];
546
+ _splitViewController.minimumThicknessForInlineSidebars = 0;
547
+ _splitViewController.splitView.vertical = YES;
548
+ _splitViewController.splitView.dividerStyle = NSSplitViewDividerStyleThin;
549
+ _splitViewController.view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
550
+ [_splitViewController addSplitViewItem:_sidebarItem];
551
+ [_splitViewController addSplitViewItem:_contentItem];
552
+ [self applyAppearance];
553
+
554
+ __weak RNSidebarSplitViewComponent *weakSelf = self;
555
+ _resizeObserver = [[NSNotificationCenter defaultCenter]
556
+ addObserverForName:NSSplitViewDidResizeSubviewsNotification
557
+ object:_splitViewController.splitView
558
+ queue:NSOperationQueue.mainQueue
559
+ usingBlock:^(__unused NSNotification *notification) {
560
+ [weakSelf splitViewDidResize];
561
+ }];
562
+
563
+ [self addSubview:_splitViewController.view];
564
+ #else
565
+ _sidebarContainer = [UIView new];
566
+ _contentContainer = [UIView new];
567
+ [self addSubview:_sidebarContainer];
568
+ [self addSubview:_contentContainer];
569
+ #endif
570
+ }
571
+ return self;
572
+ }
573
+
574
+ #if TARGET_OS_OSX
575
+ - (BOOL)isFlipped
576
+ {
577
+ return YES;
578
+ }
579
+
580
+ - (void)updateSplitItemSizing
581
+ {
582
+ _sidebarItem.minimumThickness = MAX(120, _sidebarMinWidth);
583
+ _sidebarItem.preferredThicknessFraction = 0.26;
584
+ _contentItem.minimumThickness = MAX(240, _contentMinWidth);
585
+ _listItem.minimumThickness = MAX(120, _listMinWidth);
586
+ }
587
+
588
+ - (void)updateListItem
589
+ {
590
+ BOOL installed = [_splitViewController.splitViewItems containsObject:_listItem];
591
+ if (_hasList && !installed) {
592
+ [_splitViewController insertSplitViewItem:_listItem atIndex:1];
593
+ } else if (!_hasList && installed) {
594
+ [_splitViewController removeSplitViewItem:_listItem];
595
+ }
596
+ }
597
+
598
+ - (CGFloat)listReserveWidth
599
+ {
600
+ return _hasList ? _listItem.minimumThickness + _splitViewController.splitView.dividerThickness : 0;
601
+ }
602
+
603
+ - (CGFloat)preferredSidebarWidthForBounds:(CGRect)bounds
604
+ {
605
+ CGFloat dividerThickness = _splitViewController.splitView.dividerThickness;
606
+ CGFloat maxSidebarWidth = bounds.size.width - _contentItem.minimumThickness - dividerThickness - [self listReserveWidth];
607
+ CGFloat preferredSidebarWidth = _sidebarWidth > 0 ? _sidebarWidth : _sidebarMinWidth;
608
+ CGFloat sidebarWidth = MIN(MAX(_sidebarItem.minimumThickness, preferredSidebarWidth), maxSidebarWidth);
609
+ return MAX(0, sidebarWidth);
610
+ }
611
+
612
+ - (CGFloat)preferredListWidthForBounds:(CGRect)bounds sidebarExtent:(CGFloat)sidebarExtent
613
+ {
614
+ if (!_hasList) {
615
+ return 0;
616
+ }
617
+ CGFloat dividerThickness = _splitViewController.splitView.dividerThickness;
618
+ CGFloat maxListWidth = bounds.size.width - sidebarExtent - _contentItem.minimumThickness - dividerThickness;
619
+ CGFloat preferredListWidth = _listWidth > 0 ? _listWidth : _listMinWidth;
620
+ return MAX(0, MIN(MAX(_listItem.minimumThickness, preferredListWidth), maxListWidth));
621
+ }
622
+
623
+ - (void)updateSidebarCollapsed
624
+ {
625
+ if (_sidebarItem.collapsed != _sidebarCollapsed) {
626
+ _sidebarItem.collapsed = _sidebarCollapsed;
627
+ }
628
+ }
629
+
630
+ - (void)applyAppearance
631
+ {
632
+ NSAppearance *appearance = RNSidebarSplitViewAppearanceForName(_appearanceName);
633
+ self.appearance = appearance;
634
+ _splitViewController.view.appearance = appearance;
635
+ _splitViewController.splitView.appearance = appearance;
636
+ _sidebarContainer.appearance = appearance;
637
+ _contentContainer.appearance = appearance;
638
+ _listContainer.appearance = appearance;
639
+ [_splitViewController.view setNeedsDisplay:YES];
640
+ [_splitViewController.splitView setNeedsDisplay:YES];
641
+ [_sidebarContainer setNeedsDisplay:YES];
642
+ [_contentContainer setNeedsDisplay:YES];
643
+ }
644
+
645
+ - (void)removeContentTitlebarMaterial
646
+ {
647
+ [_contentTitlebarMaterialView removeFromSuperview];
648
+ _contentTitlebarMaterialView = nil;
649
+ }
650
+
651
+ - (void)removeSidebarTitlebarMaterial
652
+ {
653
+ [_sidebarTitlebarMaterialView removeFromSuperview];
654
+ _sidebarTitlebarMaterialView = nil;
655
+ if (@available(macOS 26.1, *)) {
656
+ if (_sidebarScrollEdgeAccessory) {
657
+ NSUInteger index = [_sidebarItem.topAlignedAccessoryViewControllers indexOfObject:_sidebarScrollEdgeAccessory];
658
+ if (index != NSNotFound) {
659
+ [_sidebarItem removeTopAlignedAccessoryViewControllerAtIndex:index];
660
+ }
661
+ _sidebarScrollEdgeAccessory = nil;
662
+ _sidebarScrollEdgeHeight = nil;
663
+ }
664
+ }
665
+ }
666
+
667
+ - (void)layoutSidebarTitlebarMaterialWithHeight:(CGFloat)titlebarHeight
668
+ {
669
+ NSRect splitFrameInSidebar = [_splitViewController.view convertRect:_splitViewController.view.bounds
670
+ toView:_sidebarContainer];
671
+ if (titlebarHeight <= 0 || NSWidth(splitFrameInSidebar) <= 0) {
672
+ [self removeSidebarTitlebarMaterial];
673
+ return;
674
+ }
675
+
676
+ if (@available(macOS 26.1, *)) {
677
+ // AppKit already accounts for the window titlebar above the accessory.
678
+ // Only register any additional header height, not a second full titlebar.
679
+ CGFloat nativeTitlebarHeight = MAX(0, NSHeight(self.window.frame) - NSHeight(self.window.contentLayoutRect));
680
+ CGFloat accessoryHeight = MAX(0, titlebarHeight - nativeTitlebarHeight);
681
+ if (!_sidebarScrollEdgeAccessory) {
682
+ _sidebarScrollEdgeAccessory = [NSSplitViewItemAccessoryViewController new];
683
+ _sidebarScrollEdgeAccessory.automaticallyAppliesContentInsets = NO;
684
+ _sidebarScrollEdgeAccessory.preferredScrollEdgeEffectStyle = NSScrollEdgeEffectStyle.softStyle;
685
+ // Register the existing header region with NSScrollView's native edge
686
+ // effect. React retains ownership of its existing content inset.
687
+ NSView *accessoryView = [RNSidebarSplitViewTitlebarMaterialContainerView new];
688
+ _sidebarScrollEdgeAccessory.view = accessoryView;
689
+ _sidebarScrollEdgeHeight = [accessoryView.heightAnchor constraintEqualToConstant:accessoryHeight];
690
+ _sidebarScrollEdgeHeight.active = YES;
691
+ [_sidebarItem addTopAlignedAccessoryViewController:_sidebarScrollEdgeAccessory];
692
+ }
693
+ _sidebarScrollEdgeHeight.constant = accessoryHeight;
694
+ return;
695
+ }
696
+
697
+ CGFloat materialHeight = MIN(titlebarHeight + 10, NSHeight(splitFrameInSidebar));
698
+ CGFloat materialY = _sidebarContainer.isFlipped
699
+ ? NSMinY(splitFrameInSidebar)
700
+ : NSMaxY(splitFrameInSidebar) - materialHeight;
701
+ NSRect materialFrame = NSMakeRect(
702
+ NSMinX(splitFrameInSidebar),
703
+ materialY,
704
+ NSWidth(splitFrameInSidebar),
705
+ materialHeight);
706
+
707
+ if (!_sidebarTitlebarMaterialView) {
708
+ _sidebarTitlebarMaterialView = RNSidebarSplitViewCreateBackgroundBlurView(materialFrame, 2);
709
+ RNSidebarSplitViewApplySoftBottomEdgeMask(_sidebarTitlebarMaterialView);
710
+ RNSidebarSplitViewApplyColorOverlay(
711
+ _sidebarTitlebarMaterialView,
712
+ RNSidebarSplitViewColorFromHexString(_sidebarTitlebarOverlayColorValue),
713
+ _sidebarTitlebarOverlayOpacity);
714
+ } else {
715
+ _sidebarTitlebarMaterialView.frame = materialFrame;
716
+ }
717
+
718
+ if (_sidebarTitlebarMaterialView.superview != _sidebarContainer) {
719
+ [_sidebarTitlebarMaterialView removeFromSuperview];
720
+ }
721
+ [_sidebarContainer addSubview:_sidebarTitlebarMaterialView
722
+ positioned:NSWindowAbove
723
+ relativeTo:_sidebarReactView];
724
+ }
725
+
726
+ - (void)layoutContentTitlebarMaterial
727
+ {
728
+ if (_contentTitlebarHeight <= 0 ||
729
+ _contentTitlebarMaterialName.length == 0 ||
730
+ [_contentTitlebarMaterialName isEqualToString:@"none"] ||
731
+ !_contentContainer.superview) {
732
+ [self removeContentTitlebarMaterial];
733
+ [self removeSidebarTitlebarMaterial];
734
+ return;
735
+ }
736
+
737
+ NSRect splitFrameInContent = [_splitViewController.view convertRect:_splitViewController.view.bounds toView:_contentContainer];
738
+ CGFloat materialHeight = MIN(_contentTitlebarHeight, NSHeight(splitFrameInContent));
739
+ if (materialHeight <= 0 || NSWidth(splitFrameInContent) <= 0) {
740
+ [self removeContentTitlebarMaterial];
741
+ [self removeSidebarTitlebarMaterial];
742
+ return;
743
+ }
744
+
745
+ CGFloat materialY = _contentContainer.isFlipped
746
+ ? NSMinY(splitFrameInContent)
747
+ : NSMaxY(splitFrameInContent) - materialHeight;
748
+ NSRect materialFrame = NSMakeRect(NSMinX(splitFrameInContent), materialY, NSWidth(splitFrameInContent), materialHeight);
749
+
750
+ if (!_contentTitlebarMaterialView) {
751
+ NSColor *overlayColor = RNSidebarSplitViewColorFromHexString(_contentTitlebarOverlayColorValue);
752
+ CGFloat overlayOpacity = RNSidebarSplitViewClampedUnitValue(_contentTitlebarOverlayOpacity);
753
+ _contentTitlebarMaterialView = RNSidebarSplitViewCreateTitlebarMaterialView(
754
+ _contentTitlebarMaterialName,
755
+ materialFrame,
756
+ overlayColor,
757
+ overlayOpacity);
758
+ } else {
759
+ _contentTitlebarMaterialView.frame = materialFrame;
760
+ }
761
+
762
+ if (_contentTitlebarMaterialView.superview != _contentContainer) {
763
+ [_contentTitlebarMaterialView removeFromSuperview];
764
+ [_contentContainer addSubview:_contentTitlebarMaterialView positioned:NSWindowAbove relativeTo:_contentReactView];
765
+ } else {
766
+ [_contentContainer addSubview:_contentTitlebarMaterialView positioned:NSWindowAbove relativeTo:_contentReactView];
767
+ }
768
+
769
+ [self layoutSidebarTitlebarMaterialWithHeight:materialHeight];
770
+
771
+ _sidebarContainer.layer.zPosition = 10;
772
+ _contentContainer.layer.zPosition = 0;
773
+ }
774
+
775
+ - (void)syncReactSubviewFrames
776
+ {
777
+ CGRect sidebarBounds = _sidebarContainer.bounds;
778
+ CGRect contentBounds = _contentContainer.bounds;
779
+
780
+ [self syncReactSubview:_sidebarReactView
781
+ nativeBounds:sidebarBounds
782
+ previousLayoutMetrics:&_sidebarReactLayoutMetrics];
783
+ [self syncReactSubview:_contentReactView
784
+ nativeBounds:contentBounds
785
+ previousLayoutMetrics:&_contentReactLayoutMetrics];
786
+ [self syncReactSubview:_listReactView
787
+ nativeBounds:_hasList ? _listContainer.bounds : CGRectZero
788
+ previousLayoutMetrics:&_listReactLayoutMetrics];
789
+ }
790
+
791
+ - (void)syncReactSubview:(nullable RCTUIView<RCTComponentViewProtocol> *)subview
792
+ nativeBounds:(CGRect)nativeBounds
793
+ previousLayoutMetrics:(LayoutMetrics *)previousLayoutMetrics
794
+ {
795
+ if (!subview) {
796
+ return;
797
+ }
798
+
799
+ subview.hidden = nativeBounds.size.width <= 0 || nativeBounds.size.height <= 0;
800
+ subview.translatesAutoresizingMaskIntoConstraints = YES;
801
+ subview.frame = nativeBounds;
802
+ LayoutMetrics nextLayoutMetrics = _currentLayoutMetrics;
803
+ if (nextLayoutMetrics == EmptyLayoutMetrics) {
804
+ nextLayoutMetrics = LayoutMetrics{};
805
+ }
806
+ nextLayoutMetrics.frame = facebook::react::Rect{
807
+ facebook::react::Point{0, 0},
808
+ facebook::react::Size{(Float)nativeBounds.size.width, (Float)nativeBounds.size.height},
809
+ };
810
+ nextLayoutMetrics.contentInsets = {};
811
+ nextLayoutMetrics.borderWidth = {};
812
+ nextLayoutMetrics.overflowInset = {};
813
+
814
+ [subview updateLayoutMetrics:nextLayoutMetrics oldLayoutMetrics:*previousLayoutMetrics];
815
+ [subview finalizeUpdates:RNComponentViewUpdateMaskLayoutMetrics];
816
+ *previousLayoutMetrics = nextLayoutMetrics;
817
+ subview.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
818
+ [subview setNeedsLayout:YES];
819
+ [subview layoutSubtreeIfNeeded];
820
+ }
821
+
822
+ - (void)emitSplitViewDidResizeWithSidebarWidth:(CGFloat)sidebarWidth
823
+ contentWidth:(CGFloat)contentWidth
824
+ contentX:(CGFloat)contentX
825
+ sidebarHeight:(CGFloat)sidebarHeight
826
+ contentHeight:(CGFloat)contentHeight
827
+ height:(CGFloat)height
828
+ listWidth:(CGFloat)listWidth
829
+ listX:(CGFloat)listX
830
+ layoutReady:(BOOL)layoutReady
831
+ {
832
+ const auto eventEmitter = std::static_pointer_cast<const SidebarSplitViewEventEmitter>(_eventEmitter);
833
+ if (!eventEmitter) {
834
+ return;
835
+ }
836
+
837
+ if (contentWidth <= 0 || height <= 0) {
838
+ return;
839
+ }
840
+
841
+ BOOL panesReady = layoutReady && _sidebarReactView && _contentReactView && (!_hasList || _listReactView);
842
+ if (panesReady && self.window && !_didPublishMount) {
843
+ // This also runs when an already-laid-out Fabric tree joins its window.
844
+ // Keep it before metrics deduplication so the startup cover cannot linger.
845
+ _didPublishMount = YES;
846
+ [[NSNotificationCenter defaultCenter] postNotificationName:@"LegendSidebarSplitViewDidMount"
847
+ object:self];
848
+ }
849
+ if (fabs(sidebarWidth - _lastSidebarWidth) < 0.5 &&
850
+ fabs(contentWidth - _lastContentWidth) < 0.5 &&
851
+ fabs(listWidth - _lastListWidth) < 0.5 &&
852
+ fabs(height - _lastHeight) < 0.5 &&
853
+ panesReady == _lastLayoutReady) {
854
+ return;
855
+ }
856
+
857
+ _lastSidebarWidth = sidebarWidth;
858
+ _lastContentWidth = contentWidth;
859
+ _lastListWidth = listWidth;
860
+ _lastHeight = height;
861
+ _lastLayoutReady = panesReady;
862
+
863
+ eventEmitter->onSplitViewDidResize(SidebarSplitViewEventEmitter::OnSplitViewDidResize{
864
+ .contentHeight = contentHeight,
865
+ .contentWidth = contentWidth,
866
+ .contentX = contentX,
867
+ .height = height,
868
+ .isLayoutReady = static_cast<bool>(panesReady),
869
+ .isVertical = true,
870
+ .listHeight = listWidth > 0 ? height : 0,
871
+ .listWidth = listWidth,
872
+ .listX = listX,
873
+ .sidebarHeight = sidebarHeight,
874
+ .sidebarWidth = sidebarWidth,
875
+ });
876
+ }
877
+
878
+ - (BOOL)applyEstimatedSplitViewLayoutForBounds:(CGRect)bounds layoutReady:(BOOL)layoutReady
879
+ {
880
+ if (bounds.size.width <= 0 || bounds.size.height <= 0) {
881
+ return NO;
882
+ }
883
+
884
+ CGFloat dividerThickness = _splitViewController.splitView.dividerThickness;
885
+ CGFloat sidebarWidth = 0;
886
+ if (!_sidebarCollapsed) {
887
+ sidebarWidth = [self preferredSidebarWidthForBounds:bounds];
888
+ }
889
+ CGFloat listX = sidebarWidth > 0 ? sidebarWidth + dividerThickness : 0;
890
+ CGFloat listWidth = [self preferredListWidthForBounds:bounds sidebarExtent:listX];
891
+ CGFloat contentX = listWidth > 0 ? listX + listWidth + dividerThickness : listX;
892
+ CGFloat contentWidth = MAX(0, bounds.size.width - contentX);
893
+ if (contentWidth <= 0) {
894
+ contentWidth = bounds.size.width;
895
+ contentX = 0;
896
+ listWidth = 0;
897
+ }
898
+
899
+ _splitViewController.view.frame = bounds;
900
+ _splitViewController.splitView.frame = bounds;
901
+ _sidebarContainer.frame = CGRectMake(0, 0, sidebarWidth, bounds.size.height);
902
+ _listContainer.frame = CGRectMake(listX, 0, listWidth, bounds.size.height);
903
+ _contentContainer.frame = CGRectMake(contentX, 0, contentWidth, bounds.size.height);
904
+
905
+ CGRect sidebarBounds = CGRectMake(0, 0, sidebarWidth, bounds.size.height);
906
+ CGRect contentBounds = CGRectMake(0, 0, contentWidth, bounds.size.height);
907
+ [self syncReactSubview:_sidebarReactView
908
+ nativeBounds:sidebarBounds
909
+ previousLayoutMetrics:&_sidebarReactLayoutMetrics];
910
+ [self syncReactSubview:_contentReactView
911
+ nativeBounds:contentBounds
912
+ previousLayoutMetrics:&_contentReactLayoutMetrics];
913
+ [self syncReactSubview:_listReactView
914
+ nativeBounds:CGRectMake(0, 0, listWidth, bounds.size.height)
915
+ previousLayoutMetrics:&_listReactLayoutMetrics];
916
+ [self layoutContentTitlebarMaterial];
917
+ if (!_layingOutSplitView) {
918
+ [self emitSplitViewDidResizeWithSidebarWidth:sidebarWidth
919
+ contentWidth:contentWidth
920
+ contentX:contentX
921
+ sidebarHeight:bounds.size.height
922
+ contentHeight:bounds.size.height
923
+ height:bounds.size.height
924
+ listWidth:listWidth
925
+ listX:_hasList ? listX : 0
926
+ layoutReady:layoutReady];
927
+ }
928
+
929
+ return YES;
930
+ }
931
+
932
+ - (void)publishSplitViewLayoutAllowEstimatedReady:(BOOL)allowEstimatedReady
933
+ {
934
+ CGFloat sidebarWidth = _sidebarContainer.bounds.size.width;
935
+ CGFloat contentWidth = _contentContainer.bounds.size.width;
936
+ CGFloat contentX = [_contentContainer convertRect:_contentContainer.bounds toView:self].origin.x;
937
+ CGFloat sidebarHeight = _sidebarContainer.bounds.size.height;
938
+ CGFloat contentHeight = _contentContainer.bounds.size.height;
939
+ CGFloat listWidth = _hasList ? _listContainer.bounds.size.width : 0;
940
+ CGFloat listX = _hasList ? [_listContainer convertRect:_listContainer.bounds toView:self].origin.x : 0;
941
+ CGFloat height = MAX(sidebarHeight, contentHeight);
942
+ CGRect bounds = [self currentLayoutBounds];
943
+
944
+ if (contentWidth <= 0 || height <= 0 ||
945
+ contentX < -0.5 ||
946
+ contentX + contentWidth > bounds.size.width + 0.5 ||
947
+ fabs(_contentContainer.bounds.size.height - bounds.size.height) >= 0.5 ||
948
+ (_hasList && listWidth <= 0)) {
949
+ [self applyEstimatedSplitViewLayoutForBounds:bounds layoutReady:allowEstimatedReady];
950
+ return;
951
+ }
952
+
953
+ [self syncReactSubviewFrames];
954
+ [self layoutContentTitlebarMaterial];
955
+ [self emitSplitViewDidResizeWithSidebarWidth:sidebarWidth
956
+ contentWidth:contentWidth
957
+ contentX:contentX
958
+ sidebarHeight:sidebarHeight
959
+ contentHeight:contentHeight
960
+ height:height
961
+ listWidth:listWidth
962
+ listX:listX
963
+ layoutReady:YES];
964
+ }
965
+
966
+ - (CGRect)currentLayoutBounds
967
+ {
968
+ CGRect bounds = self.bounds;
969
+ if ((bounds.size.width <= 0 || bounds.size.height <= 0) && _currentLayoutMetrics != EmptyLayoutMetrics) {
970
+ bounds = CGRectMake(
971
+ 0,
972
+ 0,
973
+ _currentLayoutMetrics.frame.size.width,
974
+ _currentLayoutMetrics.frame.size.height);
975
+ }
976
+ return bounds;
977
+ }
978
+
979
+ /// Seeds dividers from the preferred widths. Runs only until it succeeds once (and again when those props
980
+ /// change), so a later layout pass never snaps a divider the user dragged back to its preferred position.
981
+ - (void)applyDividerPositionForBounds:(CGRect)bounds
982
+ {
983
+ if (!_needsPreferredDividerPositions || bounds.size.width <= 0 || _splitViewController.splitView.subviews.count < 2) {
984
+ return;
985
+ }
986
+ CGFloat dividerThickness = _splitViewController.splitView.dividerThickness;
987
+ CGFloat sidebarExtent = 0;
988
+ if (!_sidebarCollapsed) {
989
+ CGFloat sidebarWidth = [self preferredSidebarWidthForBounds:bounds];
990
+ if (sidebarWidth <= 0) {
991
+ return;
992
+ }
993
+ [_splitViewController.splitView setPosition:sidebarWidth ofDividerAtIndex:0];
994
+ sidebarExtent = sidebarWidth + dividerThickness;
995
+ }
996
+ if (_hasList) {
997
+ if (_splitViewController.splitView.subviews.count < 3) {
998
+ return;
999
+ }
1000
+ CGFloat listWidth = [self preferredListWidthForBounds:bounds sidebarExtent:sidebarExtent];
1001
+ if (listWidth <= 0) {
1002
+ return;
1003
+ }
1004
+ [_splitViewController.splitView setPosition:sidebarExtent + listWidth ofDividerAtIndex:1];
1005
+ }
1006
+ // A small startup frame can clamp a preference. Retry on later layouts until it fits,
1007
+ // unless a real divider drag takes ownership in splitViewDidResize.
1008
+ CGFloat desiredSidebarWidth = MAX(_sidebarItem.minimumThickness, _sidebarWidth > 0 ? _sidebarWidth : _sidebarMinWidth);
1009
+ CGFloat desiredListWidth = MAX(_listItem.minimumThickness, _listWidth > 0 ? _listWidth : _listMinWidth);
1010
+ _needsPreferredDividerPositions =
1011
+ (!_sidebarCollapsed && [self preferredSidebarWidthForBounds:bounds] < desiredSidebarWidth - 0.5) ||
1012
+ (_hasList && [self preferredListWidthForBounds:bounds sidebarExtent:sidebarExtent] < desiredListWidth - 0.5);
1013
+ }
1014
+
1015
+ - (void)splitViewDidResize
1016
+ {
1017
+ if (_layingOutSplitView) {
1018
+ return;
1019
+ }
1020
+ if (((RNSidebarSplitViewNativeSplitView *)_splitViewController.splitView).trackingDivider) {
1021
+ _needsPreferredDividerPositions = NO;
1022
+ }
1023
+ [self publishSplitViewLayoutAllowEstimatedReady:NO];
1024
+ }
1025
+
1026
+ - (void)layoutSplitView
1027
+ {
1028
+ if (_layingOutSplitView) {
1029
+ return;
1030
+ }
1031
+ _layingOutSplitView = YES;
1032
+ CGRect bounds = [self currentLayoutBounds];
1033
+ _splitViewController.view.frame = bounds;
1034
+ _splitViewController.splitView.frame = bounds;
1035
+ [self updateSplitItemSizing];
1036
+ [self updateListItem];
1037
+ [self updateSidebarCollapsed];
1038
+ if (_contentContainer.bounds.size.width <= 0 ||
1039
+ _contentContainer.bounds.size.height <= 0 ||
1040
+ fabs(_contentContainer.bounds.size.height - bounds.size.height) >= 0.5) {
1041
+ [self applyEstimatedSplitViewLayoutForBounds:bounds layoutReady:NO];
1042
+ }
1043
+ [self applyDividerPositionForBounds:bounds];
1044
+ [_splitViewController.view layoutSubtreeIfNeeded];
1045
+ [self layoutContentTitlebarMaterial];
1046
+ _layingOutSplitView = NO;
1047
+ [self publishSplitViewLayoutAllowEstimatedReady:YES];
1048
+ }
1049
+
1050
+ - (void)updateEventEmitter:(const EventEmitter::Shared &)eventEmitter
1051
+ {
1052
+ [super updateEventEmitter:eventEmitter];
1053
+
1054
+ dispatch_async(dispatch_get_main_queue(), ^{
1055
+ [self publishSplitViewLayoutAllowEstimatedReady:NO];
1056
+ });
1057
+ }
1058
+ #endif
1059
+
1060
+ - (void)mountChildComponentView:(RCTUIView<RCTComponentViewProtocol> *)childComponentView
1061
+ index:(NSInteger)index
1062
+ {
1063
+ #if TARGET_OS_OSX
1064
+ if (index == 0) {
1065
+ [_sidebarReactView removeFromSuperview];
1066
+ _sidebarReactView = childComponentView;
1067
+ _sidebarReactLayoutMetrics = EmptyLayoutMetrics;
1068
+ childComponentView.hidden = YES;
1069
+ [_sidebarContainer addSubview:childComponentView];
1070
+ if (_sidebarContainer.bounds.size.width <= 0 || _sidebarContainer.bounds.size.height <= 0) {
1071
+ [self applyEstimatedSplitViewLayoutForBounds:[self currentLayoutBounds] layoutReady:NO];
1072
+ } else {
1073
+ [self syncReactSubview:_sidebarReactView
1074
+ nativeBounds:_sidebarContainer.bounds
1075
+ previousLayoutMetrics:&_sidebarReactLayoutMetrics];
1076
+ }
1077
+ dispatch_async(dispatch_get_main_queue(), ^{
1078
+ [self publishSplitViewLayoutAllowEstimatedReady:NO];
1079
+ });
1080
+ return;
1081
+ }
1082
+
1083
+ if (index == 1) {
1084
+ [_contentReactView removeFromSuperview];
1085
+ _contentReactView = childComponentView;
1086
+ _contentReactLayoutMetrics = EmptyLayoutMetrics;
1087
+ childComponentView.hidden = YES;
1088
+ [_contentContainer addSubview:childComponentView];
1089
+ if (_contentContainer.bounds.size.width <= 0 || _contentContainer.bounds.size.height <= 0) {
1090
+ [self applyEstimatedSplitViewLayoutForBounds:[self currentLayoutBounds] layoutReady:NO];
1091
+ } else {
1092
+ [self syncReactSubview:_contentReactView
1093
+ nativeBounds:_contentContainer.bounds
1094
+ previousLayoutMetrics:&_contentReactLayoutMetrics];
1095
+ }
1096
+ dispatch_async(dispatch_get_main_queue(), ^{
1097
+ [self publishSplitViewLayoutAllowEstimatedReady:NO];
1098
+ });
1099
+ return;
1100
+ }
1101
+
1102
+ if (index == 2) {
1103
+ [_listReactView removeFromSuperview];
1104
+ _listReactView = childComponentView;
1105
+ _listReactLayoutMetrics = EmptyLayoutMetrics;
1106
+ childComponentView.hidden = YES;
1107
+ [_listContainer addSubview:childComponentView];
1108
+ [self syncReactSubview:_listReactView
1109
+ nativeBounds:_hasList ? _listContainer.bounds : CGRectZero
1110
+ previousLayoutMetrics:&_listReactLayoutMetrics];
1111
+ dispatch_async(dispatch_get_main_queue(), ^{
1112
+ [self publishSplitViewLayoutAllowEstimatedReady:NO];
1113
+ });
1114
+ return;
1115
+ }
1116
+ #else
1117
+ if (index == 0) {
1118
+ [_sidebarContainer addSubview:childComponentView];
1119
+ return;
1120
+ }
1121
+
1122
+ if (index == 1 || index == 2) {
1123
+ [_contentContainer addSubview:childComponentView];
1124
+ return;
1125
+ }
1126
+ #endif
1127
+
1128
+ [super mountChildComponentView:childComponentView index:index];
1129
+ }
1130
+
1131
+ - (void)unmountChildComponentView:(RCTUIView<RCTComponentViewProtocol> *)childComponentView
1132
+ index:(NSInteger)index
1133
+ {
1134
+ #if TARGET_OS_OSX
1135
+ if (childComponentView == _sidebarReactView) {
1136
+ _sidebarReactView = nil;
1137
+ _sidebarReactLayoutMetrics = EmptyLayoutMetrics;
1138
+ [childComponentView removeFromSuperview];
1139
+ return;
1140
+ }
1141
+
1142
+ if (childComponentView == _contentReactView) {
1143
+ _contentReactView = nil;
1144
+ _contentReactLayoutMetrics = EmptyLayoutMetrics;
1145
+ [childComponentView removeFromSuperview];
1146
+ return;
1147
+ }
1148
+
1149
+ if (childComponentView == _listReactView) {
1150
+ _listReactView = nil;
1151
+ _listReactLayoutMetrics = EmptyLayoutMetrics;
1152
+ [childComponentView removeFromSuperview];
1153
+ return;
1154
+ }
1155
+ #else
1156
+ if (index == 0 || index == 1 || index == 2) {
1157
+ [childComponentView removeFromSuperview];
1158
+ return;
1159
+ }
1160
+ #endif
1161
+
1162
+ [super unmountChildComponentView:childComponentView index:index];
1163
+ }
1164
+
1165
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
1166
+ {
1167
+ const auto &newProps = *std::static_pointer_cast<SidebarSplitViewProps const>(props);
1168
+
1169
+ #if TARGET_OS_OSX
1170
+ NSString *nextAppearanceName = [NSString stringWithUTF8String:newProps.appearance.c_str()];
1171
+ if (nextAppearanceName.length == 0) {
1172
+ nextAppearanceName = @"system";
1173
+ }
1174
+ BOOL preferredWidthsChanged =
1175
+ fabs(_sidebarWidth - newProps.sidebarWidth) >= 0.5 ||
1176
+ fabs(_listWidth - newProps.listWidth) >= 0.5 ||
1177
+ _hasList != newProps.hasList ||
1178
+ _sidebarCollapsed != newProps.sidebarCollapsed;
1179
+ BOOL shouldRelayout =
1180
+ preferredWidthsChanged ||
1181
+ fabs(_sidebarMinWidth - newProps.sidebarMinWidth) >= 0.5 ||
1182
+ fabs(_contentMinWidth - newProps.contentMinWidth) >= 0.5 ||
1183
+ fabs(_listMinWidth - newProps.listMinWidth) >= 0.5 ||
1184
+ fabs(_contentTitlebarHeight - newProps.contentTitlebarHeight) >= 0.5;
1185
+ NSString *nextContentTitlebarMaterialName = [NSString stringWithUTF8String:newProps.contentTitlebarMaterial.c_str()];
1186
+ if (nextContentTitlebarMaterialName.length == 0) {
1187
+ nextContentTitlebarMaterialName = @"none";
1188
+ }
1189
+ NSString *nextContentTitlebarOverlayColorValue = [NSString stringWithUTF8String:newProps.contentTitlebarOverlayColor.c_str()];
1190
+ if (nextContentTitlebarOverlayColorValue.length == 0) {
1191
+ nextContentTitlebarOverlayColorValue = nil;
1192
+ }
1193
+ CGFloat nextContentTitlebarOverlayOpacity = RNSidebarSplitViewClampedUnitValue(newProps.contentTitlebarOverlayOpacity);
1194
+ NSString *nextSidebarTitlebarOverlayColorValue = [NSString stringWithUTF8String:newProps.sidebarTitlebarOverlayColor.c_str()];
1195
+ if (nextSidebarTitlebarOverlayColorValue.length == 0) {
1196
+ nextSidebarTitlebarOverlayColorValue = nil;
1197
+ }
1198
+ CGFloat nextSidebarTitlebarOverlayOpacity = RNSidebarSplitViewClampedUnitValue(newProps.sidebarTitlebarOverlayOpacity);
1199
+ BOOL shouldRecreateContentTitlebarMaterial =
1200
+ ![_contentTitlebarMaterialName isEqualToString:nextContentTitlebarMaterialName] ||
1201
+ !((_contentTitlebarOverlayColorValue == nextContentTitlebarOverlayColorValue) ||
1202
+ [_contentTitlebarOverlayColorValue isEqualToString:nextContentTitlebarOverlayColorValue]) ||
1203
+ fabs(_contentTitlebarOverlayOpacity - nextContentTitlebarOverlayOpacity) >= 0.001 ||
1204
+ fabs(_contentTitlebarHeight - newProps.contentTitlebarHeight) >= 0.5;
1205
+ BOOL shouldRecreateSidebarTitlebarMaterial =
1206
+ !((_sidebarTitlebarOverlayColorValue == nextSidebarTitlebarOverlayColorValue) ||
1207
+ [_sidebarTitlebarOverlayColorValue isEqualToString:nextSidebarTitlebarOverlayColorValue]) ||
1208
+ fabs(_sidebarTitlebarOverlayOpacity - nextSidebarTitlebarOverlayOpacity) >= 0.001 ||
1209
+ fabs(_contentTitlebarHeight - newProps.contentTitlebarHeight) >= 0.5;
1210
+ _sidebarMinWidth = newProps.sidebarMinWidth;
1211
+ _sidebarWidth = newProps.sidebarWidth;
1212
+ _contentMinWidth = newProps.contentMinWidth;
1213
+ _listMinWidth = newProps.listMinWidth;
1214
+ _listWidth = newProps.listWidth;
1215
+ _hasList = newProps.hasList;
1216
+ _sidebarCollapsed = newProps.sidebarCollapsed;
1217
+ if (preferredWidthsChanged) {
1218
+ _needsPreferredDividerPositions = YES;
1219
+ }
1220
+ _contentTitlebarHeight = newProps.contentTitlebarHeight;
1221
+ _contentTitlebarMaterialName = nextContentTitlebarMaterialName;
1222
+ _contentTitlebarOverlayColorValue = nextContentTitlebarOverlayColorValue;
1223
+ _contentTitlebarOverlayOpacity = nextContentTitlebarOverlayOpacity;
1224
+ _sidebarTitlebarOverlayColorValue = nextSidebarTitlebarOverlayColorValue;
1225
+ _sidebarTitlebarOverlayOpacity = nextSidebarTitlebarOverlayOpacity;
1226
+ if (shouldRecreateContentTitlebarMaterial) {
1227
+ [self removeContentTitlebarMaterial];
1228
+ }
1229
+ if (shouldRecreateSidebarTitlebarMaterial) {
1230
+ [self removeSidebarTitlebarMaterial];
1231
+ }
1232
+ if (![_appearanceName isEqualToString:nextAppearanceName]) {
1233
+ _appearanceName = nextAppearanceName;
1234
+ [self applyAppearance];
1235
+ }
1236
+ #endif
1237
+
1238
+ [super updateProps:props oldProps:oldProps];
1239
+
1240
+ #if TARGET_OS_OSX
1241
+ if (shouldRelayout || shouldRecreateContentTitlebarMaterial || shouldRecreateSidebarTitlebarMaterial) {
1242
+ _lastSidebarWidth = -1;
1243
+ _lastContentWidth = -1;
1244
+ _lastListWidth = -1;
1245
+ _lastHeight = -1;
1246
+ _lastLayoutReady = NO;
1247
+ [self layoutSplitView];
1248
+ }
1249
+ #endif
1250
+ }
1251
+
1252
+ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
1253
+ oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
1254
+ {
1255
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
1256
+
1257
+ #if TARGET_OS_OSX
1258
+ _currentLayoutMetrics = layoutMetrics;
1259
+ [self layoutSplitView];
1260
+ #else
1261
+ CGFloat sidebarWidth = self.bounds.size.width * 0.26;
1262
+ _sidebarContainer.frame = CGRectMake(0, 0, sidebarWidth, self.bounds.size.height);
1263
+ _contentContainer.frame = CGRectMake(sidebarWidth, 0, self.bounds.size.width - sidebarWidth, self.bounds.size.height);
1264
+ #endif
1265
+ }
1266
+
1267
+ #if TARGET_OS_OSX
1268
+ - (void)layout
1269
+ {
1270
+ [super layout];
1271
+
1272
+ [self layoutSplitView];
1273
+ }
1274
+
1275
+ - (void)setFrameSize:(NSSize)newSize
1276
+ {
1277
+ [super setFrameSize:newSize];
1278
+
1279
+ [self layoutSplitView];
1280
+ }
1281
+
1282
+ - (void)viewDidMoveToWindow
1283
+ {
1284
+ [super viewDidMoveToWindow];
1285
+
1286
+ if (self.window) {
1287
+ dispatch_async(dispatch_get_main_queue(), ^{
1288
+ if (self.window) {
1289
+ [self layoutSplitView];
1290
+ }
1291
+ });
1292
+ }
1293
+ }
1294
+ #endif
1295
+
1296
+ - (void)layoutSubviews
1297
+ {
1298
+ [super layoutSubviews];
1299
+
1300
+ #if TARGET_OS_OSX
1301
+ [self layoutSplitView];
1302
+ #else
1303
+ CGFloat sidebarWidth = self.bounds.size.width * 0.26;
1304
+ _sidebarContainer.frame = CGRectMake(0, 0, sidebarWidth, self.bounds.size.height);
1305
+ _contentContainer.frame = CGRectMake(sidebarWidth, 0, self.bounds.size.width - sidebarWidth, self.bounds.size.height);
1306
+ #endif
1307
+ }
1308
+
1309
+ - (void)prepareForRecycle
1310
+ {
1311
+ [super prepareForRecycle];
1312
+
1313
+ #if TARGET_OS_OSX
1314
+ [_sidebarReactView removeFromSuperview];
1315
+ [_contentReactView removeFromSuperview];
1316
+ [_listReactView removeFromSuperview];
1317
+ _sidebarReactView = nil;
1318
+ _contentReactView = nil;
1319
+ _listReactView = nil;
1320
+ _currentLayoutMetrics = EmptyLayoutMetrics;
1321
+ _sidebarReactLayoutMetrics = EmptyLayoutMetrics;
1322
+ _contentReactLayoutMetrics = EmptyLayoutMetrics;
1323
+ _listReactLayoutMetrics = EmptyLayoutMetrics;
1324
+ _sidebarMinWidth = 180;
1325
+ _sidebarWidth = 0;
1326
+ _contentMinWidth = 320;
1327
+ _listMinWidth = 240;
1328
+ _listWidth = 0;
1329
+ _hasList = NO;
1330
+ _sidebarCollapsed = NO;
1331
+ _needsPreferredDividerPositions = YES;
1332
+ _layingOutSplitView = NO;
1333
+ _lastSidebarWidth = -1;
1334
+ _lastContentWidth = -1;
1335
+ _lastListWidth = -1;
1336
+ _lastHeight = -1;
1337
+ _lastLayoutReady = NO;
1338
+ _appearanceName = @"system";
1339
+ _didPublishMount = NO;
1340
+ _contentTitlebarHeight = 0;
1341
+ _contentTitlebarMaterialName = @"none";
1342
+ _contentTitlebarOverlayColorValue = nil;
1343
+ _contentTitlebarOverlayOpacity = 0;
1344
+ _sidebarTitlebarOverlayColorValue = nil;
1345
+ _sidebarTitlebarOverlayOpacity = 0;
1346
+ [self removeContentTitlebarMaterial];
1347
+ [self removeSidebarTitlebarMaterial];
1348
+ [self applyAppearance];
1349
+ [self updateListItem];
1350
+ [self updateSidebarCollapsed];
1351
+ [self updateSplitItemSizing];
1352
+ #else
1353
+ for (UIView *subview in _sidebarContainer.subviews) {
1354
+ [subview removeFromSuperview];
1355
+ }
1356
+ for (UIView *subview in _contentContainer.subviews) {
1357
+ [subview removeFromSuperview];
1358
+ }
1359
+ #endif
1360
+ }
1361
+
1362
+ - (void)dealloc
1363
+ {
1364
+ #if TARGET_OS_OSX
1365
+ if (_resizeObserver) {
1366
+ [[NSNotificationCenter defaultCenter] removeObserver:_resizeObserver];
1367
+ }
1368
+ #endif
1369
+ }
1370
+
1371
+ + (ComponentDescriptorProvider)componentDescriptorProvider
1372
+ {
1373
+ return concreteComponentDescriptorProvider<SidebarSplitViewComponentDescriptor>();
1374
+ }
1375
+
1376
+ @end
1377
+
1378
+ #if TARGET_OS_OSX
1379
+ // Optional C entry points let the host and window manager share this lifecycle
1380
+ // without requiring apps that do not use split views to link this package.
1381
+ extern "C" void LegendPrepareSidebarSplitViewStartup(NSWindow *window, NSDictionary *configuration)
1382
+ {
1383
+ if (![configuration isKindOfClass:NSDictionary.class] ||
1384
+ objc_getAssociatedObject(window, &RNSidebarSplitViewStartupKey)) {
1385
+ return;
1386
+ }
1387
+ RNSidebarSplitViewStartupView *view = [[RNSidebarSplitViewStartupView alloc]
1388
+ initWithFrame:window.contentView.bounds configuration:configuration];
1389
+ objc_setAssociatedObject(window, &RNSidebarSplitViewStartupKey, view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1390
+ window.appearance = view.appearance;
1391
+ [window.contentView addSubview:view];
1392
+ [window.contentView layoutSubtreeIfNeeded];
1393
+ }
1394
+
1395
+ extern "C" BOOL LegendAttachSidebarSplitViewStartupRoot(NSWindow *window, NSView *rootView,
1396
+ void (^installRoot)(void))
1397
+ {
1398
+ RNSidebarSplitViewStartupView *view = objc_getAssociatedObject(window, &RNSidebarSplitViewStartupKey);
1399
+ if (!view) {
1400
+ return NO;
1401
+ }
1402
+ view.installReactRoot = installRoot;
1403
+ // The split panes own their backgrounds. Do not carry the host's temporary
1404
+ // solid startup fill underneath AppKit's floating sidebar after the swap.
1405
+ if ([rootView respondsToSelector:@selector(setBackgroundColor:)]) {
1406
+ [(RCTUIView *)rootView setBackgroundColor:NSColor.clearColor];
1407
+ }
1408
+ rootView.layer.backgroundColor = NSColor.clearColor.CGColor;
1409
+ rootView.frame = window.contentView.bounds;
1410
+ [window.contentView addSubview:rootView positioned:NSWindowBelow relativeTo:view];
1411
+ return YES;
1412
+ }
1413
+
1414
+ extern "C" void LegendFinishSidebarSplitViewStartup(NSWindow *window)
1415
+ {
1416
+ RNSidebarSplitViewStartupView *view = objc_getAssociatedObject(window, &RNSidebarSplitViewStartupKey);
1417
+ [view finish];
1418
+ }
1419
+ #endif