react-native-gtkx 0.1.0-alpha.4 → 0.2.0-alpha.2

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 (257) hide show
  1. package/README.md +22 -9
  2. package/dist/adw/index.d.ts +3 -0
  3. package/dist/adw/index.js +41 -0
  4. package/dist/adw/index.js.map +1 -0
  5. package/dist/adw/widgets.generated.d.ts +63 -0
  6. package/dist/adw/widgets.generated.js +125 -0
  7. package/dist/adw/widgets.generated.js.map +1 -0
  8. package/dist/animated/create-animated.d.ts +2 -0
  9. package/dist/animated/create-animated.js +2 -0
  10. package/dist/animated/create-animated.js.map +1 -1
  11. package/dist/animated/index.d.ts +2 -0
  12. package/dist/animated/index.js +1 -0
  13. package/dist/animated/index.js.map +1 -1
  14. package/dist/animated/value-xy.d.ts +41 -0
  15. package/dist/animated/value-xy.js +90 -0
  16. package/dist/animated/value-xy.js.map +1 -0
  17. package/dist/animated/value.d.ts +9 -0
  18. package/dist/animated/value.js +30 -2
  19. package/dist/animated/value.js.map +1 -1
  20. package/dist/common/content.d.ts +69 -0
  21. package/dist/common/content.js +84 -0
  22. package/dist/common/content.js.map +1 -0
  23. package/dist/common/icon.d.ts +23 -0
  24. package/dist/common/icon.js +14 -0
  25. package/dist/common/icon.js.map +1 -0
  26. package/dist/common/index.d.ts +5 -0
  27. package/dist/common/index.js +21 -0
  28. package/dist/common/index.js.map +1 -0
  29. package/dist/common/list.d.ts +82 -0
  30. package/dist/common/list.js +166 -0
  31. package/dist/common/list.js.map +1 -0
  32. package/dist/common/navigation-stack.d.ts +84 -0
  33. package/dist/common/navigation-stack.js +313 -0
  34. package/dist/common/navigation-stack.js.map +1 -0
  35. package/dist/common/widget.d.ts +62 -0
  36. package/dist/common/widget.js +209 -0
  37. package/dist/common/widget.js.map +1 -0
  38. package/dist/components/animated.d.ts +7 -4
  39. package/dist/components/animated.js +88 -67
  40. package/dist/components/animated.js.map +1 -1
  41. package/dist/components/app-registry.d.ts +36 -1
  42. package/dist/components/app-registry.js +8 -3
  43. package/dist/components/app-registry.js.map +1 -1
  44. package/dist/components/host-node.d.ts +7 -0
  45. package/dist/components/host-node.js +26 -1
  46. package/dist/components/host-node.js.map +1 -1
  47. package/dist/components/index.d.ts +6 -2
  48. package/dist/components/index.js +2 -1
  49. package/dist/components/index.js.map +1 -1
  50. package/dist/components/measure.d.ts +13 -0
  51. package/dist/components/measure.js +51 -0
  52. package/dist/components/measure.js.map +1 -0
  53. package/dist/components/modal.d.ts +1 -1
  54. package/dist/components/press-event.d.ts +28 -0
  55. package/dist/components/press-event.js +46 -0
  56. package/dist/components/press-event.js.map +1 -0
  57. package/dist/components/pressable.d.ts +2 -6
  58. package/dist/components/pressable.js +119 -20
  59. package/dist/components/pressable.js.map +1 -1
  60. package/dist/components/rect-store.d.ts +11 -1
  61. package/dist/components/rect-store.js +27 -3
  62. package/dist/components/rect-store.js.map +1 -1
  63. package/dist/components/scroll-view.d.ts +4 -0
  64. package/dist/components/scroll-view.js +8 -2
  65. package/dist/components/scroll-view.js.map +1 -1
  66. package/dist/components/svg/animated-support.d.ts +19 -0
  67. package/dist/components/svg/animated-support.js +64 -0
  68. package/dist/components/svg/animated-support.js.map +1 -0
  69. package/dist/components/svg/context.d.ts +8 -0
  70. package/dist/components/svg/context.js +15 -0
  71. package/dist/components/svg/context.js.map +1 -0
  72. package/dist/components/svg/gradients.d.ts +31 -0
  73. package/dist/components/svg/gradients.js +93 -0
  74. package/dist/components/svg/gradients.js.map +1 -0
  75. package/dist/components/svg/group.d.ts +8 -0
  76. package/dist/components/svg/group.js +30 -0
  77. package/dist/components/svg/group.js.map +1 -0
  78. package/dist/components/svg/index.d.ts +6 -0
  79. package/dist/components/svg/index.js +5 -0
  80. package/dist/components/svg/index.js.map +1 -0
  81. package/dist/components/svg/node.d.ts +7 -0
  82. package/dist/components/svg/node.js +7 -0
  83. package/dist/components/svg/node.js.map +1 -0
  84. package/dist/components/svg/paint.d.ts +24 -0
  85. package/dist/components/svg/paint.js +57 -0
  86. package/dist/components/svg/paint.js.map +1 -0
  87. package/dist/components/svg/shapes.d.ts +47 -0
  88. package/dist/components/svg/shapes.js +51 -0
  89. package/dist/components/svg/shapes.js.map +1 -0
  90. package/dist/components/svg/svg.d.ts +14 -0
  91. package/dist/components/svg/svg.js +48 -0
  92. package/dist/components/svg/svg.js.map +1 -0
  93. package/dist/components/svg/use-shape-node.d.ts +12 -0
  94. package/dist/components/svg/use-shape-node.js +52 -0
  95. package/dist/components/svg/use-shape-node.js.map +1 -0
  96. package/dist/components/text-input.js +1 -1
  97. package/dist/components/text-input.js.map +1 -1
  98. package/dist/components/text.js +36 -3
  99. package/dist/components/text.js.map +1 -1
  100. package/dist/components/use-layout-child.js +50 -4
  101. package/dist/components/use-layout-child.js.map +1 -1
  102. package/dist/components/view.d.ts +9 -4
  103. package/dist/components/view.js +8 -2
  104. package/dist/components/view.js.map +1 -1
  105. package/dist/contracts.d.ts +31 -4
  106. package/dist/contracts.js.map +1 -1
  107. package/dist/gtk/index.d.ts +7 -0
  108. package/dist/gtk/index.js +46 -0
  109. package/dist/gtk/index.js.map +1 -0
  110. package/dist/gtk/widgets.generated.d.ts +103 -0
  111. package/dist/gtk/widgets.generated.js +205 -0
  112. package/dist/gtk/widgets.generated.js.map +1 -0
  113. package/dist/gtk/window-actions.d.ts +77 -0
  114. package/dist/gtk/window-actions.js +193 -0
  115. package/dist/gtk/window-actions.js.map +1 -0
  116. package/dist/gtkx/bridge/geometry.d.ts +15 -0
  117. package/dist/gtkx/bridge/geometry.js +38 -0
  118. package/dist/gtkx/bridge/geometry.js.map +1 -0
  119. package/dist/gtkx/bridge/index.d.ts +11 -4
  120. package/dist/gtkx/bridge/index.js +47 -6
  121. package/dist/gtkx/bridge/index.js.map +1 -1
  122. package/dist/gtkx/bridge/layout-manager.d.ts +2 -1
  123. package/dist/gtkx/bridge/layout-manager.js +31 -9
  124. package/dist/gtkx/bridge/layout-manager.js.map +1 -1
  125. package/dist/gtkx/bridge/slot-portal.d.ts +12 -0
  126. package/dist/gtkx/bridge/slot-portal.js +17 -0
  127. package/dist/gtkx/bridge/slot-portal.js.map +1 -0
  128. package/dist/gtkx/bridge/svg-node.d.ts +79 -0
  129. package/dist/gtkx/bridge/svg-node.js +323 -0
  130. package/dist/gtkx/bridge/svg-node.js.map +1 -0
  131. package/dist/gtkx/bridge/use-signal.js +19 -9
  132. package/dist/gtkx/bridge/use-signal.js.map +1 -1
  133. package/dist/gtkx/bridge/widgets.generated.d.ts +2 -0
  134. package/dist/gtkx/bridge/widgets.generated.js +14 -0
  135. package/dist/gtkx/bridge/widgets.generated.js.map +1 -0
  136. package/dist/index.d.ts +2 -2
  137. package/dist/index.js +1 -1
  138. package/dist/index.js.map +1 -1
  139. package/dist/mcp/bin.d.ts +2 -0
  140. package/dist/mcp/bin.js +17 -0
  141. package/dist/mcp/bin.js.map +1 -0
  142. package/dist/mcp/data/generated.d.ts +1304 -0
  143. package/dist/mcp/data/generated.js +1179 -0
  144. package/dist/mcp/data/generated.js.map +1 -0
  145. package/dist/mcp/index.d.ts +5 -0
  146. package/dist/mcp/index.js +9 -0
  147. package/dist/mcp/index.js.map +1 -0
  148. package/dist/mcp/list.d.ts +4 -0
  149. package/dist/mcp/list.js +56 -0
  150. package/dist/mcp/list.js.map +1 -0
  151. package/dist/mcp/resolve.d.ts +55 -0
  152. package/dist/mcp/resolve.js +151 -0
  153. package/dist/mcp/resolve.js.map +1 -0
  154. package/dist/mcp/search.d.ts +13 -0
  155. package/dist/mcp/search.js +48 -0
  156. package/dist/mcp/search.js.map +1 -0
  157. package/dist/mcp/server.d.ts +7 -0
  158. package/dist/mcp/server.js +135 -0
  159. package/dist/mcp/server.js.map +1 -0
  160. package/dist/mcp/tool.d.ts +21 -0
  161. package/dist/mcp/tool.js +36 -0
  162. package/dist/mcp/tool.js.map +1 -0
  163. package/dist/metro/index.js +10 -0
  164. package/dist/metro/index.js.map +1 -1
  165. package/dist/navigation/index.d.ts +50 -13
  166. package/dist/navigation/index.js +183 -148
  167. package/dist/navigation/index.js.map +1 -1
  168. package/dist/navigation/option-warnings.js +9 -1
  169. package/dist/navigation/option-warnings.js.map +1 -1
  170. package/dist/navigation/sidebar.d.ts +207 -9
  171. package/dist/navigation/sidebar.js +294 -10
  172. package/dist/navigation/sidebar.js.map +1 -1
  173. package/dist/responder/system.d.ts +27 -0
  174. package/dist/responder/system.js +184 -0
  175. package/dist/responder/system.js.map +1 -0
  176. package/dist/responder/touch-history.d.ts +10 -0
  177. package/dist/responder/touch-history.js +78 -0
  178. package/dist/responder/touch-history.js.map +1 -0
  179. package/dist/responder/types.d.ts +63 -0
  180. package/dist/responder/types.js +29 -0
  181. package/dist/responder/types.js.map +1 -0
  182. package/dist/responder/use-responder.d.ts +12 -0
  183. package/dist/responder/use-responder.js +98 -0
  184. package/dist/responder/use-responder.js.map +1 -0
  185. package/dist/runner/host-dev.js +3 -1
  186. package/dist/runner/host-dev.js.map +1 -1
  187. package/dist/runner/host.js +5 -1
  188. package/dist/runner/host.js.map +1 -1
  189. package/dist/runner/index.d.ts +22 -2
  190. package/dist/runner/index.js +163 -13
  191. package/dist/runner/index.js.map +1 -1
  192. package/dist/sea/assemble.d.ts +29 -0
  193. package/dist/sea/assemble.js +129 -0
  194. package/dist/sea/assemble.js.map +1 -0
  195. package/dist/sea/bundle.d.ts +61 -0
  196. package/dist/sea/bundle.js +202 -0
  197. package/dist/sea/bundle.js.map +1 -0
  198. package/dist/sea/gtkx-config-module.d.ts +18 -0
  199. package/dist/sea/gtkx-config-module.js +67 -0
  200. package/dist/sea/gtkx-config-module.js.map +1 -0
  201. package/dist/sea/native-shim.d.ts +40 -0
  202. package/dist/sea/native-shim.js +121 -0
  203. package/dist/sea/native-shim.js.map +1 -0
  204. package/dist/sea/react-anchor-plugin.d.ts +2 -0
  205. package/dist/sea/react-anchor-plugin.js +30 -0
  206. package/dist/sea/react-anchor-plugin.js.map +1 -0
  207. package/dist/style/box-shadow.d.ts +7 -0
  208. package/dist/style/box-shadow.js +197 -0
  209. package/dist/style/box-shadow.js.map +1 -0
  210. package/dist/style/index.d.ts +3 -0
  211. package/dist/style/index.js +3 -0
  212. package/dist/style/index.js.map +1 -1
  213. package/dist/style/split-style.d.ts +5 -2
  214. package/dist/style/split-style.js +33 -5
  215. package/dist/style/split-style.js.map +1 -1
  216. package/dist/style/text-decoration.d.ts +15 -0
  217. package/dist/style/text-decoration.js +26 -0
  218. package/dist/style/text-decoration.js.map +1 -0
  219. package/dist/style/transform.d.ts +22 -0
  220. package/dist/style/transform.js +137 -0
  221. package/dist/style/transform.js.map +1 -0
  222. package/dist/style/visual-css.js +40 -3
  223. package/dist/style/visual-css.js.map +1 -1
  224. package/dist/svg/geometry.d.ts +19 -0
  225. package/dist/svg/geometry.js +80 -0
  226. package/dist/svg/geometry.js.map +1 -0
  227. package/dist/svg/gradient-geometry.d.ts +15 -0
  228. package/dist/svg/gradient-geometry.js +15 -0
  229. package/dist/svg/gradient-geometry.js.map +1 -0
  230. package/dist/svg/transform.d.ts +22 -0
  231. package/dist/svg/transform.js +74 -0
  232. package/dist/svg/transform.js.map +1 -0
  233. package/dist/svg/view-box.d.ts +34 -0
  234. package/dist/svg/view-box.js +108 -0
  235. package/dist/svg/view-box.js.map +1 -0
  236. package/dist/svg-compat/index.d.ts +1 -0
  237. package/dist/svg-compat/index.js +16 -0
  238. package/dist/svg-compat/index.js.map +1 -0
  239. package/dist/testing/index.d.ts +14 -0
  240. package/dist/testing/index.js +14 -0
  241. package/dist/testing/index.js.map +1 -0
  242. package/dist/vendor/react-native/pan-responder.d.ts +102 -0
  243. package/dist/vendor/react-native/pan-responder.js +196 -0
  244. package/dist/vendor/react-native/pan-responder.js.map +1 -0
  245. package/dist/vendor/react-native/touch-history-math.d.ts +18 -0
  246. package/dist/vendor/react-native/touch-history-math.js +102 -0
  247. package/dist/vendor/react-native/touch-history-math.js.map +1 -0
  248. package/dist/vite/index.d.ts +7 -3
  249. package/dist/vite/index.js +16 -4
  250. package/dist/vite/index.js.map +1 -1
  251. package/dist/vitest/index.d.ts +52 -0
  252. package/dist/vitest/index.js +58 -0
  253. package/dist/vitest/index.js.map +1 -0
  254. package/dist/vitest/setup.d.ts +4 -0
  255. package/dist/vitest/setup.js +22 -0
  256. package/dist/vitest/setup.js.map +1 -0
  257. package/package.json +52 -13
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/mcp/tool.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,GAAG,CAAC,IAAY,EAAkB,EAAE,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;CAClC,CAAC,CAAA;AAEF,MAAM,SAAS,GAAG,CAAC,IAAY,EAAkB,EAAE,CAAC,CAAC;IACnD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,EAAE,IAAI;CACd,CAAC,CAAA;AAEF,MAAM,aAAa,GAAG,CAAC,KAAc,EAAkB,EAAE,CACvD,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;AAEnE,MAAM,OAAO,GAAG,CACd,OAAsE,EACtE,IAAyC,EACzB,EAAE;IAClB,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,aAAa,CAAC,KAAK,CAAC,CAAA;IAC7B,CAAC;AACH,CAAC,CAAA;AAED;;sDAEsD;AACtD,MAAM,UAAU,GAAG,CACjB,IAAiB,EACX,EAAE,CAAC,IAAY,CAAA;AAEvB,MAAM,YAAY,GAAG,CAAC,MAAiB,EAAE,IAAU,EAAQ,EAAE;IAC3D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAyC,EAAE,EAAE,CAC9D,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAA4C,CAAA;IAEzE,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;QACE,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,QAAQ,CACT,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,GAGV,CAAA","sourcesContent":["// Small defineTool/registerTool helper over @modelcontextprotocol/sdk's\n// McpServer, in the same spirit as @gtkx/mcp's own src/tool.ts (a sibling\n// package in this monorepo's node_modules, studied as a reference) — but\n// written fresh: this server has no live-app connection to route errors\n// through, so there is no ProtocolError type to special-case, only plain\n// Error.\nimport type {\n McpServer,\n ToolCallback,\n} from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\"\nimport type { z } from \"zod\"\n\ntype ToolArgs<Shape extends Record<string, z.ZodType>> = {\n [K in keyof Shape]: z.output<Shape[K]>\n}\n\ntype Tool<Shape extends Record<string, z.ZodType> = Record<string, z.ZodType>> =\n {\n name: string\n title: string\n description: string\n inputSchema: Shape\n handler: (args: ToolArgs<Shape>) => CallToolResult\n }\n\nconst textContent = (text: string): CallToolResult => ({\n content: [{ type: \"text\", text }],\n})\n\nconst textError = (text: string): CallToolResult => ({\n content: [{ type: \"text\", text }],\n isError: true,\n})\n\nconst errorToResult = (error: unknown): CallToolResult =>\n textError(error instanceof Error ? error.message : String(error))\n\nconst runTool = (\n handler: (args: ToolArgs<Record<string, z.ZodType>>) => CallToolResult,\n args: ToolArgs<Record<string, z.ZodType>>,\n): CallToolResult => {\n try {\n return handler(args)\n } catch (error) {\n return errorToResult(error)\n }\n}\n\n/** Identity function with a narrower input type — keeps tool definitions\n * readable (named fields) while erasing the generic Shape at the call site,\n * matching the pattern registerTool below expects. */\nconst defineTool = <Shape extends Record<string, z.ZodType>>(\n tool: Tool<Shape>,\n): Tool => tool as Tool\n\nconst registerTool = (server: McpServer, tool: Tool): void => {\n const callback = ((args: ToolArgs<Record<string, z.ZodType>>) =>\n runTool(tool.handler, args)) as ToolCallback<Record<string, z.ZodType>>\n\n server.registerTool(\n tool.name,\n {\n title: tool.title,\n description: tool.description,\n inputSchema: tool.inputSchema,\n annotations: {\n title: tool.title,\n readOnlyHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n },\n callback,\n )\n}\n\nexport {\n defineTool,\n registerTool,\n textContent,\n textError,\n type Tool,\n type ToolArgs,\n}\n"]}
@@ -31,11 +31,13 @@ export const HOST_MODULE_EXTERNALS = [
31
31
  "@gtkx/gi/gdk",
32
32
  "@gtkx/gi/gio",
33
33
  "@gtkx/gi/glib",
34
+ "@gtkx/gi/gobject",
34
35
  "@gtkx/gi/graphene",
35
36
  "@gtkx/gi/gsk",
36
37
  "@gtkx/gi/gtk",
37
38
  "@gtkx/gi/pango",
38
39
  "@gtkx/jsx/adw",
40
+ "@gtkx/jsx/gio",
39
41
  "@gtkx/jsx/gtk",
40
42
  "@gtkx/react",
41
43
  "@gtkx/react/internal",
@@ -96,6 +98,14 @@ export const withLinuxPlatform = (config, options = {}) => {
96
98
  moduleName.startsWith("react-native/")) {
97
99
  return fallback(context, moduleName.replace(/^react-native/, "react-native-gtkx"), platform);
98
100
  }
101
+ // Same alias, same guard shape, for the SVG compat subpath (see
102
+ // src/svg-compat/index.ts and the vite preset's rewriteReactNativeImport
103
+ // — kept in sync deliberately rather than sharing code, Metro and vite
104
+ // resolvers have never shared an implementation in this package).
105
+ if (moduleName === "react-native-svg" ||
106
+ moduleName.startsWith("react-native-svg/")) {
107
+ return fallback(context, moduleName.replace(/^react-native-svg/, "react-native-gtkx/svg"), platform);
108
+ }
99
109
  return fallback(context, moduleName, platform);
100
110
  };
101
111
  // The cast: T may carry narrower resolver/serializer types than the ones
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metro/index.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,4EAA4E;AAC5E,sBAAsB;AACtB,EAAE;AACF,uEAAuE;AACvE,EAAE;AACF,qEAAqE;AACrE,sCAAsC;AACtC,0EAA0E;AAC1E,yEAAyE;AACzE,wCAAwC;AACxC,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,+CAA+C;AAC/C,oEAAoE;AACpE,oEAAoE;AACpE,2EAA2E;AAC3E,wDAAwD;AACxD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,oEAAoE;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,WAAW;IACX,cAAc;IACd,cAAc;IACd,cAAc;IACd,eAAe;IACf,mBAAmB;IACnB,cAAc;IACd,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,aAAa;IACb,sBAAsB;IACtB,eAAe;IACf,OAAO;IACP,mBAAmB;IACnB,uBAAuB;IACvB,aAAa;CACd,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAA;AAgCrC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,KAAK,CAAA;AAE9E,MAAM,eAAe,GAAG,CAAC,IAAY,EAAU,EAAE;AAC/C,2EAA2E;AAC3E,yCAAyC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAA;AAEpE,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE,CAC5C,yCAAyC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAA;AAEpE,2EAA2E;AAC3E,yEAAyE;AACzE,uEAAuE;AACvE,sCAAsC;AACtC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,SAAsB,EAAQ,EAAE;IACpE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;IACjE,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5D,aAAa,CACX,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,EACnC,YAAY,CAAC,QAAQ,IAAI,EAAE,CAAC,CAC7B,CAAA;IACH,CAAC;AACH,CAAC,CAAA;AAYD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAS,EACT,UAAgC,EAAE,EACV,EAAE;IAC1B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;QACxB,GAAG,qBAAqB;QACxB,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;KAC7B,CAAC,CAAA;IACF,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ;QAChB,IAAI,CACF,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,EACnC,cAAc,EACd,oBAAoB,EACpB,iBAAiB,CAClB,CAAA;IACH,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IACpC,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,EAAE,cAAc,IAAI,IAAI,CAAA;IAE/D,MAAM,QAAQ,GAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,CAChE,eAAe;QACb,CAAC,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC;QAChD,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IAE3D,MAAM,cAAc,GAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE;QACtE,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;YAChC,OAAO,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;QAChD,CAAC;QACD,IAAI,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YACvD,OAAO;gBACL,IAAI,EAAE,YAAY;gBAClB,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;aAC/C,CAAA;QACH,CAAC;QACD,IACE,UAAU,KAAK,cAAc;YAC7B,UAAU,CAAC,UAAU,CAAC,eAAe,CAAC,EACtC,CAAC;YACD,OAAO,QAAQ,CACb,OAAO,EACP,UAAU,CAAC,OAAO,CAAC,eAAe,EAAE,mBAAmB,CAAC,EACxD,QAAQ,CACT,CAAA;QACH,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IAChD,CAAC,CAAA;IAED,yEAAyE;IACzE,iEAAiE;IACjE,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,EAAE;YACR,GAAG,MAAM,CAAC,QAAQ;YAClB,SAAS,EAAE;gBACT,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;aACpE;YACD,cAAc;SACf;QACD,UAAU,EAAE;YACV,GAAG,MAAM,CAAC,UAAU;YACpB,gEAAgE;YAChE,4DAA4D;YAC5D,gCAAgC;YAChC,6BAA6B,EAAE,GAAG,EAAE,CAAC,EAAE;SACxC;KACwB,CAAA;AAC7B,CAAC,CAAA","sourcesContent":["// Metro preset for the linux out-of-tree platform: wrap the app's Metro\n// config with `withLinuxPlatform` and the standard RN toolchain bundles for\n// `--platform linux`.\n//\n// What it does on top of RN defaults (validated by spike/rn-platform):\n//\n// 1. Adds \"linux\" to resolver.platforms (`.linux.tsx` extensions and\n// Platform.OS come along with it).\n// 2. Redirects `react-native` (and subpaths) to `react-native-gtkx` — the\n// out-of-tree npmPackageName declaration alone does not alias imports\n// for `bundle`, the resolver has to.\n// 3. EXTERNALIZES host-side singletons. Unlike react-native-windows, whose\n// native side lives outside the JS bundle by construction, our \"native\"\n// is Node modules with NAPI bindings (@gtkx/*) plus yoga-layout's WASM —\n// Metro cannot bundle those. react (and its jsx runtimes) must also stay\n// host-side: the reconciler inside @gtkx/react and the app have to share\n// one React instance. Every external resolves to a generated proxy that\n// reads the real module from global.__hostModules — the run-linux host\n// injects them before executing the bundle.\n// 4. Proxies Node builtins through the host's require: apps on this\n// platform may use the whole Node API, it is a platform feature.\n// 5. Drops InitializeCore (RN's mobile environment polyfills): the runtime\n// environment IS Node, the host provides everything.\nimport { mkdirSync, writeFileSync } from \"node:fs\"\nimport { builtinModules, isBuiltin } from \"node:module\"\nimport { join } from \"node:path\"\n\n/** Modules the run-linux host provides to the bundle at runtime. */\nexport const HOST_MODULE_EXTERNALS = [\n \"@gtkx/css\",\n \"@gtkx/gi/adw\",\n \"@gtkx/gi/gdk\",\n \"@gtkx/gi/gio\",\n \"@gtkx/gi/glib\",\n \"@gtkx/gi/graphene\",\n \"@gtkx/gi/gsk\",\n \"@gtkx/gi/gtk\",\n \"@gtkx/gi/pango\",\n \"@gtkx/jsx/adw\",\n \"@gtkx/jsx/gtk\",\n \"@gtkx/react\",\n \"@gtkx/react/internal\",\n \"@gtkx/runtime\",\n \"react\",\n \"react/jsx-runtime\",\n \"react/jsx-dev-runtime\",\n \"yoga-layout\",\n]\n\nexport const LINUX_PLATFORM = \"linux\"\n\n// Structural slices of Metro's config/resolution types: Metro is the app's\n// dependency, not ours — depending on its types here would pin versions.\nexport type MetroResolutionContext = {\n resolveRequest: MetroResolver\n}\nexport type MetroResolution = { type: string; filePath?: string }\nexport type MetroResolver = (\n context: MetroResolutionContext,\n moduleName: string,\n platform: string | null,\n) => MetroResolution\n\nexport type MetroLikeConfig = {\n projectRoot?: string\n resolver?: {\n platforms?: readonly string[]\n resolveRequest?: MetroResolver | null\n }\n serializer?: {\n getModulesRunBeforeMainModule?: (entryFilePath: string) => string[]\n }\n}\n\nexport type LinuxPlatformOptions = {\n /** Extra host-provided modules to keep out of the bundle. */\n externals?: readonly string[]\n /** Proxy directory override (default: node_modules/.react-native-gtkx). */\n proxyDir?: string\n}\n\nconst sanitize = (name: string): string => name.replace(/[@/:]/g, \"_\") + \".js\"\n\nconst hostModuleProxy = (name: string): string =>\n // The run-linux host guarantees __hostModules before executing the bundle.\n `module.exports = global.__hostModules[${JSON.stringify(name)}]\\n`\n\nconst builtinProxy = (name: string): string =>\n `module.exports = global.__hostRequire(${JSON.stringify(name)})\\n`\n\n// Every proxy is generated eagerly when the config loads: Metro crawls the\n// file map before transforming, and files that appear mid-build lose the\n// race (\"Failed to get the SHA-1\"). The builtin list is finite, so the\n// whole proxy set can exist up front.\nconst generateProxies = (dir: string, externals: Set<string>): void => {\n mkdirSync(dir, { recursive: true })\n for (const name of externals) {\n writeFileSync(join(dir, sanitize(name)), hostModuleProxy(name))\n }\n for (const bare of builtinModules) {\n writeFileSync(join(dir, sanitize(bare)), builtinProxy(bare))\n writeFileSync(\n join(dir, sanitize(`node:${bare}`)),\n builtinProxy(`node:${bare}`),\n )\n }\n}\n\nexport type LinuxPlatformConfig<T extends MetroLikeConfig> = T & {\n resolver: {\n platforms: string[]\n resolveRequest: MetroResolver\n }\n serializer: {\n getModulesRunBeforeMainModule: (entryFilePath: string) => string[]\n }\n}\n\n/**\n * Wraps a Metro config (RN's getDefaultConfig output) with everything the\n * linux platform needs. Composes with an existing custom resolveRequest —\n * non-linux platforms fall through to it untouched.\n */\nexport const withLinuxPlatform = <T extends MetroLikeConfig>(\n config: T,\n options: LinuxPlatformOptions = {},\n): LinuxPlatformConfig<T> => {\n const externals = new Set([\n ...HOST_MODULE_EXTERNALS,\n ...(options.externals ?? []),\n ])\n const proxyDir =\n options.proxyDir ??\n join(\n config.projectRoot ?? process.cwd(),\n \"node_modules\",\n \".react-native-gtkx\",\n \"metro-externals\",\n )\n generateProxies(proxyDir, externals)\n const previousResolve = config.resolver?.resolveRequest ?? null\n\n const fallback: MetroResolver = (context, moduleName, platform) =>\n previousResolve\n ? previousResolve(context, moduleName, platform)\n : context.resolveRequest(context, moduleName, platform)\n\n const resolveRequest: MetroResolver = (context, moduleName, platform) => {\n if (platform !== LINUX_PLATFORM) {\n return fallback(context, moduleName, platform)\n }\n if (externals.has(moduleName) || isBuiltin(moduleName)) {\n return {\n type: \"sourceFile\",\n filePath: join(proxyDir, sanitize(moduleName)),\n }\n }\n if (\n moduleName === \"react-native\" ||\n moduleName.startsWith(\"react-native/\")\n ) {\n return fallback(\n context,\n moduleName.replace(/^react-native/, \"react-native-gtkx\"),\n platform,\n )\n }\n return fallback(context, moduleName, platform)\n }\n\n // The cast: T may carry narrower resolver/serializer types than the ones\n // rebuilt here — the runtime shape is a strict superset of both.\n return {\n ...config,\n resolver: {\n ...config.resolver,\n platforms: [\n ...new Set([...(config.resolver?.platforms ?? []), LINUX_PLATFORM]),\n ],\n resolveRequest,\n },\n serializer: {\n ...config.serializer,\n // RN prepends InitializeCore (Hermes Promise, nativeLoggingHook\n // console...). Our runtime environment IS Node — nothing to\n // initialize inside the bundle.\n getModulesRunBeforeMainModule: () => [],\n },\n } as LinuxPlatformConfig<T>\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metro/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Metro preset for the linux out-of-tree platform: wrap the app's Metro\n// config with `withLinuxPlatform` and the standard RN toolchain bundles for\n// `--platform linux`.\n//\n// What it does on top of RN defaults (validated by spike/rn-platform):\n//\n// 1. Adds \"linux\" to resolver.platforms (`.linux.tsx` extensions and\n// Platform.OS come along with it).\n// 2. Redirects `react-native` (and subpaths) to `react-native-gtkx` — the\n// out-of-tree npmPackageName declaration alone does not alias imports\n// for `bundle`, the resolver has to.\n// 3. EXTERNALIZES host-side singletons. Unlike react-native-windows, whose\n// native side lives outside the JS bundle by construction, our \"native\"\n// is Node modules with NAPI bindings (@gtkx/*) plus yoga-layout's WASM —\n// Metro cannot bundle those. react (and its jsx runtimes) must also stay\n// host-side: the reconciler inside @gtkx/react and the app have to share\n// one React instance. Every external resolves to a generated proxy that\n// reads the real module from global.__hostModules — the run-linux host\n// injects them before executing the bundle.\n// 4. Proxies Node builtins through the host's require: apps on this\n// platform may use the whole Node API, it is a platform feature.\n// 5. Drops InitializeCore (RN's mobile environment polyfills): the runtime\n// environment IS Node, the host provides everything.\nimport { mkdirSync, writeFileSync } from \"node:fs\"\nimport { builtinModules, isBuiltin } from \"node:module\"\nimport { join } from \"node:path\"\n\n/** Modules the run-linux host provides to the bundle at runtime. */\nexport const HOST_MODULE_EXTERNALS = [\n \"@gtkx/css\",\n \"@gtkx/gi/adw\",\n \"@gtkx/gi/gdk\",\n \"@gtkx/gi/gio\",\n \"@gtkx/gi/glib\",\n \"@gtkx/gi/gobject\",\n \"@gtkx/gi/graphene\",\n \"@gtkx/gi/gsk\",\n \"@gtkx/gi/gtk\",\n \"@gtkx/gi/pango\",\n \"@gtkx/jsx/adw\",\n \"@gtkx/jsx/gio\",\n \"@gtkx/jsx/gtk\",\n \"@gtkx/react\",\n \"@gtkx/react/internal\",\n \"@gtkx/runtime\",\n \"react\",\n \"react/jsx-runtime\",\n \"react/jsx-dev-runtime\",\n \"yoga-layout\",\n]\n\nexport const LINUX_PLATFORM = \"linux\"\n\n// Structural slices of Metro's config/resolution types: Metro is the app's\n// dependency, not ours — depending on its types here would pin versions.\nexport type MetroResolutionContext = {\n resolveRequest: MetroResolver\n}\nexport type MetroResolution = { type: string; filePath?: string }\nexport type MetroResolver = (\n context: MetroResolutionContext,\n moduleName: string,\n platform: string | null,\n) => MetroResolution\n\nexport type MetroLikeConfig = {\n projectRoot?: string\n resolver?: {\n platforms?: readonly string[]\n resolveRequest?: MetroResolver | null\n }\n serializer?: {\n getModulesRunBeforeMainModule?: (entryFilePath: string) => string[]\n }\n}\n\nexport type LinuxPlatformOptions = {\n /** Extra host-provided modules to keep out of the bundle. */\n externals?: readonly string[]\n /** Proxy directory override (default: node_modules/.react-native-gtkx). */\n proxyDir?: string\n}\n\nconst sanitize = (name: string): string => name.replace(/[@/:]/g, \"_\") + \".js\"\n\nconst hostModuleProxy = (name: string): string =>\n // The run-linux host guarantees __hostModules before executing the bundle.\n `module.exports = global.__hostModules[${JSON.stringify(name)}]\\n`\n\nconst builtinProxy = (name: string): string =>\n `module.exports = global.__hostRequire(${JSON.stringify(name)})\\n`\n\n// Every proxy is generated eagerly when the config loads: Metro crawls the\n// file map before transforming, and files that appear mid-build lose the\n// race (\"Failed to get the SHA-1\"). The builtin list is finite, so the\n// whole proxy set can exist up front.\nconst generateProxies = (dir: string, externals: Set<string>): void => {\n mkdirSync(dir, { recursive: true })\n for (const name of externals) {\n writeFileSync(join(dir, sanitize(name)), hostModuleProxy(name))\n }\n for (const bare of builtinModules) {\n writeFileSync(join(dir, sanitize(bare)), builtinProxy(bare))\n writeFileSync(\n join(dir, sanitize(`node:${bare}`)),\n builtinProxy(`node:${bare}`),\n )\n }\n}\n\nexport type LinuxPlatformConfig<T extends MetroLikeConfig> = T & {\n resolver: {\n platforms: string[]\n resolveRequest: MetroResolver\n }\n serializer: {\n getModulesRunBeforeMainModule: (entryFilePath: string) => string[]\n }\n}\n\n/**\n * Wraps a Metro config (RN's getDefaultConfig output) with everything the\n * linux platform needs. Composes with an existing custom resolveRequest —\n * non-linux platforms fall through to it untouched.\n */\nexport const withLinuxPlatform = <T extends MetroLikeConfig>(\n config: T,\n options: LinuxPlatformOptions = {},\n): LinuxPlatformConfig<T> => {\n const externals = new Set([\n ...HOST_MODULE_EXTERNALS,\n ...(options.externals ?? []),\n ])\n const proxyDir =\n options.proxyDir ??\n join(\n config.projectRoot ?? process.cwd(),\n \"node_modules\",\n \".react-native-gtkx\",\n \"metro-externals\",\n )\n generateProxies(proxyDir, externals)\n const previousResolve = config.resolver?.resolveRequest ?? null\n\n const fallback: MetroResolver = (context, moduleName, platform) =>\n previousResolve\n ? previousResolve(context, moduleName, platform)\n : context.resolveRequest(context, moduleName, platform)\n\n const resolveRequest: MetroResolver = (context, moduleName, platform) => {\n if (platform !== LINUX_PLATFORM) {\n return fallback(context, moduleName, platform)\n }\n if (externals.has(moduleName) || isBuiltin(moduleName)) {\n return {\n type: \"sourceFile\",\n filePath: join(proxyDir, sanitize(moduleName)),\n }\n }\n if (\n moduleName === \"react-native\" ||\n moduleName.startsWith(\"react-native/\")\n ) {\n return fallback(\n context,\n moduleName.replace(/^react-native/, \"react-native-gtkx\"),\n platform,\n )\n }\n // Same alias, same guard shape, for the SVG compat subpath (see\n // src/svg-compat/index.ts and the vite preset's rewriteReactNativeImport\n // — kept in sync deliberately rather than sharing code, Metro and vite\n // resolvers have never shared an implementation in this package).\n if (\n moduleName === \"react-native-svg\" ||\n moduleName.startsWith(\"react-native-svg/\")\n ) {\n return fallback(\n context,\n moduleName.replace(/^react-native-svg/, \"react-native-gtkx/svg\"),\n platform,\n )\n }\n return fallback(context, moduleName, platform)\n }\n\n // The cast: T may carry narrower resolver/serializer types than the ones\n // rebuilt here — the runtime shape is a strict superset of both.\n return {\n ...config,\n resolver: {\n ...config.resolver,\n platforms: [\n ...new Set([...(config.resolver?.platforms ?? []), LINUX_PLATFORM]),\n ],\n resolveRequest,\n },\n serializer: {\n ...config.serializer,\n // RN prepends InitializeCore (Hermes Promise, nativeLoggingHook\n // console...). Our runtime environment IS Node — nothing to\n // initialize inside the bundle.\n getModulesRunBeforeMainModule: () => [],\n },\n } as LinuxPlatformConfig<T>\n}\n"]}
@@ -1,30 +1,64 @@
1
- import { type NavigationProp, type ParamListBase, type RouteProp, type StackNavigationState } from "@react-navigation/native";
1
+ import { type NavigationProp, type NavigatorTypeBagBase, type NavigatorTypeBagFor, type ParamListBase, type RouteProp, type StackNavigationState, type TypedNavigator } from "@react-navigation/native";
2
2
  import { type ComponentType, type ReactNode } from "react";
3
3
  import type { HeaderButton } from "./sidebar";
4
4
  export type StackNavigationOptions = {
5
- /** HeaderBar title; defaults to the route name. */
5
+ /** AdwHeaderBar title; defaults to the route name. */
6
6
  title?: string;
7
- /** Render the Adwaita HeaderBar for this screen (default true). */
7
+ /** Render the Adwaitan AdwHeaderBar for this screen (default true). */
8
8
  headerShown?: boolean;
9
- /** Buttons packed at the end of this screen's HeaderBar (see
9
+ /** Buttons packed at the end of this screen's AdwHeaderBar (see
10
10
  * HeaderButton); screens usually set them via navigation.setOptions. */
11
11
  headerButtons?: HeaderButton[];
12
- /** RN content packed at the start of the HeaderBar (an intrinsic-size
12
+ /** RN content packed at the start of the AdwHeaderBar (an intrinsic-size
13
13
  * layout root: the content's Yoga size IS the slot size). */
14
14
  headerLeft?: () => ReactNode;
15
- /** RN content packed at the end of the HeaderBar, before headerButtons. */
15
+ /** RN content packed at the end of the AdwHeaderBar, before headerButtons. */
16
16
  headerRight?: () => ReactNode;
17
17
  /** false disables the native back button, Escape and the back gesture
18
18
  * for this screen (the page's Adwaita can-pop). Programmatic goBack
19
19
  * still works. Also the mechanism behind usePreventRemove. */
20
20
  gestureEnabled?: boolean;
21
+ /**
22
+ * `"none"` turns transitions off; any other value (including the
23
+ * `@react-navigation/native-stack` style names like `"slide_from_bottom"`
24
+ * or `"fade"`) turns them on. GTK has exactly one transition style, so a
25
+ * specific requested type cannot be honored — only whether to animate at
26
+ * all can be. Requesting a specific (non-`"default"`) type still animates,
27
+ * with the standard Adwaita transition, and warns once in development.
28
+ * Read from whichever screen is currently on top of the visible stack, so
29
+ * setting it uniformly via `screenOptions` is the reliable way to use it —
30
+ * see docs/api.md.
31
+ */
32
+ animation?: string;
33
+ };
34
+ export type StackNavigationEventMap = {
35
+ /** Fires when a push/pop/replace transition starts, once per involved
36
+ * route (not once per gesture or user tap). */
37
+ transitionStart: {
38
+ data: {
39
+ closing: boolean;
40
+ };
41
+ };
42
+ /** Fires when the transition settles, driven by the page's own real
43
+ * `shown`/`hidden` AdwNavigationPage signal (see docs/api.md and the
44
+ * primitive's beginTransition) — not a timer, except as a fallback for
45
+ * the rare cases where neither signal arrives. Native pops (back
46
+ * button, Escape, back gesture) do not fire this at all today — see
47
+ * docs/api.md. */
48
+ transitionEnd: {
49
+ data: {
50
+ closing: boolean;
51
+ };
52
+ };
21
53
  };
22
54
  type StackNavigatorProps = {
23
55
  initialRouteName?: string;
24
56
  screenOptions?: StackNavigationOptions;
25
57
  children: ReactNode;
26
58
  };
27
- export type StackNavigationHelpers<ParamList extends ParamListBase = ParamListBase, RouteName extends keyof ParamList = keyof ParamList> = NavigationProp<ParamList, RouteName, undefined, StackNavigationState<ParamList>, StackNavigationOptions>;
59
+ declare const StackNavigator: ({ initialRouteName, screenOptions, children, }: StackNavigatorProps) => React.JSX.Element;
60
+ export { createSidebarNavigator, type HeaderButton, type SidebarNavigationEventMap, type SidebarNavigationHelpers, type SidebarNavigationOptions, type SidebarScreenConfig, type SidebarScreenProps, type TypedSidebarNavigator, } from "./sidebar";
61
+ export type StackNavigationHelpers<ParamList extends ParamListBase = ParamListBase, RouteName extends keyof ParamList = keyof ParamList> = NavigationProp<ParamList, RouteName, StackNavigationState<ParamList>, StackNavigationOptions, StackNavigationEventMap>;
28
62
  export type StackScreenProps<ParamList extends ParamListBase = ParamListBase, RouteName extends keyof ParamList = keyof ParamList> = {
29
63
  route: RouteProp<ParamList, RouteName>;
30
64
  navigation: StackNavigationHelpers<ParamList, RouteName>;
@@ -35,10 +69,13 @@ export type StackScreenConfig<ParamList extends ParamListBase, RouteName extends
35
69
  options?: StackNavigationOptions | ((props: StackScreenProps<ParamList, RouteName>) => StackNavigationOptions);
36
70
  initialParams?: Partial<ParamList[RouteName]>;
37
71
  };
38
- export type TypedStackNavigator<ParamList extends ParamListBase> = {
39
- Navigator: ComponentType<StackNavigatorProps>;
40
- Screen: <RouteName extends keyof ParamList>(props: StackScreenConfig<ParamList, RouteName>) => null;
41
- };
72
+ interface StackTypeBag extends NavigatorTypeBagBase {
73
+ ParamList: ParamListBase;
74
+ State: StackNavigationState<ParamListBase>;
75
+ ScreenOptions: StackNavigationOptions;
76
+ EventMap: StackNavigationEventMap;
77
+ ActionHelpers: Record<string, () => void>;
78
+ Navigator: typeof StackNavigator;
79
+ }
80
+ export type TypedStackNavigator<ParamList extends ParamListBase> = TypedNavigator<NavigatorTypeBagFor<StackTypeBag, ParamList>, undefined>;
42
81
  export declare const createStackNavigator: <ParamList extends ParamListBase = ParamListBase>() => TypedStackNavigator<ParamList>;
43
- export { createSidebarNavigator, type HeaderButton, type SidebarNavigationOptions, type SidebarScreenConfig, type SidebarScreenProps, type TypedSidebarNavigator, } from "./sidebar";
44
- export { CommonActions, NavigationContainer, StackActions, useFocusEffect, useIsFocused, useNavigation, useNavigationContainerRef, usePreventRemove, useRoute, } from "@react-navigation/native";
@@ -1,26 +1,27 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // react-native-gtkx/navigation — a react-navigation stack navigator backed
3
- // by Adw.NavigationView. The model mirrors @react-navigation/native-stack
4
- // on iOS (UINavigationController): react-navigation state is the source of
5
- // truth, the native view is imperatively synced to it, and NATIVE pops (the
6
- // Adwaita back button, Escape, the back gesture) are reported back through
7
- // the "popped" signal.
3
+ // by the Adw.NavigationView primitive from react-native-gtkx/adwaita.
8
4
  //
9
- // Sync protocol (the two directions must not echo each other):
10
- // - state view: an effect diffs the synced tag stack against
11
- // state.routes and drives pushByTag / popToTag / replaceWithTags. Pages
12
- // are declarative children keyed by route.key, so the widgets exist
13
- // before the effect runs.
14
- // - viewstate: "popped" fires for EVERY popped page, ours and the
15
- // user's. The discriminator is the state itself: a tag that is still in
16
- // state.routes means the user popped the view (dispatch POP); a tag
17
- // already gone from state means the pop was state-driven — ignore.
5
+ // This file is an ADAPTER and nothing else. Every widget concern — diffing
6
+ // the tag stack into pushes and pops, holding a popped page alive until its
7
+ // exit animation ends, bracketing transitions lives in the primitive. What
8
+ // stays here is exactly the react-navigation half:
9
+ //
10
+ // - statethe ordered tags handed to NavigationStack (route keys);
11
+ // - a native pop (back button, Escape, back gesture) StackActions.pop,
12
+ // but only when the tag is still in state, otherwise the pop was one WE
13
+ // caused and echoing it would double-pop;
14
+ // - descriptors → page titles, header content and canPop;
15
+ // - unknown-option warnings.
16
+ //
17
+ // The same split as @react-navigation/native-stack over react-native-screens.
18
+ // If you do not want a router, use the primitive directly.
18
19
  import { createNavigatorFactory, StackActions, StackRouter, useNavigationBuilder, usePreventRemoveContext, } from "@react-navigation/native";
19
- import { useCallback, useEffect, useRef, useState, } from "react";
20
- import { InteractionManager } from "../apis/interaction-manager";
20
+ import { useEffect, useRef } from "react";
21
21
  import { getActiveChrome } from "../components/app-registry";
22
- import { IntrinsicRoot, NestedRoot } from "../components/root";
23
- import { AdwHeaderBar, AdwNavigationPage, AdwNavigationView, AdwToolbarView, GtkButton, } from "../gtkx/bridge/index";
22
+ import { AdwHeaderBar, AdwToolbarView } from "../adw";
23
+ import { HeaderSlotContent, NavigationStack, NavigationStackPage, SlotContent, } from "../common";
24
+ import { GtkButton } from "../gtkx/bridge/index";
24
25
  import { warnIgnoredOptions } from "./option-warnings";
25
26
  const STACK_OPTION_KEYS = new Set([
26
27
  "title",
@@ -29,6 +30,7 @@ const STACK_OPTION_KEYS = new Set([
29
30
  "headerLeft",
30
31
  "headerRight",
31
32
  "gestureEnabled",
33
+ "animation",
32
34
  ]);
33
35
  const StackNavigator = ({ initialRouteName, screenOptions, children, }) => {
34
36
  const { state, descriptors, navigation, NavigationContent } = useNavigationBuilder(StackRouter, {
@@ -36,12 +38,47 @@ const StackNavigator = ({ initialRouteName, screenOptions, children, }) => {
36
38
  screenOptions,
37
39
  children,
38
40
  });
39
- const viewRef = useRef(null);
41
+ // React Navigation 8: `state.routes` is no longer just the visible stack —
42
+ // it is active routes followed by retained routes (closing, kept mounted
43
+ // for `inactiveBehavior`) and preloaded routes (`navigation.preload()`,
44
+ // not yet navigated to), all concatenated, with the focused/visible tail
45
+ // ending at `state.index` (see StackRouter's `getStateWithRoutes`: `routes:
46
+ // activeRoutes.concat(retainedRoutes, preloadedRoutes)`, `index:
47
+ // activeRoutes.length - 1`). Handing the whole array to NavigationStack
48
+ // would push a preloaded screen onto the widget as if it were a real page
49
+ // the user navigated to. Only the active slice is the visible stack.
50
+ const visibleRoutes = state.routes.slice(0, state.index + 1);
51
+ const visibleKeys = visibleRoutes.map((route) => route.key);
52
+ // GTK has exactly one transition style and one animate-transitions switch
53
+ // for the whole view — there is no per-route knob to hand it. The screen
54
+ // actually being navigated TO is the natural read of "the currently
55
+ // relevant animation option": for a push, that is the new top of stack;
56
+ // for a pop, the screen the pop reveals. An app that sets `animation`
57
+ // uniformly through `screenOptions` (the common case for "turn animation
58
+ // off entirely") gets the same value everywhere, so this only matters
59
+ // when different screens genuinely disagree.
60
+ const activeRouteKey = visibleKeys[visibleKeys.length - 1];
61
+ const activeDescriptor = activeRouteKey
62
+ ? descriptors[activeRouteKey]
63
+ : undefined;
64
+ const animateTransitions = activeDescriptor?.options.animation !== "none";
40
65
  useEffect(() => {
41
66
  for (const route of state.routes) {
42
67
  const descriptor = descriptors[route.key];
43
68
  if (descriptor) {
44
69
  warnIgnoredOptions("createStackNavigator", descriptor.options, STACK_OPTION_KEYS);
70
+ const { animation } = descriptor.options;
71
+ // "animation" itself is in STACK_OPTION_KEYS above (it IS honored,
72
+ // collapsed to a boolean), so the call above never flags it. A
73
+ // specific requested type — anything but "none" (handled) or
74
+ // "default" (not a specific request) — is a separate, narrower
75
+ // complaint, forced through the same verdict lookup and the same
76
+ // once-per-navigator-per-key dedupe with an empty supported set.
77
+ if (animation !== undefined &&
78
+ animation !== "none" &&
79
+ animation !== "default") {
80
+ warnIgnoredOptions("createStackNavigator", { animation }, new Set());
81
+ }
45
82
  }
46
83
  }
47
84
  }, [state, descriptors]);
@@ -51,127 +88,129 @@ const StackNavigator = ({ initialRouteName, screenOptions, children, }) => {
51
88
  console.warn('[react-native-gtkx/navigation] the app runs with the default window chrome — pages bring their own HeaderBars, so you will see a doubled titlebar. Pass chrome: "content" to AppRegistry.runApplication.');
52
89
  }
53
90
  }, []);
54
- // Mirror of the view's visible stack (route keys), maintained by the sync
55
- // effect and by the popped handler — the two never race: GTK signals run
56
- // synchronously inside the very push/pop calls the effect makes.
57
- const syncedRef = useRef([]);
58
- // Pop ANIMATION support: react-navigation drops a popped route from state
59
- // immediately, but Adwaita still animates the page out (~200 ms). Pages
60
- // therefore render from renderedKeys — live routes plus closing pages —
61
- // and a closing page leaves only on its "hidden" signal (the end of the
62
- // transition). Its content renders from a snapshot cached while live.
63
- const [renderedKeys, setRenderedKeys] = useState(() => state.routes.map((route) => route.key));
64
- const liveKeys = state.routes.map((route) => route.key);
65
- const missingKeys = liveKeys.filter((key) => !renderedKeys.includes(key));
66
- if (missingKeys.length > 0) {
67
- // The sanctioned derive-state-during-render pattern: a new route must be
68
- // in renderedKeys within the same commit its page is pushed.
69
- setRenderedKeys([...renderedKeys, ...missingKeys]);
70
- }
71
- // A state-held stable Map (not a ref): the render path reads it for
72
- // closing pages, and the react-hooks/refs rule rightly bans render-time
73
- // ref reads.
74
- const [snapshots] = useState(() => new Map());
75
- useEffect(() => {
76
- for (const route of state.routes) {
77
- const descriptor = descriptors[route.key];
78
- if (descriptor) {
79
- snapshots.set(route.key, {
80
- name: route.name,
81
- options: descriptor.options,
82
- element: _jsx(NestedRoot, { children: descriptor.render() }),
83
- });
84
- }
91
+ // `navigation` is identity-stable across renders (react-navigation builder
92
+ // contract) and getState() always reads the live state no ref needed.
93
+ const handlePopped = (tag) => {
94
+ if (navigation.getState().routes.some((route) => route.key === tag)) {
95
+ // Still in state, so the WIDGET popped on its own: follow in state.
96
+ navigation.dispatch(StackActions.pop());
85
97
  }
86
- });
87
- const handleHidden = useCallback((key) => {
88
- // "hidden" also fires for a live page covered by a push — only pages
89
- // gone from state are actually closing.
90
- if (navigation.getState().routes.some((route) => route.key === key)) {
91
- return;
98
+ // Otherwise state dropped the route first and the primitive is merely
99
+ // reporting the animation we asked for. Nothing to do.
100
+ };
101
+ // transitionStart/transitionEnd: translates NavigationStack's primitive
102
+ // callbacks into react-navigation's own per-route events, matching
103
+ // @react-navigation/stack and @react-navigation/native-stack's v8
104
+ // behavior byte for byte (verified against their source, not docs — see
105
+ // 007.md): a route that just became visible fires `closing: false`, a
106
+ // route that just left the visible stack fires `closing: true`, and a
107
+ // route whose visibility did not change (e.g. covered by a push) gets
108
+ // neither event.
109
+ //
110
+ // The start and end sides deliberately use TWO DIFFERENT primitive
111
+ // signals, not the same onTransitionStart/onTransitionEnd pair for both:
112
+ //
113
+ // - transitionStart (both directions) rides onTransitionStart, a
114
+ // view-level "a transition just began" signal with no per-route
115
+ // identity — the adapter supplies that identity itself by diffing
116
+ // visibleKeys against the previous render's visible keys.
117
+ // - transitionEnd for an OPENING route also rides the view-level
118
+ // onTransitionEnd, itself driven by the pushed page's own real "shown"
119
+ // signal (transitionDuration only as a fallback — see docs/api.md and
120
+ // the primitive's beginTransition): the pushed screen stays mounted
121
+ // indefinitely once it is the active page, so nothing about that is
122
+ // unsafe here either way.
123
+ // - transitionEnd for a CLOSING route rides onPageClosed instead, fired
124
+ // PER TAG when that page's exit actually finishes (a real GTK
125
+ // "hidden" signal when available, the primitive's own timer as
126
+ // fallback). This was not a style choice: routing the closing side
127
+ // through the generic view-level timer was tried first and is wrong
128
+ // whenever the real close finishes before the fixed transitionDuration
129
+ // default (guaranteed in headless test environments with animations
130
+ // disabled, and possible on a real desktop too) — the closing screen's
131
+ // React component has already unmounted (and unsubscribed its
132
+ // listeners) by the time the generic, one-size-fits-all timer gets
133
+ // around to firing, so the event never reaches anyone. onPageClosed
134
+ // fires synchronously before React commits that unmount, so the
135
+ // listener is still there to receive it.
136
+ //
137
+ // previousVisibleKeysRef is compared by CONTENT, not a call-count flag:
138
+ // NavigationStack's sync effect can call beginTransition() (hence
139
+ // onTransitionStart) more than once for one state update — e.g. popping
140
+ // back past two routes and pushing two new ones in the same dispatch
141
+ // calls it three times — and every one of those calls closes over the
142
+ // SAME visibleKeys for this render. Diffing against the ref and only
143
+ // then updating it makes every call after the first a no-op (the ref
144
+ // already equals visibleKeys), without a manual "already handling a
145
+ // transition" flag that would also incorrectly swallow a second,
146
+ // genuinely separate transition starting before the first one settles.
147
+ const previousVisibleKeysRef = useRef(visibleKeys);
148
+ const pendingOpeningEndRef = useRef([]);
149
+ // Tags this adapter itself put in flight via transitionStart(closing:
150
+ // true) — NOT every tag onPageClosed ever reports. A native pop (back
151
+ // button, Escape, back gesture) also eventually drops its tag through
152
+ // the exact same primitive mechanism, but never called beginTransition()
153
+ // (see the primitive: a native pop's own handlePopped reconciles
154
+ // syncedRef directly, so the sync effect finds nothing left to push or
155
+ // pop once react-navigation's state catches up) — so it never got a
156
+ // transitionStart either. Without this guard, handlePageClosed would
157
+ // emit a transitionEnd with no matching transitionStart for every native
158
+ // pop, which is worse than emitting neither: a listener would see an
159
+ // end event out of nowhere. Documented as Known limitation #2 in 007.md
160
+ // — native pops fire neither event today.
161
+ const pendingClosingRef = useRef(new Set());
162
+ const emitTransitionEvent = (type, keys, closing) => {
163
+ for (const key of keys) {
164
+ navigation.emit({ type, data: { closing }, target: key });
92
165
  }
93
- snapshots.delete(key);
94
- setRenderedKeys((keys) => keys.filter((rendered) => rendered !== key));
95
- }, [navigation, snapshots]);
96
- // "hidden" delivery is not guaranteed in every environment (headless
97
- // compositors with animations disabled never emit it) — a timer slightly
98
- // longer than the Adwaita transition is the fallback; handleHidden is
99
- // idempotent, whichever fires first wins.
100
- const scheduleRetainedRemoval = useCallback((key) => {
101
- setTimeout(() => handleHidden(key), 400);
102
- }, [handleHidden]);
103
- // Bracket every view transition with an InteractionManager handle so
104
- // runAfterInteractions-scheduled work (a screen's own data load / heavy
105
- // render) waits for the slide to finish instead of stealing its frames.
106
- // The handle is opened when the sync effect mutates the view and cleared
107
- // one transition-length later; overlapping transitions reference-count.
108
- const beginTransition = useCallback(() => {
109
- const handle = InteractionManager.createInteractionHandle();
110
- setTimeout(() => InteractionManager.clearInteractionHandle(handle), 400);
111
- }, []);
112
- useEffect(() => {
113
- const view = viewRef.current;
114
- if (!view) {
166
+ };
167
+ const handleTransitionStart = () => {
168
+ const previous = previousVisibleKeysRef.current;
169
+ if (previous.length === visibleKeys.length &&
170
+ previous.every((key, index) => key === visibleKeys[index])) {
171
+ // A duplicate beginTransition() call for the same commit (see
172
+ // above) already diffed by an earlier call this render.
115
173
  return;
116
174
  }
117
- const target = state.routes.map((route) => route.key);
118
- if (syncedRef.current.length === 0 && target.length > 0) {
119
- // First mount: NavigationView shows the first added page by itself.
120
- syncedRef.current = target.slice(0, 1);
175
+ const opening = visibleKeys.filter((key) => !previous.includes(key));
176
+ const closing = previous.filter((key) => !visibleKeys.includes(key));
177
+ previousVisibleKeysRef.current = visibleKeys;
178
+ pendingOpeningEndRef.current.push(...opening);
179
+ for (const key of closing) {
180
+ pendingClosingRef.current.add(key);
121
181
  }
122
- let common = 0;
123
- while (common < syncedRef.current.length &&
124
- common < target.length &&
125
- syncedRef.current[common] === target[common]) {
126
- common += 1;
127
- }
128
- if (common === 0 && syncedRef.current[0] !== target[0]) {
129
- // The stack root changed (reset): swap the whole visible stack.
130
- const leaving = syncedRef.current.filter((key) => !target.includes(key));
131
- syncedRef.current = [...target];
132
- beginTransition();
133
- view.replaceWithTags(target);
134
- for (const key of leaving) {
135
- scheduleRetainedRemoval(key);
136
- }
182
+ emitTransitionEvent("transitionStart", opening, false);
183
+ emitTransitionEvent("transitionStart", closing, true);
184
+ };
185
+ // Drains whatever opening keys are pending rather than trusting call
186
+ // count, for the same reason handleTransitionStart diffs by content: a
187
+ // compound update's several onTransitionEnd calls (one per
188
+ // beginTransition() above) all land at essentially the same moment, so
189
+ // the first one emits everything queued and the rest find nothing left
190
+ // to drain. Closing keys are NOT handled here — see handlePageClosed.
191
+ const handleTransitionEnd = () => {
192
+ const opening = pendingOpeningEndRef.current;
193
+ if (opening.length === 0) {
137
194
  return;
138
195
  }
139
- if (syncedRef.current.length > common) {
140
- const anchor = target[common - 1];
141
- const leaving = syncedRef.current.slice(common);
142
- syncedRef.current = syncedRef.current.slice(0, common);
143
- if (anchor !== undefined) {
144
- beginTransition();
145
- view.popToTag(anchor);
146
- }
147
- for (const key of leaving) {
148
- scheduleRetainedRemoval(key);
149
- }
150
- }
151
- for (let index = syncedRef.current.length; index < target.length; index += 1) {
152
- const key = target[index];
153
- syncedRef.current.push(key);
154
- beginTransition();
155
- view.pushByTag(key);
156
- }
157
- }, [state, scheduleRetainedRemoval, beginTransition]);
158
- // `navigation` is identity-stable across renders (react-navigation
159
- // builder contract) and getState() always reads the live state — the
160
- // closure needs no ref indirection.
161
- const handlePopped = (page) => {
162
- const tag = page?.getTag();
163
- if (!tag) {
196
+ pendingOpeningEndRef.current = [];
197
+ emitTransitionEvent("transitionEnd", opening, false);
198
+ };
199
+ const handlePageClosed = (tag) => {
200
+ if (!pendingClosingRef.current.has(tag)) {
201
+ // Not a tag this adapter put in flight (a native pop, or a stray
202
+ // call) — no transitionStart was ever emitted for it, so no
203
+ // transitionEnd either.
164
204
  return;
165
205
  }
166
- syncedRef.current = syncedRef.current.filter((key) => key !== tag);
167
- const current = navigation.getState();
168
- if (current.routes.some((route) => route.key === tag)) {
169
- // The view popped on its own (back button / gesture): follow in state.
170
- navigation.dispatch(StackActions.pop());
171
- }
172
- scheduleRetainedRemoval(tag);
206
+ pendingClosingRef.current.delete(tag);
207
+ navigation.emit({
208
+ type: "transitionEnd",
209
+ data: { closing: true },
210
+ target: tag,
211
+ });
173
212
  };
174
- return (_jsx(NavigationContent, { children: _jsx(StackView, { viewRef: viewRef, renderedKeys: renderedKeys, routeKeys: state.routes.map((route) => route.key), descriptors: descriptors, snapshots: snapshots, onPopped: handlePopped, onHidden: handleHidden }) }));
213
+ return (_jsx(NavigationContent, { children: _jsx(StackView, { routeKeys: visibleKeys, descriptors: descriptors, animateTransitions: animateTransitions, onPopped: handlePopped, onTransitionStart: handleTransitionStart, onTransitionEnd: handleTransitionEnd, onPageClosed: handlePageClosed }) }));
175
214
  };
176
215
  // The page list lives inside NavigationContent so it can read the
177
216
  // prevent-remove context (which useNavigationBuilder only provides to
@@ -181,36 +220,32 @@ const StackNavigator = ({ initialRouteName, screenOptions, children, }) => {
181
220
  // programmatic goBack still pops (once the app lifts the prevention, e.g.
182
221
  // after its own confirmation dialog). This is why a native pop can never
183
222
  // race react-navigation state for these routes.
184
- const StackView = ({ viewRef, renderedKeys, routeKeys, descriptors, snapshots, onPopped, onHidden, }) => {
223
+ const StackView = ({ routeKeys, descriptors, animateTransitions, onPopped, onTransitionStart, onTransitionEnd, onPageClosed, }) => {
185
224
  const { preventedRoutes } = usePreventRemoveContext();
186
- return (_jsx(AdwNavigationView, { ref: viewRef, onPopped: (page) => onPopped(page), children: renderedKeys.map((key) => {
187
- const isLive = routeKeys.includes(key);
188
- const descriptor = isLive
189
- ? descriptors[key]
190
- : undefined;
191
- const snapshot = snapshots.get(key);
192
- const options = descriptor?.options ?? snapshot?.options ?? {};
225
+ return (_jsx(NavigationStack, { stack: routeKeys, animateTransitions: animateTransitions, onPopped: onPopped, onTransitionStart: onTransitionStart, onTransitionEnd: onTransitionEnd, onPageClosed: onPageClosed, children: routeKeys.map((key) => {
226
+ const descriptor = descriptors[key];
227
+ if (!descriptor) {
228
+ return null;
229
+ }
230
+ const options = descriptor.options;
193
231
  const headerShown = options.headerShown ?? true;
194
232
  const canPop = options.gestureEnabled !== false &&
195
233
  !preventedRoutes[key]?.preventRemove;
196
- const content = descriptor ? (_jsx(NestedRoot, { children: descriptor.render() })) : ((snapshot?.element ?? null));
197
- return (_jsx(AdwNavigationPage, { tag: key,
198
- // Never the route key — that is an internal identifier, and
199
- // it would end up in the window title under content chrome.
200
- title: options.title ?? descriptor?.route.name ?? snapshot?.name ?? key, canPop: canPop, onHidden: () => onHidden(key), children: headerShown ? (_jsx(AdwToolbarView, { topBar: _jsx(AdwHeaderBar, { start: options.headerLeft ? (_jsx(IntrinsicRoot, { children: options.headerLeft() })) : undefined, end: [
234
+ const content = _jsx(SlotContent, { children: descriptor.render() });
235
+ return (_jsx(NavigationStackPage, { tag: key,
236
+ // Never the route key — that is an internal identifier, and it
237
+ // would end up in the window title under content chrome.
238
+ title: options.title ?? descriptor.route.name, canPop: canPop, children: headerShown ? (_jsx(AdwToolbarView, { topBar: _jsx(AdwHeaderBar, { start: options.headerLeft ? (_jsx(HeaderSlotContent, { children: options.headerLeft() })) : undefined, end: [
201
239
  ...(options.headerRight
202
240
  ? [
203
- _jsx(IntrinsicRoot, { children: options.headerRight() }, "header-right"),
241
+ _jsx(HeaderSlotContent, { children: options.headerRight() }, "header-right"),
204
242
  ]
205
243
  : []),
206
244
  ...(options.headerButtons?.map((button) => (_jsx(GtkButton, { iconName: button.icon, tooltipText: button.tooltip, onClicked: button.onPress }, button.id))) ?? []),
207
245
  ] }), children: content })) : (content) }, key));
208
246
  }) }));
209
247
  };
248
+ export { createSidebarNavigator, } from "./sidebar";
210
249
  const stackFactory = createNavigatorFactory(StackNavigator);
211
250
  export const createStackNavigator = () => stackFactory();
212
- export { createSidebarNavigator, } from "./sidebar";
213
- // The rest of the react-navigation surface apps need, so a linux app can
214
- // import everything from one place.
215
- export { CommonActions, NavigationContainer, StackActions, useFocusEffect, useIsFocused, useNavigation, useNavigationContainerRef, usePreventRemove, useRoute, } from "@react-navigation/native";
216
251
  //# sourceMappingURL=index.js.map