@legendapp/spark 0.0.1-next.2 → 0.0.1-next.3

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 (399) 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/config-plugin.d.cts +2 -0
  7. package/contracts.ts +2 -0
  8. package/diagnostics.ts +1 -0
  9. package/expo-config.d.cts +1 -0
  10. package/metro.cjs +4 -1
  11. package/metro.d.cts +12 -0
  12. package/native.cjs +3 -1
  13. package/native.d.cts +6 -0
  14. package/package.json +82 -14
  15. package/schema.json +276 -58
  16. package/settings-observable.ts +1 -0
  17. package/settings-window.ts +1 -0
  18. package/shortcuts-commands.ts +1 -0
  19. package/shortcuts-keyboard.ts +3 -0
  20. package/ui-classnames.ts +1 -0
  21. package/ui-glass.ts +1 -0
  22. package/ui-search.ts +1 -0
  23. package/ui-sidebar.ts +1 -0
  24. package/ui-split-view.ts +1 -0
  25. package/ui-symbol.ts +1 -0
  26. package/vendor/node_modules/@legendapp/spark-ai/package.json +19 -0
  27. package/vendor/node_modules/@legendapp/spark-ai/src/availability.ts +17 -0
  28. package/vendor/node_modules/@legendapp/spark-ai/src/index.ts +15 -0
  29. package/vendor/node_modules/@legendapp/spark-ai/src/invocations.ts +34 -0
  30. package/vendor/node_modules/@legendapp/spark-ai/src/output.ts +62 -0
  31. package/vendor/node_modules/@legendapp/spark-ai/src/run.ts +12 -0
  32. package/vendor/node_modules/@legendapp/spark-ai/src/types.ts +16 -0
  33. package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.h +2 -1
  34. package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.mm +126 -24
  35. package/vendor/node_modules/@legendapp/spark-audio/package.json +5 -2
  36. package/vendor/node_modules/@legendapp/spark-audio/src/NativeSparkAudio.ts +5 -1
  37. package/vendor/node_modules/@legendapp/spark-audio/src/desktop.ts +36 -32
  38. package/vendor/node_modules/@legendapp/spark-audio/src/events.ts +11 -0
  39. package/vendor/node_modules/@legendapp/spark-audio/src/hooks.ts +65 -0
  40. package/vendor/node_modules/@legendapp/spark-audio/src/index.web.ts +92 -33
  41. package/vendor/node_modules/@legendapp/spark-audio/src/media-session-unavailable.ts +6 -4
  42. package/vendor/node_modules/@legendapp/spark-audio/src/media-session.ts +52 -19
  43. package/vendor/node_modules/@legendapp/spark-audio/src/media-session.web.ts +18 -10
  44. package/vendor/node_modules/@legendapp/spark-audio/src/media-types.ts +40 -13
  45. package/vendor/node_modules/@legendapp/spark-audio/src/mobile.ts +40 -32
  46. package/vendor/node_modules/@legendapp/spark-audio/src/player.ts +97 -0
  47. package/vendor/node_modules/@legendapp/spark-audio/src/status-listeners.ts +21 -15
  48. package/vendor/node_modules/@legendapp/spark-audio/src/types.ts +9 -4
  49. package/vendor/node_modules/@legendapp/spark-audio/windows/SparkAudio/SparkAudio.h +67 -20
  50. package/vendor/node_modules/@legendapp/spark-auth-session/package.json +4 -3
  51. package/vendor/node_modules/@legendapp/spark-auth-session/src/core.ts +60 -42
  52. package/vendor/node_modules/@legendapp/spark-auth-session/src/index.ts +28 -12
  53. package/vendor/node_modules/@legendapp/spark-auth-session/src/mobile.ts +97 -41
  54. package/vendor/node_modules/@legendapp/spark-auth-session/src/types.ts +20 -9
  55. package/vendor/node_modules/@legendapp/spark-cli/dist/add-desktop.js +50 -7
  56. package/vendor/node_modules/@legendapp/spark-cli/dist/build-mode.js +1 -1
  57. package/vendor/node_modules/@legendapp/spark-cli/dist/build.js +83 -48
  58. package/vendor/node_modules/@legendapp/spark-cli/dist/cli-arguments.js +60 -0
  59. package/vendor/node_modules/@legendapp/spark-cli/dist/commands.js +7 -2
  60. package/vendor/node_modules/@legendapp/spark-cli/dist/create.js +31 -5
  61. package/vendor/node_modules/@legendapp/spark-cli/dist/credentials.js +69 -23
  62. package/vendor/node_modules/@legendapp/spark-cli/dist/dev-command.js +12 -3
  63. package/vendor/node_modules/@legendapp/spark-cli/dist/dev.js +12 -9
  64. package/vendor/node_modules/@legendapp/spark-cli/dist/examples.js +1 -1
  65. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-dev-patch.cjs +4 -2
  66. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-metro.cjs +1 -1
  67. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-node.js +3 -3
  68. package/vendor/node_modules/@legendapp/spark-cli/dist/index.js +10 -38
  69. package/vendor/node_modules/@legendapp/spark-cli/dist/local.js +1 -1
  70. package/vendor/node_modules/@legendapp/spark-cli/dist/metro.cjs +26 -5
  71. package/vendor/node_modules/@legendapp/spark-cli/dist/native-metadata.js +26 -0
  72. package/vendor/node_modules/@legendapp/spark-cli/dist/native-patch-preflight.js +84 -0
  73. package/vendor/node_modules/@legendapp/spark-cli/dist/native-preparation.js +88 -0
  74. package/vendor/node_modules/@legendapp/spark-cli/dist/notary-profiles.js +75 -0
  75. package/vendor/node_modules/@legendapp/spark-cli/dist/package.js +4 -2
  76. package/vendor/node_modules/@legendapp/spark-cli/dist/platform.js +16 -2
  77. package/vendor/node_modules/@legendapp/spark-cli/dist/project.js +66 -13
  78. package/vendor/node_modules/@legendapp/spark-cli/dist/release.js +84 -4
  79. package/vendor/node_modules/@legendapp/spark-cli/dist/release.json +23 -18
  80. package/vendor/node_modules/@legendapp/spark-cli/dist/runner-install.js +145 -31
  81. package/vendor/node_modules/@legendapp/spark-cli/dist/signing.js +4 -3
  82. package/vendor/node_modules/@legendapp/spark-cli/dist/updates.js +41 -4
  83. package/vendor/node_modules/@legendapp/spark-cli/dist/windows.js +4 -1
  84. package/vendor/node_modules/@legendapp/spark-cli/package.json +7 -6
  85. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/App.tsx +6 -12
  86. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/desktop.config.json +5 -3
  87. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/package.json +11 -9
  88. package/vendor/node_modules/@legendapp/spark-cli/templates/diff-lite/Git.macos.tsx +2 -2
  89. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.macos.tsx +23 -21
  90. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.windows.tsx +23 -21
  91. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.desktop.ts +11 -8
  92. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.macos.ts +3 -3
  93. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/Lifecycle.desktop.tsx +8 -14
  94. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/OpenFiles.desktop.tsx +5 -10
  95. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.desktop.ts +11 -8
  96. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.macos.ts +3 -3
  97. package/vendor/node_modules/@legendapp/spark-cli/templates/music-lite/assets.desktop.ts +2 -2
  98. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Activation.desktop.tsx +2 -2
  99. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Desktop.desktop.ts +37 -15
  100. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/session.ts +5 -6
  101. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/window-session.ts +5 -4
  102. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/desktop.config.json +5 -3
  103. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/metro.config.js +1 -1
  104. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/package.json +13 -11
  105. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/react-native.config.js +1 -1
  106. package/vendor/node_modules/@legendapp/spark-cli/templates/windows/package.json +13 -11
  107. package/vendor/node_modules/@legendapp/spark-cli/templates/windows/react-native.config.js +1 -1
  108. package/vendor/node_modules/@legendapp/spark-clipboard/macos/RNDesktopClipboard.mm +10 -16
  109. package/vendor/node_modules/@legendapp/spark-clipboard/package.json +2 -2
  110. package/vendor/node_modules/@legendapp/spark-clipboard/src/NativeDesktopClipboard.ts +1 -1
  111. package/vendor/node_modules/@legendapp/spark-clipboard/src/desktop.ts +55 -31
  112. package/vendor/node_modules/@legendapp/spark-clipboard/src/expo.ts +21 -11
  113. package/vendor/node_modules/@legendapp/spark-clipboard/src/options.ts +8 -0
  114. package/vendor/node_modules/@legendapp/spark-clipboard/src/types.ts +10 -0
  115. package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.h +38 -15
  116. package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.vcxproj +2 -0
  117. package/vendor/node_modules/@legendapp/spark-codex/RNCodex.podspec +22 -0
  118. package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.hpp +23 -0
  119. package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.mm +1529 -0
  120. package/vendor/node_modules/@legendapp/spark-codex/nitro.json +21 -0
  121. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/.gitattributes +1 -0
  122. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex+autolinking.rb +62 -0
  123. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.cpp +17 -0
  124. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.hpp +27 -0
  125. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Umbrella.hpp +38 -0
  126. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.mm +35 -0
  127. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.swift +16 -0
  128. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexAvailability.hpp +95 -0
  129. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexRunResult.hpp +99 -0
  130. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.cpp +24 -0
  131. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.hpp +71 -0
  132. package/vendor/node_modules/@legendapp/spark-codex/package.json +35 -0
  133. package/vendor/node_modules/@legendapp/spark-codex/react-native.config.js +11 -0
  134. package/vendor/node_modules/@legendapp/spark-codex/src/Codex.nitro.ts +30 -0
  135. package/vendor/node_modules/@legendapp/spark-codex/src/index.ts +65 -0
  136. package/vendor/node_modules/@legendapp/spark-codex/src/native.ts +6 -0
  137. package/vendor/node_modules/@legendapp/spark-commands/package.json +21 -0
  138. package/vendor/node_modules/@legendapp/spark-commands/src/bindings.ts +90 -0
  139. package/vendor/node_modules/@legendapp/spark-commands/src/index.tsx +400 -0
  140. package/vendor/node_modules/@legendapp/spark-commands/src/router.ts +138 -0
  141. package/vendor/node_modules/@legendapp/spark-commands/src/storage.ts +20 -0
  142. package/vendor/node_modules/@legendapp/spark-context-menu/macos/RNContextMenu.mm +7 -8
  143. package/vendor/node_modules/@legendapp/spark-context-menu/package.json +4 -3
  144. package/vendor/node_modules/@legendapp/spark-context-menu/src/NativeContextMenu.ts +1 -1
  145. package/vendor/node_modules/@legendapp/spark-context-menu/src/index.ts +26 -26
  146. package/vendor/node_modules/@legendapp/spark-context-menu/windows/SparkContextMenu/SparkContextMenu.h +3 -2
  147. package/vendor/node_modules/@legendapp/spark-desktop-app/RNDesktopApp.podspec +2 -1
  148. package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryJSI.hpp +89 -0
  149. package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryWindows.hpp +22 -0
  150. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/RNDesktopApp.mm +13 -7
  151. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkBinaryJSI.h +48 -0
  152. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.h +4 -0
  153. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.mm +33 -33
  154. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktopError.h +20 -0
  155. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.h +26 -0
  156. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.mm +49 -0
  157. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.h +9 -0
  158. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.mm +70 -0
  159. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkWindow.mm +9 -6
  160. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/recent-documents/RNRecentDocumentController.mm +55 -0
  161. package/vendor/node_modules/@legendapp/spark-desktop-app/package.json +5 -3
  162. package/vendor/node_modules/@legendapp/spark-desktop-app/src/NativeDesktopApp.ts +1 -1
  163. package/vendor/node_modules/@legendapp/spark-desktop-app/src/api.ts +86 -40
  164. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/accelerator.ts +40 -0
  165. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/index.ts +56 -0
  166. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/menu.ts +114 -0
  167. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/native-buffer.ts +22 -0
  168. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/path.ts +24 -0
  169. package/vendor/node_modules/@legendapp/spark-desktop-app/src/events.ts +75 -0
  170. package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.ts +2 -0
  171. package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.windows.ts +2 -0
  172. package/vendor/node_modules/@legendapp/spark-desktop-app/src/open-requests.ts +43 -0
  173. package/vendor/node_modules/@legendapp/spark-desktop-app/src/restoration.ts +11 -0
  174. package/vendor/node_modules/@legendapp/spark-desktop-app/src/transport.ts +10 -0
  175. package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.cjs +10 -5
  176. package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.d.cts +3 -0
  177. package/vendor/node_modules/@legendapp/spark-desktop-config/autolinking.cjs +35 -0
  178. package/vendor/node_modules/@legendapp/spark-desktop-config/config.cjs +16 -3
  179. package/vendor/node_modules/@legendapp/spark-desktop-config/config.d.cts +89 -9
  180. package/vendor/node_modules/@legendapp/spark-desktop-config/expo.d.cts +3 -0
  181. package/vendor/node_modules/@legendapp/spark-desktop-config/identity.cjs +3 -2
  182. package/vendor/node_modules/@legendapp/spark-desktop-config/lifecycle.cjs +20 -0
  183. package/vendor/node_modules/@legendapp/spark-desktop-config/package.json +6 -5
  184. package/vendor/node_modules/@legendapp/spark-desktop-config/schema.json +276 -58
  185. package/vendor/node_modules/@legendapp/spark-desktop-config/updates.cjs +1 -0
  186. package/vendor/node_modules/@legendapp/spark-desktop-config/validation.cjs +35 -0
  187. package/vendor/node_modules/@legendapp/spark-desktop-config/windows.plugin.cjs +2 -1
  188. package/vendor/node_modules/@legendapp/spark-desktop-host/AppDelegate.mm +129 -11
  189. package/vendor/node_modules/@legendapp/spark-desktop-host/package.json +2 -2
  190. package/vendor/node_modules/@legendapp/spark-desktop-host/windows/application.inc +277 -121
  191. package/vendor/node_modules/@legendapp/spark-desktop-links/common/AuthLoopback.h +5 -7
  192. package/vendor/node_modules/@legendapp/spark-desktop-links/macos/RNDesktopLinks.mm +10 -9
  193. package/vendor/node_modules/@legendapp/spark-desktop-links/package.json +2 -2
  194. package/vendor/node_modules/@legendapp/spark-desktop-links/src/NativeDesktopLinks.ts +1 -1
  195. package/vendor/node_modules/@legendapp/spark-desktop-links/src/api.ts +27 -33
  196. package/vendor/node_modules/@legendapp/spark-desktop-links/src/expo.ts +3 -4
  197. package/vendor/node_modules/@legendapp/spark-desktop-links/src/native.ts +9 -0
  198. package/vendor/node_modules/@legendapp/spark-desktop-links/windows/SparkLinks/SparkLinks.h +22 -22
  199. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/RNDesktopShortcuts.podspec +1 -0
  200. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/RNDesktopShortcuts.mm +1 -1
  201. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.h +9 -0
  202. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.mm +307 -0
  203. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/package.json +8 -5
  204. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/NativeDesktopShortcuts.ts +1 -1
  205. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/api.ts +39 -14
  206. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/NativeKeyboardManager.ts +12 -0
  207. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/codes.ts +108 -0
  208. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/index.ts +99 -0
  209. package/vendor/node_modules/@legendapp/spark-desktop-windows/RNDesktopWindows.podspec +2 -0
  210. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/RNDesktopWindows.mm +229 -103
  211. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/SparkWindowGeometry.h +63 -0
  212. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.h +20 -0
  213. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.mm +27 -0
  214. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.h +12 -0
  215. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.mm +3130 -0
  216. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManagerStartup.mm +31 -0
  217. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/SidebarStartupFallbacks.mm +14 -0
  218. package/vendor/node_modules/@legendapp/spark-desktop-windows/package.json +10 -6
  219. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/NativeDesktopWindowManager.ts +1 -1
  220. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/api.ts +144 -70
  221. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/diagnostics.ts +17 -0
  222. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.ts +3 -1
  223. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.windows.ts +3 -1
  224. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos-adapter.ts +53 -0
  225. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos.ts +51 -0
  226. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/transport.ts +41 -0
  227. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/types.ts +140 -0
  228. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/validation.ts +162 -0
  229. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/window-manager/NativeWindowManager.ts +28 -0
  230. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/WindowProvider.tsx +20 -0
  231. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/createWindowsNavigator.tsx +78 -0
  232. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/index.ts +6 -0
  233. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle.ts +34 -0
  234. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/types.ts +11 -0
  235. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/usePrimaryWindowLifecycle.ts +18 -0
  236. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/useWindowFocusEffect.ts +17 -0
  237. package/vendor/node_modules/@legendapp/spark-documents/package.json +22 -0
  238. package/vendor/node_modules/@legendapp/spark-documents/src/controller.ts +97 -0
  239. package/vendor/node_modules/@legendapp/spark-documents/src/documentTransition.ts +13 -0
  240. package/vendor/node_modules/@legendapp/spark-documents/src/hooks.ts +139 -0
  241. package/vendor/node_modules/@legendapp/spark-documents/src/index.tsx +50 -0
  242. package/vendor/node_modules/@legendapp/spark-documents/src/reload.ts +39 -0
  243. package/vendor/node_modules/@legendapp/spark-documents/src/requests.ts +15 -0
  244. package/vendor/node_modules/@legendapp/spark-drag-drop/package.json +4 -3
  245. package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts +1 -1
  246. package/vendor/node_modules/@legendapp/spark-drag-drop/src/contracts.ts +73 -18
  247. package/vendor/node_modules/@legendapp/spark-drag-drop/src/index.tsx +58 -15
  248. package/vendor/node_modules/@legendapp/spark-drag-drop/windows/SparkDragDrop/SparkDragDrop.h +14 -8
  249. package/vendor/node_modules/@legendapp/spark-file-dialog/ios/RNFileDialog.mm +34 -121
  250. package/vendor/node_modules/@legendapp/spark-file-dialog/package.json +12 -5
  251. package/vendor/node_modules/@legendapp/spark-file-dialog/src/NativeFileDialog.ts +1 -5
  252. package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.ts +19 -84
  253. package/vendor/node_modules/@legendapp/spark-file-dialog/src/native.ts +12 -0
  254. package/vendor/node_modules/@legendapp/spark-file-dialog/src/options.ts +34 -14
  255. package/vendor/node_modules/@legendapp/spark-file-dialog/src/types.ts +26 -0
  256. package/vendor/node_modules/@legendapp/spark-file-dialog/windows/SparkFileDialog/SparkFileDialog.h +42 -58
  257. package/vendor/node_modules/@legendapp/spark-file-system/RNDesktopFileSystem.podspec +1 -0
  258. package/vendor/node_modules/@legendapp/spark-file-system/macos/RNDesktopFileSystem.mm +32 -21
  259. package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.h +24 -0
  260. package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.mm +215 -0
  261. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.h +9 -0
  262. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.mm +82 -0
  263. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.h +47 -0
  264. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm +306 -0
  265. package/vendor/node_modules/@legendapp/spark-file-system/package.json +8 -6
  266. package/vendor/node_modules/@legendapp/spark-file-system/src/NativeDesktopFileSystem.ts +1 -1
  267. package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts +11 -0
  268. package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/index.ts +93 -0
  269. package/vendor/node_modules/@legendapp/spark-file-system/src/handles.ts +48 -14
  270. package/vendor/node_modules/@legendapp/spark-file-system/src/index.ts +134 -45
  271. package/vendor/node_modules/@legendapp/spark-file-system/src/path.ts +1 -9
  272. package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.h +102 -26
  273. package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.vcxproj +2 -0
  274. package/vendor/node_modules/@legendapp/spark-global-shortcuts/RNDesktopGlobalShortcuts.podspec +1 -0
  275. package/vendor/node_modules/@legendapp/spark-global-shortcuts/macos/RNDesktopGlobalShortcuts.mm +7 -4
  276. package/vendor/node_modules/@legendapp/spark-global-shortcuts/package.json +4 -3
  277. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/NativeDesktopGlobalShortcuts.ts +1 -1
  278. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/index.ts +39 -10
  279. package/vendor/node_modules/@legendapp/spark-global-shortcuts/windows/SparkGlobalShortcuts/SparkGlobalShortcuts.h +5 -4
  280. package/vendor/node_modules/@legendapp/spark-message-dialog/macos/RNDesktopMessageDialog.mm +2 -2
  281. package/vendor/node_modules/@legendapp/spark-message-dialog/package.json +2 -2
  282. package/vendor/node_modules/@legendapp/spark-message-dialog/src/NativeDesktopMessageDialog.ts +1 -1
  283. package/vendor/node_modules/@legendapp/spark-message-dialog/src/index.ts +48 -11
  284. package/vendor/node_modules/@legendapp/spark-native-menu/ios/RNNativeMenu.mm +141 -609
  285. package/vendor/node_modules/@legendapp/spark-native-menu/package.json +9 -4
  286. package/vendor/node_modules/@legendapp/spark-native-menu/src/NativeMenu.ts +2 -7
  287. package/vendor/node_modules/@legendapp/spark-native-menu/src/api.ts +76 -121
  288. package/vendor/node_modules/@legendapp/spark-native-menu/src/hooks.ts +97 -0
  289. package/vendor/node_modules/@legendapp/spark-native-menu/src/windows-menus.ts +43 -37
  290. package/vendor/node_modules/@legendapp/spark-notifications/macos/RNDesktopNotifications.mm +75 -30
  291. package/vendor/node_modules/@legendapp/spark-notifications/package.json +2 -2
  292. package/vendor/node_modules/@legendapp/spark-notifications/src/NativeDesktopNotifications.ts +1 -1
  293. package/vendor/node_modules/@legendapp/spark-notifications/src/index.ts +130 -42
  294. package/vendor/node_modules/@legendapp/spark-notifications/windows/SparkNotifications/SparkNotifications.h +46 -8
  295. package/vendor/node_modules/@legendapp/spark-processes/macos/RNDesktopProcesses.mm +94 -21
  296. package/vendor/node_modules/@legendapp/spark-processes/package.json +4 -3
  297. package/vendor/node_modules/@legendapp/spark-processes/src/NativeDesktopProcesses.ts +1 -1
  298. package/vendor/node_modules/@legendapp/spark-processes/src/index.ts +124 -28
  299. package/vendor/node_modules/@legendapp/spark-processes/src/types.ts +34 -0
  300. package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.h +83 -34
  301. package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.vcxproj +2 -0
  302. package/vendor/node_modules/@legendapp/spark-secure-storage/macos/RNDesktopSecureStorage.mm +49 -40
  303. package/vendor/node_modules/@legendapp/spark-secure-storage/package.json +2 -2
  304. package/vendor/node_modules/@legendapp/spark-secure-storage/src/NativeDesktopSecureStorage.ts +1 -1
  305. package/vendor/node_modules/@legendapp/spark-secure-storage/src/desktop.ts +16 -14
  306. package/vendor/node_modules/@legendapp/spark-secure-storage/src/expo.ts +0 -1
  307. package/vendor/node_modules/@legendapp/spark-secure-storage/src/options.ts +3 -2
  308. package/vendor/node_modules/@legendapp/spark-secure-storage/src/unavailable.ts +6 -3
  309. package/vendor/node_modules/@legendapp/spark-settings/package.json +10 -3
  310. package/vendor/node_modules/@legendapp/spark-settings/src/fileStorage.ts +11 -0
  311. package/vendor/node_modules/@legendapp/spark-settings/src/index.ts +7 -9
  312. package/vendor/node_modules/@legendapp/spark-settings/src/storage/index.ts +142 -0
  313. package/vendor/node_modules/@legendapp/spark-settings/src/store.ts +63 -21
  314. package/vendor/node_modules/@legendapp/spark-settings-ui/package.json +20 -0
  315. package/vendor/node_modules/@legendapp/spark-settings-ui/src/index.tsx +436 -0
  316. package/vendor/node_modules/@legendapp/spark-settings-ui/src/options.ts +10 -0
  317. package/vendor/node_modules/@legendapp/spark-sqlite/package.json +3 -3
  318. package/vendor/node_modules/@legendapp/spark-sqlite/src/database.ts +182 -0
  319. package/vendor/node_modules/@legendapp/spark-sqlite/src/index.ts +19 -6
  320. package/vendor/node_modules/@legendapp/spark-sqlite/src/types.ts +22 -0
  321. package/vendor/node_modules/@legendapp/spark-system/macos/RNDesktopSystem.mm +36 -11
  322. package/vendor/node_modules/@legendapp/spark-system/package.json +2 -2
  323. package/vendor/node_modules/@legendapp/spark-system/src/NativeDesktopSystem.ts +1 -1
  324. package/vendor/node_modules/@legendapp/spark-system/src/index.ts +89 -32
  325. package/vendor/node_modules/@legendapp/spark-system/windows/SparkSystem/SparkSystem.h +8 -4
  326. package/vendor/node_modules/@legendapp/spark-tray/macos/RNDesktopTray.mm +20 -8
  327. package/vendor/node_modules/@legendapp/spark-tray/package.json +2 -2
  328. package/vendor/node_modules/@legendapp/spark-tray/src/NativeDesktopTray.ts +1 -1
  329. package/vendor/node_modules/@legendapp/spark-tray/src/index.ts +91 -34
  330. package/vendor/node_modules/@legendapp/spark-tray/windows/SparkTray/SparkTray.h +45 -15
  331. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkButton.mm +2 -1
  332. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkTextInput.mm +10 -2
  333. package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.h +15 -0
  334. package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.mm +1182 -0
  335. package/vendor/node_modules/@legendapp/spark-ui/macos/glass-effect-view/RNGlassEffectView.mm +72 -0
  336. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.h +15 -0
  337. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.mm +194 -0
  338. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.h +15 -0
  339. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.mm +180 -0
  340. package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.h +15 -0
  341. package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.mm +155 -0
  342. package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.h +18 -0
  343. package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.mm +645 -0
  344. package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.h +15 -0
  345. package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.mm +164 -0
  346. package/vendor/node_modules/@legendapp/spark-ui/package.json +16 -4
  347. package/vendor/node_modules/@legendapp/spark-ui/src/SparkSelectNativeComponent.ts +3 -1
  348. package/vendor/node_modules/@legendapp/spark-ui/src/SparkTextInputNativeComponent.ts +6 -2
  349. package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/SidebarSplitViewNativeComponent.ts +31 -0
  350. package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/index.tsx +77 -0
  351. package/vendor/node_modules/@legendapp/spark-ui/src/availability.ts +10 -0
  352. package/vendor/node_modules/@legendapp/spark-ui/src/classnames/index.ts +8 -0
  353. package/vendor/node_modules/@legendapp/spark-ui/src/control.ts +42 -0
  354. package/vendor/node_modules/@legendapp/spark-ui/src/desktop.tsx +56 -0
  355. package/vendor/node_modules/@legendapp/spark-ui/src/glass-effect-view/index.tsx +15 -0
  356. package/vendor/node_modules/@legendapp/spark-ui/src/index.android.tsx +35 -21
  357. package/vendor/node_modules/@legendapp/spark-ui/src/index.ios.tsx +55 -26
  358. package/vendor/node_modules/@legendapp/spark-ui/src/index.tsx +1 -27
  359. package/vendor/node_modules/@legendapp/spark-ui/src/index.web.tsx +45 -14
  360. package/vendor/node_modules/@legendapp/spark-ui/src/index.windows.tsx +1 -42
  361. package/vendor/node_modules/@legendapp/spark-ui/src/mobile-input.tsx +11 -0
  362. package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSegmentedControlNativeComponent.ts +17 -0
  363. package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSelectNativeComponent.ts +17 -0
  364. package/vendor/node_modules/@legendapp/spark-ui/src/select.ts +5 -3
  365. package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/SFSymbolNativeComponent.ts +13 -0
  366. package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/index.tsx +27 -0
  367. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarItemNativeComponent.ts +25 -0
  368. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarNativeComponent.ts +24 -0
  369. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/index.tsx +104 -0
  370. package/vendor/node_modules/@legendapp/spark-ui/src/specialized.ts +22 -0
  371. package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/TextInputSearchNativeComponent.ts +33 -0
  372. package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/index.tsx +34 -0
  373. package/vendor/node_modules/@legendapp/spark-ui/src/types.ts +30 -19
  374. package/vendor/node_modules/@legendapp/spark-ui/uniwind.ts +3 -1
  375. package/vendor/node_modules/@legendapp/spark-ui/uniwind.web.ts +3 -1
  376. package/vendor/node_modules/@legendapp/spark-ui/windows/SparkUI/SparkUI.h +16 -11
  377. package/vendor/node_modules/@legendapp/spark-updates/macos/RNDesktopUpdates.mm +21 -8
  378. package/vendor/node_modules/@legendapp/spark-updates/package.json +2 -2
  379. package/vendor/node_modules/@legendapp/spark-updates/src/NativeDesktopUpdates.ts +3 -2
  380. package/vendor/node_modules/@legendapp/spark-updates/src/index.ts +71 -15
  381. package/vendor/node_modules/@legendapp/spark-webview/package.json +2 -2
  382. package/vendor/node_modules/@legendapp/spark-webview/src/WebView.tsx +11 -0
  383. package/vendor/node_modules/@legendapp/spark-webview/src/adapter.ts +55 -0
  384. package/vendor/node_modules/@legendapp/spark-webview/src/index.ts +2 -2
  385. package/vendor/node_modules/@legendapp/spark-webview/src/types.ts +32 -0
  386. package/vendor/node_modules/@legendapp/spark-webview/src/view-props.ts +28 -0
  387. package/vendor/node_modules/@legendapp/spark-window-options/index.cjs +51 -14
  388. package/vendor/node_modules/@legendapp/spark-window-options/index.d.ts +21 -8
  389. package/vendor/node_modules/@legendapp/spark-window-options/package.json +1 -1
  390. package/windows-macos.ts +1 -0
  391. package/expo-metro.cjs +0 -1
  392. package/message-dialog.ts +0 -1
  393. package/universal.cjs +0 -1
  394. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/accelerator.ts +0 -22
  395. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows-options.ts +0 -11
  396. package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.windows.ts +0 -15
  397. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/accelerator.ts +0 -22
  398. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.h +0 -4
  399. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.mm +0 -53
@@ -1,30 +1,59 @@
1
- import { useCallback, useMemo } from "react";
1
+ import { useState, type ComponentProps } from "react";
2
+ function ExpoButton(props: ComponentProps<typeof import("@expo/ui/swift-ui").Button>) {
3
+ const Component = (require("@expo/ui/swift-ui") as typeof import("@expo/ui/swift-ui")).Button;
4
+ return <Component {...props} />;
5
+ }
6
+ function Host(props: ComponentProps<typeof import("@expo/ui/swift-ui").Host>) {
7
+ const Component = (require("@expo/ui/swift-ui") as typeof import("@expo/ui/swift-ui")).Host;
8
+ return <Component {...props} />;
9
+ }
10
+ function Picker(props: ComponentProps<typeof import("@expo/ui/swift-ui").Picker>) {
11
+ const Component = (require("@expo/ui/swift-ui") as typeof import("@expo/ui/swift-ui")).Picker;
12
+ return <Component {...props} />;
13
+ }
14
+ import { frame, disabled as disabledModifier, accessibilityLabel as labelModifier } from "@expo/ui/swift-ui/modifiers";
15
+ import { View, Text } from "react-native";
16
+ import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
17
+ import { requireOptionalNativeModule } from "expo-modules-core";
18
+ import { useControl, validateButton } from "./control";
2
19
  import { selectionIndex } from "./select";
3
- import { Button as ExpoButton, Host, TextField, Picker } from "@expo/ui/swift-ui";
4
- import { frame, padding, accessibilityLabel as labelModifier } from "@expo/ui/swift-ui/modifiers";
5
- import { StyleSheet } from "react-native";
6
- import type { ButtonProps, TextInputProps, SelectProps } from "./types";
7
- export type { ButtonProps, TextInputProps, SelectProps } from "./types";
8
-
9
- const fill = [frame({ maxWidth: Infinity, maxHeight: Infinity })];
10
- export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
11
- return <Host style={[styles.button, style]}>
12
- <ExpoButton onPress={disabled ? undefined : onPress} disabled={disabled}
13
- variant={variant} modifiers={fill} testID={testID}>{children}</ExpoButton>
14
- </Host>;
20
+ import type { ButtonProps, SelectProps, SegmentedControlProps, ControlKind } from "./types";
21
+ export type { ButtonProps, TextInputProps, ControlledTextInputProps, UncontrolledTextInputProps, SelectProps, SelectOption, SegmentedControlProps, ControlProps, ControlRef, ControlKind } from "./types";
22
+ export { TextInput } from "./mobile-input";
23
+ export function getControlAvailability(control: ControlKind): Availability {
24
+ if (!["button", "text-input", "select", "segmented-control"].includes(control)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown control kind");
25
+ return control === "text-input" || requireOptionalNativeModule("ExpoUI") ? { available: true } : { available: false, reason: "missing-module" };
15
26
  }
16
- const styles = StyleSheet.create({ button: { width: 160, height: 44 } });
17
-
18
- const fieldModifiers = [padding({ horizontal: 8 }), ...fill];
19
- const ignoreText = (_value: string) => {};
20
- export function TextInput({ defaultValue, onChangeText, accessibilityLabel, style, testID }: TextInputProps) {
21
- const modifiers = useMemo(() => accessibilityLabel ? [...fieldModifiers, labelModifier(accessibilityLabel)] : fieldModifiers, [accessibilityLabel]);
22
- return <Host style={[{ width: 240, height: 44, borderWidth: StyleSheet.hairlineWidth, borderColor: "#8e8e93", borderRadius: 6 }, style]}><TextField allowNewlines={false} multiline={false} defaultValue={defaultValue} onChangeText={onChangeText ?? ignoreText} modifiers={modifiers} testID={testID} /></Host>;
27
+ const fill = [frame({ maxWidth: Infinity, maxHeight: Infinity })];
28
+ export function Button(props: ButtonProps) {
29
+ validateButton(props); const control = useControl(props, getControlAvailability("button"));
30
+ const { children, onPress, variant = "default", style, testID, accessibilityLabel = children } = props;
31
+ return <View ref={control.ref} style={[{ width: 160, height: 44 }, style]}>
32
+ {control.failed ? <Text accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }} testID={testID}>{children}</Text> :
33
+ <Host style={{ flex: 1 }}><ExpoButton onPress={() => { if (control.active()) onPress?.(); }} disabled={control.disabled}
34
+ variant={variant} modifiers={[...fill, labelModifier(accessibilityLabel)]} testID={testID}>{children}</ExpoButton></Host>}
35
+ </View>;
23
36
  }
24
- export function Select({ options, value, onValueChange, accessibilityLabel, style, testID }: SelectProps) {
25
- const selectedIndex = selectionIndex(options, value);
26
- const labels = useMemo(() => options.map(option => option.label), [options]);
27
- const changed = useCallback((event: { nativeEvent: { index: number } }) => { const option = options[event.nativeEvent.index]; if (option) onValueChange(option.value); }, [options, onValueChange]);
28
- const modifiers = useMemo(() => accessibilityLabel ? [labelModifier(accessibilityLabel)] : [], [accessibilityLabel]);
29
- return <Host style={[{ width: 240, height: 44 }, style]}><Picker variant="menu" options={labels} selectedIndex={selectedIndex} onOptionSelected={changed} modifiers={modifiers} testID={testID} /></Host>;
37
+ function Selection({ segmented, ...props }: SelectProps & { segmented: boolean }) {
38
+ const selectedIndex = selectionIndex(props.options, props.value);
39
+ const [selectionRevision, revise] = useState(0);
40
+ if (typeof props.onValueChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected onValueChange");
41
+ const control = useControl(props, getControlAvailability(segmented ? "segmented-control" : "select"));
42
+ const { options, onValueChange, accessibilityLabel, style, testID } = props;
43
+ const modifiers = [disabledModifier(control.disabled), ...(accessibilityLabel ? [labelModifier(accessibilityLabel)] : [])];
44
+ return <View ref={control.ref} style={[{ width: 240, height: 44 }, style]}>
45
+ {control.failed ? <Text accessibilityLabel={accessibilityLabel} accessibilityState={{ disabled: true }} testID={testID}>{options[selectedIndex].label}</Text> :
46
+ <Host style={{ flex: 1 }}><Picker key={selectionRevision} variant={segmented ? "segmented" : "menu"} options={options.map(option => option.label)} selectedIndex={selectedIndex}
47
+ onOptionSelected={event => {
48
+ if (!control.active()) return;
49
+ const index = event?.nativeEvent?.index;
50
+ if (!Number.isInteger(index) || !options[index]) { control.error(new SparkError("E_INVALID_DATA", "Invalid native selection")); return; }
51
+ // Expo's SwiftUI picker retains local selection and ignores an unchanged
52
+ // selectedIndex. A fresh picker also restores a parent-vetoed selection.
53
+ revise(value => value + 1);
54
+ onValueChange(options[index].value);
55
+ }} modifiers={modifiers} testID={testID} /></Host>}
56
+ </View>;
30
57
  }
58
+ export function Select(props: SelectProps) { return <Selection {...props} segmented={false} />; }
59
+ export function SegmentedControl(props: SegmentedControlProps) { return <Selection {...props} segmented />; }
@@ -1,27 +1 @@
1
- import { useCallback, useMemo } from "react";
2
- import type { NativeSyntheticEvent } from "react-native";
3
- import NativeTextInput from "./SparkTextInputNativeComponent";
4
- import NativeSelect from "./SparkSelectNativeComponent";
5
- import { selectionIndex } from "./select";
6
- import { StyleSheet } from "react-native";
7
- import NativeButton from "./SparkButtonNativeComponent";
8
- import type { ButtonProps, TextInputProps, SelectProps } from "./types";
9
- export type { ButtonProps, TextInputProps, SelectProps } from "./types";
10
-
11
- export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
12
- return <NativeButton title={children} disabled={disabled} variant={variant}
13
- onButtonPress={disabled ? undefined : onPress} testID={testID}
14
- style={[styles.button, style]} />;
15
- }
16
- const styles = StyleSheet.create({ button: { width: 160, height: 36 } });
17
-
18
- export function TextInput({ defaultValue = "", onChangeText, style, ...props }: TextInputProps) {
19
- const changed = useCallback((event: NativeSyntheticEvent<{ text: string }>) => onChangeText?.(event.nativeEvent.text), [onChangeText]);
20
- return <NativeTextInput {...props} defaultText={defaultValue} onTextChange={changed} style={[{ width: 240, height: 36 }, style]} />;
21
- }
22
- export function Select({ options, value, onValueChange, style, ...props }: SelectProps) {
23
- selectionIndex(options, value);
24
- const itemsJson = useMemo(() => JSON.stringify(options), [options]);
25
- const changed = useCallback((event: NativeSyntheticEvent<{ value: string }>) => onValueChange(event.nativeEvent.value), [onValueChange]);
26
- return <NativeSelect {...props} itemsJson={itemsJson} value={value} onSelectionChange={changed} style={[{ width: 240, height: 36 }, style]} />;
27
- }
1
+ export * from "./desktop";
@@ -1,23 +1,54 @@
1
1
  import { selectionIndex } from "./select";
2
2
  import type { CSSProperties } from "react";
3
- import { StyleSheet, View } from "react-native";
4
- import type { ButtonProps, TextInputProps, SelectProps } from "./types";
5
- export type { ButtonProps, TextInputProps, SelectProps } from "./types";
6
-
3
+ import { View } from "react-native";
4
+ import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
5
+ import { useControl, useTextValue, validateButton } from "./control";
6
+ import type { ButtonProps, TextInputProps, SelectProps, SegmentedControlProps, ControlKind } from "./types";
7
+ export type { ButtonProps, TextInputProps, ControlledTextInputProps, UncontrolledTextInputProps, SelectProps, SelectOption, SegmentedControlProps, ControlProps, ControlRef, ControlKind } from "./types";
8
+ export function getControlAvailability(control: ControlKind): Availability {
9
+ if (!["button", "text-input", "select", "segmented-control"].includes(control)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown control kind");
10
+ return { available: true };
11
+ }
7
12
  const nativeStyle: CSSProperties = { width: "100%", height: "100%", boxSizing: "border-box", font: "14px system-ui" };
8
13
  const borderlessStyle: CSSProperties = { ...nativeStyle, border: "none", background: "transparent" };
9
- export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
10
- return <View style={[styles.button, style]} testID={testID}>
11
- <button type="button" disabled={disabled} onClick={disabled ? undefined : onPress}
14
+ export function Button(props: ButtonProps) {
15
+ validateButton(props); const control = useControl(props);
16
+ const { children, onPress, variant = "default", accessibilityLabel = children, style, testID } = props;
17
+ return <View ref={control.ref} style={[{ width: 160, height: 36 }, style]} testID={testID}>
18
+ <button type="button" disabled={control.disabled} onClick={() => { if (control.active()) onPress?.(); }} aria-label={accessibilityLabel}
12
19
  style={variant === "borderless" ? borderlessStyle : nativeStyle}>{children}</button>
13
20
  </View>;
14
21
  }
15
- const styles = StyleSheet.create({ button: { width: 160, height: 36 } });
16
-
17
- export function TextInput({ defaultValue, onChangeText, accessibilityLabel, style, testID }: TextInputProps) {
18
- return <View style={[{ width: 240, height: 36 }, style]} testID={testID}><input type="text" defaultValue={defaultValue} onChange={event => onChangeText?.(event.currentTarget.value)} aria-label={accessibilityLabel} style={nativeStyle} /></View>;
22
+ export function TextInput(props: TextInputProps) {
23
+ const control = useControl(props), state = useTextValue(props);
24
+ return <View ref={control.ref} style={[{ width: 240, height: 36 }, props.style]} testID={props.testID}>
25
+ <input type="text" value={state.controlled ? state.text : undefined} defaultValue={state.controlled ? undefined : state.defaultText} disabled={control.disabled}
26
+ onChange={event => { if (control.active()) props.onChangeText?.(event.currentTarget.value); }} aria-label={props.accessibilityLabel} style={nativeStyle} />
27
+ </View>;
28
+ }
29
+ function useSelection(props: SelectProps) {
30
+ selectionIndex(props.options, props.value);
31
+ if (typeof props.onValueChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Expected onValueChange");
32
+ const control = useControl(props);
33
+ return { ...control, change(value: string) {
34
+ if (!control.active()) return;
35
+ if (!props.options.some(option => option.value === value)) { control.error(new SparkError("E_INVALID_DATA", "Invalid native selection")); return; }
36
+ props.onValueChange(value);
37
+ } };
19
38
  }
20
- export function Select({ options, value, onValueChange, accessibilityLabel, style, testID }: SelectProps) {
21
- selectionIndex(options, value);
22
- return <View style={[{ width: 240, height: 36 }, style]} testID={testID}><select value={value} onChange={event => onValueChange(event.currentTarget.value)} aria-label={accessibilityLabel} style={nativeStyle}>{options.map(option => <option key={option.value} value={option.value}>{option.label}</option>)}</select></View>;
39
+ export function Select(props: SelectProps) {
40
+ const control = useSelection(props);
41
+ return <View ref={control.ref} style={[{ width: 240, height: 36 }, props.style]} testID={props.testID}>
42
+ <select value={props.value} disabled={control.disabled} onChange={event => control.change(event.currentTarget.value)} aria-label={props.accessibilityLabel} style={nativeStyle}>
43
+ {props.options.map(option => <option key={option.value} value={option.value}>{option.label}</option>)}
44
+ </select>
45
+ </View>;
46
+ }
47
+ export function SegmentedControl(props: SegmentedControlProps) {
48
+ const control = useSelection(props);
49
+ return <View ref={control.ref} style={[{ width: 240, height: 36 }, props.style]} testID={props.testID}>
50
+ <div role="group" aria-label={props.accessibilityLabel} style={{ display: "flex", width: "100%", height: "100%" }}>
51
+ {props.options.map(option => <button type="button" key={option.value} disabled={control.disabled} aria-pressed={option.value === props.value} onClick={() => control.change(option.value)} style={{ ...nativeStyle, flex: 1 }}>{option.label}</button>)}
52
+ </div>
53
+ </View>;
23
54
  }
@@ -1,42 +1 @@
1
- import { useCallback, useMemo, useState } from "react";
2
- import { Text, View, TurboModuleRegistry } from "react-native";
3
- import type { NativeSyntheticEvent, TurboModule, StyleProp, ViewStyle } from "react-native";
4
- import NativeButton from "./SparkButtonNativeComponent";
5
- import NativeTextInput from "./SparkTextInputNativeComponent";
6
- import NativeSelect from "./SparkSelectNativeComponent";
7
- import { selectionIndex } from "./select";
8
- import type { ButtonProps, TextInputProps, SelectProps } from "./types";
9
- export type { ButtonProps, TextInputProps, SelectProps } from "./types";
10
- interface Availability extends TurboModule { isAvailable(): boolean }
11
- const available = TurboModuleRegistry.get<Availability>("NativeSparkUI")?.isAvailable() === true;
12
- function useAvailability() {
13
- const [failed, setFailed] = useState(!available);
14
- const unavailable = useCallback((event: NativeSyntheticEvent<{ message: string }>) => {
15
- console.warn(`Windows native control unavailable: ${event.nativeEvent.message}`); setFailed(true);
16
- }, []);
17
- return { failed, onUnavailable: unavailable };
18
- }
19
- function Placeholder({ label, style, testID }: { label: string; style?: StyleProp<ViewStyle>; testID?: string }) {
20
- return <View style={[{ minHeight: 36, padding: 8, borderWidth: 1, borderColor: "#999" }, style]} testID={testID} accessible accessibilityLabel={label} accessibilityState={{ disabled: true }}>
21
- <Text>{label} — Windows control unavailable; rebuild the development client.</Text>
22
- </View>;
23
- }
24
- export function Button({ children, onPress, disabled = false, variant = "default", style, testID }: ButtonProps) {
25
- const { failed, onUnavailable } = useAvailability();
26
- return failed ? <Placeholder label={children} style={style} testID={testID} /> :
27
- <NativeButton title={children} disabled={disabled} variant={variant} onButtonPress={disabled ? undefined : onPress} onUnavailable={onUnavailable} testID={testID} style={[{ width: 160, height: 36 }, style]} />;
28
- }
29
- export function TextInput({ defaultValue = "", onChangeText, style, ...props }: TextInputProps) {
30
- const { failed, onUnavailable } = useAvailability();
31
- const changed = useCallback((event: NativeSyntheticEvent<{ text: string }>) => onChangeText?.(event.nativeEvent.text), [onChangeText]);
32
- return failed ? <Placeholder label={props.accessibilityLabel ?? "Text input"} style={style} testID={props.testID} /> :
33
- <NativeTextInput {...props} defaultText={defaultValue} onTextChange={changed} onUnavailable={onUnavailable} style={[{ width: 240, height: 36 }, style]} />;
34
- }
35
- export function Select({ options, value, onValueChange, style, ...props }: SelectProps) {
36
- const selected = selectionIndex(options, value);
37
- const { failed, onUnavailable } = useAvailability();
38
- const itemsJson = useMemo(() => JSON.stringify(options), [options]);
39
- const changed = useCallback((event: NativeSyntheticEvent<{ value: string }>) => onValueChange(event.nativeEvent.value), [onValueChange]);
40
- return failed ? <Placeholder label={`${props.accessibilityLabel ?? "Select"}: ${options[selected]!.label}`} style={style} testID={props.testID} /> :
41
- <NativeSelect {...props} itemsJson={itemsJson} value={value} onSelectionChange={changed} onUnavailable={onUnavailable} style={[{ width: 240, height: 36 }, style]} />;
42
- }
1
+ export * from "./desktop";
@@ -0,0 +1,11 @@
1
+ import { TextInput as RNTextInput } from "react-native";
2
+ import { useControl, useTextValue } from "./control";
3
+ import type { TextInputProps } from "./types";
4
+ /** RN owns text editing, IME, controlled-value reconciliation and selection on mobile. */
5
+ export function TextInput(props: TextInputProps) {
6
+ const control = useControl(props), state = useTextValue(props);
7
+ return <RNTextInput ref={control.ref} value={state.controlled ? state.text : undefined} defaultValue={state.defaultText}
8
+ onChangeText={text => { if (control.active()) props.onChangeText?.(text); }} editable={!control.disabled} multiline={false}
9
+ accessibilityLabel={props.accessibilityLabel} accessibilityState={{ disabled: control.disabled }} testID={props.testID}
10
+ style={[{ width: 240, height: 44, borderWidth: 1, borderColor: "#8e8e93", borderRadius: 6, paddingHorizontal: 8 }, props.style]} />;
11
+ }
@@ -0,0 +1,17 @@
1
+ import type { HostComponent, ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+ import type { DirectEventHandler, Int32 } from "react-native/Libraries/Types/CodegenTypes";
4
+
5
+ export type NativeSegmentedControlChangeEvent = {
6
+ value: string;
7
+ };
8
+
9
+ export interface NativeProps extends ViewProps {
10
+ enabled?: boolean;
11
+ selectionRevision?: Int32;
12
+ segmentsJson: string;
13
+ onValueChange?: DirectEventHandler<NativeSegmentedControlChangeEvent>;
14
+ value: string;
15
+ }
16
+
17
+ export default codegenNativeComponent<NativeProps>("NativeSegmentedControl") as HostComponent<NativeProps>;
@@ -0,0 +1,17 @@
1
+ import type { HostComponent, ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+ import type { DirectEventHandler, Int32 } from "react-native/Libraries/Types/CodegenTypes";
4
+
5
+ export type NativeSelectChangeEvent = {
6
+ value: string;
7
+ };
8
+
9
+ export interface NativeProps extends ViewProps {
10
+ enabled?: boolean;
11
+ selectionRevision?: Int32;
12
+ itemsJson: string;
13
+ onValueChange?: DirectEventHandler<NativeSelectChangeEvent>;
14
+ value: string;
15
+ }
16
+
17
+ export default codegenNativeComponent<NativeProps>("NativeSelect") as HostComponent<NativeProps>;
@@ -1,7 +1,9 @@
1
+ import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
1
2
  import type { SelectProps } from "./types";
2
- export function selectionIndex(options: SelectProps["options"], value: string) {
3
- if (!options.length || new Set(options.map(option => option.value)).size !== options.length) throw new Error("Select options must be nonempty with unique values");
3
+ export function selectionIndex(options: SelectProps["options"], value: string): number {
4
+ if (!Array.isArray(options) || !options.length || Array.from(options).some(option => !option || typeof option !== "object" || typeof option.label !== "string" || !option.label.length || typeof option.value !== "string") || new Set(options.map(option => option.value)).size !== options.length) throw new SparkError("E_INVALID_ARGUMENT", "Select options must have nonempty labels and unique string values");
5
+ for (const option of options) for (const key of Object.keys(option)) if (key !== "label" && key !== "value") throw new SparkError("E_UNSUPPORTED_OPTION", `Unknown select option: ${key}`);
4
6
  const index = options.findIndex(option => option.value === value);
5
- if (index < 0) throw new Error("Select value must match an option");
7
+ if (index < 0) throw new SparkError("E_INVALID_ARGUMENT", "Select value must match an option");
6
8
  return index;
7
9
  }
@@ -0,0 +1,13 @@
1
+ import type { CodegenTypes, ColorValue, HostComponent, ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+
4
+ export interface NativeProps extends ViewProps {
5
+ name: string;
6
+ onSymbolError?: CodegenTypes.DirectEventHandler<Readonly<{ name: string; message: string }>>;
7
+ color?: ColorValue;
8
+ scale?: string;
9
+ size?: CodegenTypes.Double;
10
+ yOffset?: CodegenTypes.Double;
11
+ }
12
+
13
+ export default codegenNativeComponent<NativeProps>("SFSymbol") as HostComponent<NativeProps>;
@@ -0,0 +1,27 @@
1
+ import { View, type ColorValue, type NativeSyntheticEvent } from "react-native";
2
+ import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
3
+ import { useControl } from "../control";
4
+ import { finite, identifier, macosViewAvailability, type SpecializedViewProps } from "../specialized";
5
+ import NativeSFSymbol from "./SFSymbolNativeComponent";
6
+ export type SFSymbolScale = "small" | "medium" | "large";
7
+ export interface SFSymbolProps extends Omit<SpecializedViewProps, "children"> {
8
+ name: string;
9
+ color?: ColorValue;
10
+ scale?: SFSymbolScale;
11
+ size?: number;
12
+ yOffset?: number;
13
+ }
14
+ export function getSFSymbolAvailability() { return macosViewAvailability("SFSymbol"); }
15
+ export function SFSymbol({ name, color, scale = "medium", size = 24, yOffset = 0, ref, onError, style, ...props }: SFSymbolProps) {
16
+ identifier(name, "symbol name"); finite(size, "symbol size", 1); finite(yOffset, "symbol offset", -Infinity);
17
+ if (!["small", "medium", "large"].includes(scale)) throw new SparkError("E_INVALID_ARGUMENT", "Invalid symbol scale");
18
+ const control = useControl({ ref, onError }, getSFSymbolAvailability());
19
+ const frame = [{ height: size, width: size }, style];
20
+ function error(event: NativeSyntheticEvent<{ name: string; message: string }>) {
21
+ if (!control.active()) return;
22
+ if (typeof event?.nativeEvent?.name !== "string" || typeof event?.nativeEvent?.message !== "string") { control.error(new SparkError("E_INVALID_DATA", "Invalid symbol error")); return; }
23
+ if (event.nativeEvent.name === name) control.error(new SparkError("E_NOT_FOUND", event.nativeEvent.message));
24
+ }
25
+ if (control.failed) return <View {...props} ref={control.ref} style={frame} />;
26
+ return <NativeSFSymbol {...props} ref={control.ref} name={name} color={color} scale={scale} size={size} yOffset={yOffset} style={frame} onSymbolError={error} />;
27
+ }
@@ -0,0 +1,25 @@
1
+ import type { HostComponent, ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+ import type { DirectEventHandler, Double } from "react-native/Libraries/Types/CodegenTypes";
4
+
5
+ export type SidebarItemRightClickEvent = Readonly<{
6
+ altKey: boolean;
7
+ button: Double;
8
+ ctrlKey: boolean;
9
+ metaKey: boolean;
10
+ pageX: Double;
11
+ pageY: Double;
12
+ shiftKey: boolean;
13
+ x: Double;
14
+ y: Double;
15
+ }>;
16
+
17
+ export interface NativeProps extends ViewProps {
18
+ autoHeight?: boolean;
19
+ itemId?: string;
20
+ onRightClick?: DirectEventHandler<SidebarItemRightClickEvent>;
21
+ rowHeight?: Double;
22
+ selectable?: boolean;
23
+ }
24
+
25
+ export default codegenNativeComponent<NativeProps>("SidebarItem") as HostComponent<NativeProps>;
@@ -0,0 +1,24 @@
1
+ import type { HostComponent, ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+ import type { DirectEventHandler, Double, Int32 } from "react-native/Libraries/Types/CodegenTypes";
4
+
5
+ export type SidebarSelectionChangeEvent = Readonly<{
6
+ id: string;
7
+ }>;
8
+
9
+ export type SidebarLayoutEvent = Readonly<{
10
+ height: Double;
11
+ width: Double;
12
+ }>;
13
+
14
+ export interface NativeProps extends ViewProps {
15
+ contentInsetTop?: Double;
16
+ defaultRowHeight?: Double;
17
+ itemsJson?: string;
18
+ onSidebarLayout?: DirectEventHandler<SidebarLayoutEvent>;
19
+ onSidebarSelectionChange?: DirectEventHandler<SidebarSelectionChangeEvent>;
20
+ selectedId?: string;
21
+ selectionRevision?: Int32;
22
+ }
23
+
24
+ export default codegenNativeComponent<NativeProps>("Sidebar") as HostComponent<NativeProps>;
@@ -0,0 +1,104 @@
1
+ import { Children, Fragment, createContext, isValidElement, useContext, useMemo, useState, type ReactElement, type ReactNode } from "react";
2
+ import { Text, View, type NativeSyntheticEvent } from "react-native";
3
+ import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
4
+ import { useControl } from "../control";
5
+ import { callback, finite, identifier, macosViewAvailability, type SpecializedViewProps } from "../specialized";
6
+ import NativeSidebar from "./SidebarNativeComponent";
7
+ import NativeSidebarItem from "./SidebarItemNativeComponent";
8
+ export interface SidebarItemData { id: string; label: string; selectable?: boolean }
9
+ export type SidebarRowHeight = number | "auto";
10
+ export interface SidebarSelectionEvent { id: string | null }
11
+ export interface SidebarContentLayoutEvent { width: number; height: number }
12
+ export interface SidebarContextMenuEvent {
13
+ id: string;
14
+ /** Logical top-left coordinates within the row and the owning window's content. */
15
+ position: { x: number; y: number };
16
+ windowPosition: { x: number; y: number };
17
+ modifiers: { alt: boolean; control: boolean; meta: boolean; shift: boolean };
18
+ }
19
+ export interface SidebarBaseProps extends Omit<SpecializedViewProps, "children"> {
20
+ contentInsetTop?: number;
21
+ defaultRowHeight?: number;
22
+ selectedId: string | null;
23
+ onContentLayout?: (event: SidebarContentLayoutEvent) => void;
24
+ onSelectionChange: (event: SidebarSelectionEvent) => void;
25
+ }
26
+ export type SidebarProps = SidebarBaseProps & ({ items: readonly SidebarItemData[]; children?: never } | { items?: never; children: ReactNode });
27
+ export interface SidebarItemProps extends SpecializedViewProps {
28
+ id: string;
29
+ rowHeight?: SidebarRowHeight;
30
+ selectable?: boolean;
31
+ onContextMenu?: (event: SidebarContextMenuEvent) => void;
32
+ }
33
+ const SidebarContext = createContext(false);
34
+ export function getSidebarAvailability() {
35
+ const availability = macosViewAvailability("Sidebar");
36
+ return availability.available ? macosViewAvailability("SidebarItem") : availability;
37
+ }
38
+ function childRows(children: ReactNode): ReactElement<SidebarItemProps>[] {
39
+ const rows: ReactElement<SidebarItemProps>[] = [];
40
+ Children.forEach(children, child => {
41
+ if (child === null) return;
42
+ if (isValidElement<{ children?: ReactNode }>(child) && child.type === Fragment) { rows.push(...childRows(child.props.children)); return; }
43
+ if (!isValidElement<SidebarItemProps>(child) || child.type !== SidebarItem) throw new SparkError("E_INVALID_ARGUMENT", "Sidebar children must be SidebarItem elements or fragments");
44
+ rows.push(child);
45
+ });
46
+ return rows;
47
+ }
48
+ export function Sidebar({ items, children, selectedId, contentInsetTop = 0, defaultRowHeight = 28, onContentLayout, onSelectionChange, ref, onError, ...props }: SidebarProps) {
49
+ finite(contentInsetTop, "content inset"); finite(defaultRowHeight, "row height", 1);
50
+ callback(onContentLayout, "content layout");
51
+ if (typeof onSelectionChange !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Sidebar selection is controlled and requires onSelectionChange");
52
+ if (items !== undefined && (children !== undefined || !Array.isArray(items))) throw new SparkError("E_INVALID_ARGUMENT", "Use either items or SidebarItem children");
53
+ const { selectableIds, itemsJson } = useMemo(() => {
54
+ const rows = items === undefined ? childRows(children) : [];
55
+ const entries = items === undefined ? rows.map(row => ({ id: row.props.id, selectable: row.props.selectable })) : items;
56
+ const ids = new Set<string>(), selectableIds = new Set<string>();
57
+ for (const item of entries) {
58
+ if (!item || typeof item !== "object") throw new SparkError("E_INVALID_ARGUMENT", "Invalid sidebar item");
59
+ identifier(item.id, "sidebar ID");
60
+ if (ids.has(item.id)) throw new SparkError("E_INVALID_ARGUMENT", "Sidebar IDs must be unique"); ids.add(item.id);
61
+ if (item.selectable !== undefined && typeof item.selectable !== "boolean") throw new SparkError("E_INVALID_ARGUMENT", "Expected selectable boolean");
62
+ if (items !== undefined) identifier((item as SidebarItemData).label, "sidebar label");
63
+ if (item.selectable !== false) selectableIds.add(item.id);
64
+ }
65
+ return { selectableIds, itemsJson: items === undefined ? "" : JSON.stringify(items.map(({ id, label, selectable = true }) => ({ id, title: label, selectable }))) };
66
+ }, [items, children]);
67
+ if (selectedId !== null && !selectableIds.has(selectedId)) throw new SparkError("E_INVALID_ARGUMENT", "Selected sidebar ID must identify a selectable row");
68
+ const control = useControl({ ref, onError }, getSidebarAvailability());
69
+ const [selectionRevision, revise] = useState(0);
70
+ function selection(event: NativeSyntheticEvent<{ id: string }>) {
71
+ if (!control.active()) return;
72
+ const id = event?.nativeEvent?.id;
73
+ if (typeof id !== "string" || (id !== "" && !selectableIds.has(id))) { control.error(new SparkError("E_INVALID_DATA", "Invalid sidebar selection")); return; }
74
+ revise(value => value + 1); onSelectionChange?.({ id: id || null });
75
+ }
76
+ function layout(event: NativeSyntheticEvent<{ width: number; height: number }>) {
77
+ if (!control.active()) return;
78
+ try { finite(event?.nativeEvent?.width, "content width"); finite(event?.nativeEvent?.height, "content height"); }
79
+ catch (cause) { control.error(new SparkError("E_INVALID_DATA", "Invalid sidebar layout", { cause })); return; }
80
+ onContentLayout?.({ width: event.nativeEvent.width, height: event.nativeEvent.height });
81
+ }
82
+ if (control.failed) return <View {...props} ref={control.ref}><SidebarContext.Provider value>{items?.map(item => <Text key={item.id}>{item.label}</Text>) ?? children}</SidebarContext.Provider></View>;
83
+ return <NativeSidebar {...props} ref={control.ref} itemsJson={itemsJson} selectedId={selectedId ?? ""} selectionRevision={selectionRevision} contentInsetTop={contentInsetTop} defaultRowHeight={defaultRowHeight} onSidebarLayout={layout} onSidebarSelectionChange={selection}>
84
+ <SidebarContext.Provider value>{children}</SidebarContext.Provider>
85
+ </NativeSidebar>;
86
+ }
87
+ export function SidebarItem({ id, children, rowHeight, selectable = true, onContextMenu, ref, onError, ...props }: SidebarItemProps) {
88
+ if (!useContext(SidebarContext)) throw new SparkError("E_INVALID_ARGUMENT", "SidebarItem requires a Sidebar parent");
89
+ identifier(id, "sidebar ID"); callback(onContextMenu, "context menu");
90
+ if (rowHeight !== undefined && rowHeight !== "auto") finite(rowHeight, "row height", 1);
91
+ if (typeof selectable !== "boolean") throw new SparkError("E_INVALID_ARGUMENT", "Expected selectable boolean");
92
+ const control = useControl({ ref, onError }, getSidebarAvailability());
93
+ function contextMenu(event: NativeSyntheticEvent<{ x: number; y: number; pageX: number; pageY: number; altKey: boolean; ctrlKey: boolean; metaKey: boolean; shiftKey: boolean }>) {
94
+ if (!control.active()) return;
95
+ const data = event?.nativeEvent;
96
+ try {
97
+ for (const key of ["x", "y", "pageX", "pageY"] as const) finite(data?.[key], key, -Infinity);
98
+ for (const key of ["altKey", "ctrlKey", "metaKey", "shiftKey"] as const) if (typeof data[key] !== "boolean") throw new Error("Invalid modifiers");
99
+ } catch (cause) { control.error(new SparkError("E_INVALID_DATA", "Invalid sidebar context menu event", { cause })); return; }
100
+ onContextMenu?.({ id, position: { x: data.x, y: data.y }, windowPosition: { x: data.pageX, y: data.pageY }, modifiers: { alt: data.altKey, control: data.ctrlKey, meta: data.metaKey, shift: data.shiftKey } });
101
+ }
102
+ if (control.failed) return <View {...props} ref={control.ref}>{children}</View>;
103
+ return <NativeSidebarItem {...props} ref={control.ref} itemId={id} autoHeight={rowHeight === "auto"} rowHeight={typeof rowHeight === "number" ? rowHeight : 0} selectable={selectable} onRightClick={contextMenu}>{children}</NativeSidebarItem>;
104
+ }
@@ -0,0 +1,22 @@
1
+ import { Platform, UIManager, type ViewProps } from "react-native";
2
+ import type { Ref } from "react";
3
+ import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
4
+ import type { ControlRef } from "./types";
5
+ export interface SpecializedViewProps extends ViewProps { ref?: Ref<ControlRef>; onError?: (error: SparkError) => void }
6
+ export function macosViewAvailability(name: string, minimumVersion = 14): Availability {
7
+ if (Platform.OS !== "macos") return { available: false, reason: "unsupported-platform" };
8
+ if (Number.parseInt(String(Platform.Version), 10) < minimumVersion) return { available: false, reason: "host-restriction" };
9
+ return UIManager.hasViewManagerConfig(name) ? { available: true } : { available: false, reason: "missing-module" };
10
+ }
11
+ export function finite(value: unknown, name: string, minimum = 0, maximum = Infinity): asserts value is number {
12
+ if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum) throw new SparkError("E_INVALID_ARGUMENT", `Invalid ${name}`);
13
+ }
14
+ export function identifier(value: unknown, name = "ID"): asserts value is string {
15
+ if (typeof value !== "string" || !value.length || value.includes("\0")) throw new SparkError("E_INVALID_ARGUMENT", `Expected a nonempty ${name}`);
16
+ }
17
+ export function appearance(value: unknown) {
18
+ if (!["system", "light", "dark"].includes(value as string)) throw new SparkError("E_INVALID_ARGUMENT", "Invalid appearance");
19
+ }
20
+ export function callback(value: unknown, name: string) {
21
+ if (value !== undefined && typeof value !== "function") throw new SparkError("E_INVALID_ARGUMENT", `Expected ${name} callback`);
22
+ }
@@ -0,0 +1,33 @@
1
+ import type { HostComponent, ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+ import codegenNativeCommands from "react-native/Libraries/Utilities/codegenNativeCommands";
4
+ import type { DirectEventHandler, Int32, WithDefault } from "react-native/Libraries/Types/CodegenTypes";
5
+
6
+ export type TextInputSearchChangeEvent = {
7
+ text: string;
8
+ eventCount: Int32;
9
+ };
10
+
11
+ export interface NativeProps extends ViewProps {
12
+ appearance?: string;
13
+ defaultText?: string;
14
+ controlled?: WithDefault<boolean, false>;
15
+ disabled?: WithDefault<boolean, false>;
16
+ eventCount?: Int32;
17
+ onChangeText?: DirectEventHandler<TextInputSearchChangeEvent>;
18
+ placeholder?: string;
19
+ text?: string;
20
+ }
21
+
22
+ type NativeComponentType = HostComponent<NativeProps>;
23
+
24
+ export interface NativeCommands {
25
+ focus: (viewRef: React.ElementRef<NativeComponentType>) => void;
26
+ blur: (viewRef: React.ElementRef<NativeComponentType>) => void;
27
+ }
28
+
29
+ export const Commands = codegenNativeCommands<NativeCommands>({
30
+ supportedCommands: ["focus", "blur"],
31
+ });
32
+
33
+ export default codegenNativeComponent<NativeProps>("TextInputSearch") as NativeComponentType;
@@ -0,0 +1,34 @@
1
+ import { createElement, useCallback, useImperativeHandle, useRef, type ElementRef, type Ref } from "react";
2
+ import { Text, View, type NativeSyntheticEvent } from "react-native";
3
+ import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
4
+ import { useControl, useTextValue } from "../control";
5
+ import { macosViewAvailability, appearance } from "../specialized";
6
+ import type { ControlRef, ControlledTextInputProps, UncontrolledTextInputProps } from "../types";
7
+ import NativeSearch, { Commands } from "./TextInputSearchNativeComponent";
8
+ export type TextInputSearchProps = (Omit<ControlledTextInputProps, "ref"> | Omit<UncontrolledTextInputProps, "ref">) & {
9
+ appearance?: "dark" | "light" | "system";
10
+ placeholder?: string;
11
+ ref?: Ref<TextInputSearchRef>;
12
+ };
13
+ export interface TextInputSearchRef extends ControlRef { focus(): void; blur(): void }
14
+ export function getSearchAvailability() { return macosViewAvailability("TextInputSearch"); }
15
+ export function TextInputSearch({ ref, appearance: theme = "system", placeholder = "", ...props }: TextInputSearchProps) {
16
+ appearance(theme);
17
+ if (typeof placeholder !== "string") throw new SparkError("E_INVALID_ARGUMENT", "Expected search placeholder");
18
+ const layout = useRef<ControlRef>(null), native = useRef<ElementRef<typeof NativeSearch>>(null);
19
+ const control = useControl({ ...props, ref: layout }, getSearchAvailability()), value = useTextValue(props);
20
+ const nativeRef = useCallback((view: ElementRef<typeof NativeSearch> | null) => { native.current = view; control.ref(view); }, [control.ref]);
21
+ useImperativeHandle(ref, () => ({
22
+ measureInWindow(callback) { if (!layout.current) throw new SparkError("E_CLOSED", "Search input is not mounted"); layout.current.measureInWindow(callback); },
23
+ focus() { if (!native.current) throw new SparkError("E_CLOSED", "Search input is not mounted or available"); Commands.focus(native.current); },
24
+ blur() { if (!native.current) throw new SparkError("E_CLOSED", "Search input is not mounted or available"); Commands.blur(native.current); },
25
+ }), []);
26
+ function changed(event: NativeSyntheticEvent<{ text: string; eventCount: number }>) {
27
+ if (!control.active()) return;
28
+ const data = event?.nativeEvent;
29
+ if (typeof data?.text !== "string" || !Number.isSafeInteger(data.eventCount) || data.eventCount < 1 || data.eventCount > 2147483647) { control.error(new SparkError("E_INVALID_DATA", "Invalid search input event")); return; }
30
+ if (value.acknowledge(data.eventCount)) props.onChangeText?.(data.text);
31
+ }
32
+ if (control.failed) return <View ref={control.ref} style={props.style} testID={props.testID} accessible accessibilityLabel={props.accessibilityLabel} accessibilityState={{ disabled: true }}><Text>{value.controlled ? value.text : value.defaultText}</Text></View>;
33
+ return createElement(NativeSearch, { ref: nativeRef, appearance: theme, placeholder, disabled: control.disabled, controlled: value.controlled, eventCount: value.eventCount, defaultText: value.defaultText, text: value.text, onChangeText: changed, style: props.style, testID: props.testID, accessibilityLabel: props.accessibilityLabel });
34
+ }