akanjs 3.0.0-alpha.2 → 3.0.0-alpha.21

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 (388) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/base/symbols.ts +4 -0
  4. package/client/clientRuntime.ts +8 -0
  5. package/client/cn.ts +7 -0
  6. package/client/csrTypes.ts +2 -0
  7. package/client/frameDebug.ts +3 -2
  8. package/common/Logger.ts +4 -0
  9. package/common/deepObjectify.ts +21 -7
  10. package/common/index.ts +14 -0
  11. package/common/mcpExposure.ts +99 -0
  12. package/common/pathSet.ts +17 -5
  13. package/common/routeConvention.ts +30 -0
  14. package/constant/crystalize.ts +3 -1
  15. package/constant/fieldInfo.ts +6 -0
  16. package/constant/getDefault.ts +37 -9
  17. package/constant/immerify.ts +1 -1
  18. package/constant/index.ts +2 -0
  19. package/constant/labelOf.ts +17 -0
  20. package/constant/mask.ts +60 -0
  21. package/constant/purify.ts +17 -11
  22. package/constant/types.ts +14 -12
  23. package/dictionary/DictionaryLookup.ts +30 -0
  24. package/dictionary/agent.dictionary.ts +31 -0
  25. package/dictionary/agentTurn.dictionary.ts +29 -0
  26. package/dictionary/base.dictionary.ts +8 -0
  27. package/dictionary/dictInfo.ts +8 -0
  28. package/dictionary/dictionary.ts +9 -3
  29. package/dictionary/index.ts +1 -0
  30. package/document/database.ts +21 -0
  31. package/document/filterMeta.ts +7 -0
  32. package/document/index.ts +1 -0
  33. package/document/into.ts +7 -1
  34. package/document/noDocumentError.ts +12 -0
  35. package/fetch/agentTurn.ts +19 -0
  36. package/fetch/client/fetchClient.ts +71 -13
  37. package/fetch/client/wsClient.ts +17 -2
  38. package/fetch/fetchType/endpointFetch.type.ts +10 -4
  39. package/fetch/index.ts +1 -0
  40. package/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
  41. package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
  42. package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
  43. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
  44. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
  45. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
  46. package/package.json +11 -9
  47. package/server/akanApp.ts +30 -34
  48. package/server/akanOption.ts +65 -7
  49. package/server/akanServer.ts +172 -7
  50. package/server/animatedImage.ts +83 -0
  51. package/server/artifact/routeClientCache.ts +14 -0
  52. package/server/assetEncoding.ts +47 -0
  53. package/server/devtools/signalSerializer.ts +2 -2
  54. package/server/devtools/types.ts +2 -2
  55. package/server/di/diLifecycle.ts +31 -3
  56. package/server/di/predefinedAdaptor.ts +6 -0
  57. package/server/imageOptimizer.ts +33 -46
  58. package/server/index.ts +1 -2
  59. package/server/mcp/McpAuth.ts +177 -0
  60. package/server/mcp/McpDispatcher.ts +245 -0
  61. package/server/mcp/McpEventStream.ts +76 -0
  62. package/server/mcp/McpExecutionContext.ts +105 -0
  63. package/server/mcp/McpRouter.ts +591 -0
  64. package/server/mcp/index.ts +5 -0
  65. package/server/resolver/CascadeRunner.ts +1 -1
  66. package/server/resolver/database.resolver.ts +42 -5
  67. package/server/resolver/service.resolver.ts +29 -0
  68. package/server/resolver/signal.resolver.ts +16 -1
  69. package/server/routeTreeBuilder.ts +2 -44
  70. package/server/rscWorker.tsx +6 -2
  71. package/server/subRouteIndexDocument.tsx +61 -0
  72. package/server/systemPageDocument.tsx +2 -2
  73. package/server/systemPages.tsx +49 -16
  74. package/server/vendor/akanjs-fetch.ts +1 -0
  75. package/server/webRouter.ts +159 -35
  76. package/service/agent.service.ts +14 -0
  77. package/service/base.service.ts +2 -1
  78. package/service/index.ts +1 -0
  79. package/service/predefinedAdaptor/database.adaptor.ts +78 -24
  80. package/service/predefinedAdaptor/deepseekLlm.ts +230 -0
  81. package/service/predefinedAdaptor/index.ts +3 -0
  82. package/service/predefinedAdaptor/insightQuery.ts +183 -0
  83. package/service/predefinedAdaptor/llm.adaptor.ts +76 -0
  84. package/service/predefinedAdaptor/role.adaptor.ts +2 -0
  85. package/service/predefinedAdaptor/schedule.adaptor.ts +12 -5
  86. package/service/serviceModule.ts +17 -0
  87. package/service/types.ts +4 -0
  88. package/signal/agent/AgentCatalogue.ts +165 -0
  89. package/signal/agent/index.ts +1 -0
  90. package/signal/agent.signal.ts +42 -0
  91. package/signal/agentTurn.ts +8 -0
  92. package/signal/agentTurnStream.ts +48 -0
  93. package/signal/base.signal.ts +2 -1
  94. package/signal/endpointInfo.ts +38 -2
  95. package/signal/guard.ts +13 -1
  96. package/signal/guards.ts +52 -1
  97. package/signal/index.ts +6 -0
  98. package/signal/mcp/McpDocument.ts +286 -0
  99. package/signal/mcp/McpProgress.ts +106 -0
  100. package/signal/mcp/McpUriTemplate.ts +85 -0
  101. package/signal/mcp/Msg.ts +368 -0
  102. package/signal/mcp/index.ts +5 -0
  103. package/signal/mcp/mcpProtocol.ts +120 -0
  104. package/signal/middleware.ts +7 -3
  105. package/signal/openapi/openapi.ts +32 -171
  106. package/signal/schema/JsonSchemaBuilder.ts +211 -0
  107. package/signal/schema/index.ts +1 -0
  108. package/signal/signalContext.ts +85 -9
  109. package/signal/slice.ts +9 -9
  110. package/signal/types.ts +1 -1
  111. package/store/action.ts +11 -22
  112. package/store/actionTag.ts +33 -0
  113. package/store/agent/AgentBridge.ts +323 -0
  114. package/store/agent/AgentContext.ts +74 -0
  115. package/store/agent/AgentPrompts.ts +82 -0
  116. package/store/agent/AgentVisibility.ts +68 -0
  117. package/store/agent/ScreenReader.ts +208 -0
  118. package/store/agent/StoreCatalogue.ts +351 -0
  119. package/store/agent/StoreSurfaceSource.ts +122 -0
  120. package/store/agent/index.ts +9 -0
  121. package/store/agent/storeSurface.ts +28 -0
  122. package/store/agent/types.ts +50 -0
  123. package/store/agentic/StToolBuilder.ts +199 -0
  124. package/store/agentic/attachAgentic.ts +22 -0
  125. package/store/agentic/index.ts +5 -0
  126. package/store/agentic/readableValue.ts +17 -0
  127. package/store/agentic/useStExpose.ts +18 -0
  128. package/store/agentic/useStState.ts +35 -0
  129. package/store/baseSt.ts +7 -0
  130. package/store/databaseStateNames.ts +31 -0
  131. package/store/formSetterNames.ts +21 -0
  132. package/store/index.ts +8 -0
  133. package/store/rootStore.ts +3 -1
  134. package/store/sliceRole.ts +36 -0
  135. package/store/state.ts +2 -12
  136. package/store/store.ts +19 -1
  137. package/store/storeInstance.ts +165 -20
  138. package/store/storeRegistry.ts +16 -1
  139. package/store/types.ts +18 -0
  140. package/store/withSelector.ts +7 -8
  141. package/test/registerDom.ts +4 -0
  142. package/types/base/symbols.d.ts +4 -0
  143. package/types/client/cn.d.ts +5 -0
  144. package/types/client/csrTypes.d.ts +2 -0
  145. package/types/common/Logger.d.ts +2 -0
  146. package/types/common/deepObjectify.d.ts +4 -2
  147. package/types/common/index.d.ts +2 -1
  148. package/types/common/mcpExposure.d.ts +60 -0
  149. package/types/common/routeConvention.d.ts +8 -0
  150. package/types/constant/fieldInfo.d.ts +1 -0
  151. package/types/constant/getDefault.d.ts +5 -0
  152. package/types/constant/index.d.ts +2 -0
  153. package/types/constant/labelOf.d.ts +6 -0
  154. package/types/constant/mask.d.ts +34 -0
  155. package/types/constant/purify.d.ts +2 -2
  156. package/types/constant/types.d.ts +2 -2
  157. package/types/dictionary/DictionaryLookup.d.ts +14 -0
  158. package/types/dictionary/agent.dictionary.d.ts +1 -0
  159. package/types/dictionary/agentTurn.dictionary.d.ts +1 -0
  160. package/types/dictionary/base.dictionary.d.ts +1 -1
  161. package/types/dictionary/dictInfo.d.ts +6 -0
  162. package/types/dictionary/dictionary.d.ts +11 -9
  163. package/types/dictionary/index.d.ts +1 -0
  164. package/types/document/database.d.ts +20 -0
  165. package/types/document/filterMeta.d.ts +1 -0
  166. package/types/document/index.d.ts +1 -0
  167. package/types/document/into.d.ts +6 -1
  168. package/types/document/noDocumentError.d.ts +12 -0
  169. package/types/fetch/agentTurn.d.ts +593 -0
  170. package/types/fetch/client/fetchClient.d.ts +10 -0
  171. package/types/fetch/fetchType/endpointFetch.type.d.ts +5 -3
  172. package/types/fetch/index.d.ts +1 -0
  173. package/types/server/akanOption.d.ts +35 -7
  174. package/types/server/akanServer.d.ts +44 -1
  175. package/types/server/animatedImage.d.ts +7 -0
  176. package/types/server/artifact/routeClientCache.d.ts +6 -0
  177. package/types/server/assetEncoding.d.ts +7 -0
  178. package/types/server/devtools/types.d.ts +2 -2
  179. package/types/server/di/predefinedAdaptor.d.ts +4 -1
  180. package/types/server/index.d.ts +0 -2
  181. package/types/server/mcp/McpAuth.d.ts +62 -0
  182. package/types/server/mcp/McpDispatcher.d.ts +54 -0
  183. package/types/server/mcp/McpEventStream.d.ts +18 -0
  184. package/types/server/mcp/McpExecutionContext.d.ts +44 -0
  185. package/types/server/mcp/McpRouter.d.ts +60 -0
  186. package/types/server/mcp/index.d.ts +5 -0
  187. package/types/server/mcp.d.ts +1 -0
  188. package/types/server/subRouteIndexDocument.d.ts +8 -0
  189. package/types/server/systemPageDocument.d.ts +1 -0
  190. package/types/server/systemPages.d.ts +5 -0
  191. package/types/server/vendor/akanjs-fetch.d.ts +1 -0
  192. package/types/service/agent.service.d.ts +12 -0
  193. package/types/service/base.service.d.ts +4 -0
  194. package/types/service/index.d.ts +1 -0
  195. package/types/service/predefinedAdaptor/database.adaptor.d.ts +24 -2
  196. package/types/service/predefinedAdaptor/deepseekLlm.d.ts +64 -0
  197. package/types/service/predefinedAdaptor/index.d.ts +3 -0
  198. package/types/service/predefinedAdaptor/insightQuery.d.ts +50 -0
  199. package/types/service/predefinedAdaptor/llm.adaptor.d.ts +68 -0
  200. package/types/service/predefinedAdaptor/role.adaptor.d.ts +2 -0
  201. package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +10 -6
  202. package/types/service/types.d.ts +4 -1
  203. package/types/signal/agent/AgentCatalogue.d.ts +100 -0
  204. package/types/signal/agent/index.d.ts +1 -0
  205. package/types/signal/agent.d.ts +1 -0
  206. package/types/signal/agent.signal.d.ts +29 -0
  207. package/types/signal/agentTurn.d.ts +9 -0
  208. package/types/signal/agentTurnStream.d.ts +16 -0
  209. package/types/signal/base.signal.d.ts +1 -1
  210. package/types/signal/endpointInfo.d.ts +21 -3
  211. package/types/signal/guard.d.ts +11 -0
  212. package/types/signal/guards.d.ts +22 -1
  213. package/types/signal/index.d.ts +6 -0
  214. package/types/signal/mcp/McpDocument.d.ts +65 -0
  215. package/types/signal/mcp/McpProgress.d.ts +40 -0
  216. package/types/signal/mcp/McpUriTemplate.d.ts +26 -0
  217. package/types/signal/mcp/Msg.d.ts +143 -0
  218. package/types/signal/mcp/index.d.ts +5 -0
  219. package/types/signal/mcp/mcpProtocol.d.ts +107 -0
  220. package/types/signal/mcp.d.ts +1 -0
  221. package/types/signal/openapi/openapi.d.ts +3 -3
  222. package/types/signal/schema/JsonSchemaBuilder.d.ts +47 -0
  223. package/types/signal/schema/index.d.ts +1 -0
  224. package/types/signal/schema.d.ts +1 -0
  225. package/types/signal/signalContext.d.ts +16 -1
  226. package/types/signal/slice.d.ts +8 -8
  227. package/types/signal/types.d.ts +1 -1
  228. package/types/store/actionTag.d.ts +21 -0
  229. package/types/store/agent/AgentBridge.d.ts +77 -0
  230. package/types/store/agent/AgentContext.d.ts +16 -0
  231. package/types/store/agent/AgentPrompts.d.ts +31 -0
  232. package/types/store/agent/AgentVisibility.d.ts +21 -0
  233. package/types/store/agent/ScreenReader.d.ts +11 -0
  234. package/types/store/agent/StoreCatalogue.d.ts +26 -0
  235. package/types/store/agent/StoreSurfaceSource.d.ts +18 -0
  236. package/types/store/agent/index.d.ts +9 -0
  237. package/types/store/agent/storeSurface.d.ts +14 -0
  238. package/types/store/agent/types.d.ts +49 -0
  239. package/types/store/agent.d.ts +1 -0
  240. package/types/store/agentic/StToolBuilder.d.ts +41 -0
  241. package/types/store/agentic/attachAgentic.d.ts +14 -0
  242. package/types/store/agentic/index.d.ts +5 -0
  243. package/types/store/agentic/readableValue.d.ts +3 -0
  244. package/types/store/agentic/useStExpose.d.ts +8 -0
  245. package/types/store/agentic/useStState.d.ts +12 -0
  246. package/types/store/agentic.d.ts +1 -0
  247. package/types/store/baseSt.d.ts +29 -22
  248. package/types/store/databaseStateNames.d.ts +25 -0
  249. package/types/store/formSetterNames.d.ts +16 -0
  250. package/types/store/index.d.ts +7 -0
  251. package/types/store/rootStore.d.ts +5 -1
  252. package/types/store/sliceRole.d.ts +25 -0
  253. package/types/store/store.d.ts +7 -2
  254. package/types/store/storeInstance.d.ts +33 -1
  255. package/types/store/storeRegistry.d.ts +5 -0
  256. package/types/store/types.d.ts +15 -0
  257. package/types/store/withSelector.d.ts +7 -8
  258. package/types/test/registerDom.d.ts +1 -0
  259. package/types/ui/Agent/Approval.d.ts +7 -0
  260. package/types/ui/Agent/Bubble.d.ts +13 -0
  261. package/types/ui/Agent/Chat.d.ts +24 -0
  262. package/types/ui/Agent/Context.d.ts +9 -0
  263. package/types/ui/Agent/Dock.d.ts +16 -0
  264. package/types/ui/Agent/Guide.d.ts +9 -0
  265. package/types/ui/Agent/Section.d.ts +10 -0
  266. package/types/ui/Agent/StateKey.d.ts +16 -0
  267. package/types/ui/Agent/Tool.d.ts +15 -0
  268. package/types/ui/Agent/Transcript.d.ts +13 -0
  269. package/types/ui/Agent/Zone.d.ts +23 -0
  270. package/types/ui/Agent/fetchRunner.d.ts +12 -0
  271. package/types/ui/Agent/index.d.ts +17 -0
  272. package/types/ui/Agent/index_.d.ts +1 -0
  273. package/types/ui/Agent/sessionHistory.d.ts +12 -0
  274. package/types/ui/Agent.d.ts +1 -0
  275. package/types/ui/Badge.d.ts +1 -1
  276. package/types/ui/Button.d.ts +1 -1
  277. package/types/ui/CsrImage.d.ts +1 -1
  278. package/types/ui/Dropdown.d.ts +2 -0
  279. package/types/ui/Image.d.ts +3 -3
  280. package/types/ui/Layout/BottomInset.d.ts +2 -1
  281. package/types/ui/Layout/index.d.ts +1 -1
  282. package/types/ui/Signal/style.d.ts +4 -1
  283. package/types/ui/UiOverride/context.d.ts +14 -2
  284. package/types/ui/agentAttrs.d.ts +14 -0
  285. package/types/ui/index.d.ts +4 -1
  286. package/types/ui/overlayLayer.d.ts +24 -0
  287. package/types/ui/recipe/badgeRecipe.d.ts +7 -3
  288. package/types/ui/recipe/buttonRecipe.d.ts +7 -3
  289. package/types/ui/recipe/inputRecipe.d.ts +5 -1
  290. package/types/vendor/use-agentic/AgentProvider.d.ts +18 -0
  291. package/types/vendor/use-agentic/AgentScope.d.ts +9 -0
  292. package/types/vendor/use-agentic/AgentSession.d.ts +50 -0
  293. package/types/vendor/use-agentic/Agentic.d.ts +21 -0
  294. package/types/vendor/use-agentic/AgenticSurface.d.ts +44 -0
  295. package/types/vendor/use-agentic/httpRunner.d.ts +15 -0
  296. package/types/vendor/use-agentic/index.d.ts +13 -0
  297. package/types/vendor/use-agentic/surfaceContext.d.ts +5 -0
  298. package/types/vendor/use-agentic/types.d.ts +133 -0
  299. package/types/vendor/use-agentic/useAgent.d.ts +4 -0
  300. package/types/vendor/use-agentic/useAgentGuide.d.ts +6 -0
  301. package/types/vendor/use-agentic/useAgentResource.d.ts +7 -0
  302. package/types/vendor/use-agentic/useAgentState.d.ts +13 -0
  303. package/types/vendor/use-agentic/useAgentTool.d.ts +16 -0
  304. package/types/vendor/use-agentic.d.ts +1 -0
  305. package/types/webkit/index.d.ts +3 -0
  306. package/types/webkit/lazy.d.ts +12 -0
  307. package/types/webkit/useCsrValues.d.ts +3 -3
  308. package/types/webkit/useEscapeKey.d.ts +5 -0
  309. package/types/webkit/useFrameRuntime.d.ts +6 -1
  310. package/types/webkit/useScreenScope.d.ts +18 -0
  311. package/ui/Agent/Approval.tsx +29 -0
  312. package/ui/Agent/Bubble.tsx +74 -0
  313. package/ui/Agent/Chat.tsx +225 -0
  314. package/ui/Agent/Context.tsx +38 -0
  315. package/ui/Agent/Dock.tsx +72 -0
  316. package/ui/Agent/Guide.tsx +16 -0
  317. package/ui/Agent/Section.tsx +24 -0
  318. package/ui/Agent/StateKey.tsx +44 -0
  319. package/ui/Agent/Tool.tsx +66 -0
  320. package/ui/Agent/Transcript.tsx +33 -0
  321. package/ui/Agent/Zone.tsx +48 -0
  322. package/ui/Agent/fetchRunner.ts +30 -0
  323. package/ui/Agent/index.ts +12 -0
  324. package/ui/Agent/index_.tsx +4 -0
  325. package/ui/Agent/sessionHistory.ts +33 -0
  326. package/ui/Badge.tsx +3 -3
  327. package/ui/BottomSheet.tsx +5 -0
  328. package/ui/Button.tsx +6 -2
  329. package/ui/Constant/Doc.tsx +1 -1
  330. package/ui/CsrImage.tsx +1 -1
  331. package/ui/Data/ListContainer.tsx +1 -1
  332. package/ui/DatePicker.tsx +5 -4
  333. package/ui/Dialog/Modal.tsx +12 -15
  334. package/ui/DraggableList.tsx +3 -1
  335. package/ui/Dropdown.tsx +33 -11
  336. package/ui/Field.tsx +30 -16
  337. package/ui/Image.tsx +3 -3
  338. package/ui/Input.tsx +14 -5
  339. package/ui/Layout/BottomInset.tsx +6 -1
  340. package/ui/Load/Units.tsx +11 -2
  341. package/ui/Load/View.tsx +7 -2
  342. package/ui/Loading/ProgressBar.tsx +8 -1
  343. package/ui/Menu.tsx +7 -8
  344. package/ui/Model/EditModal.tsx +37 -2
  345. package/ui/Model/SureToRemove.tsx +2 -1
  346. package/ui/Model/index_.tsx +42 -15
  347. package/ui/ObjectId.tsx +3 -4
  348. package/ui/Pagination.tsx +3 -4
  349. package/ui/Popconfirm.tsx +8 -7
  350. package/ui/Select.tsx +6 -4
  351. package/ui/Signal/RestApi.tsx +43 -16
  352. package/ui/Signal/WebSocket.tsx +1 -1
  353. package/ui/Signal/style.ts +6 -1
  354. package/ui/Switch.tsx +2 -0
  355. package/ui/System/CSR.tsx +6 -2
  356. package/ui/System/ThemeToggle.tsx +55 -33
  357. package/ui/ToggleSelect.tsx +4 -3
  358. package/ui/Tooltip.tsx +2 -1
  359. package/ui/UiOverride/context.ts +14 -2
  360. package/ui/agentAttrs.ts +19 -0
  361. package/ui/index.ts +10 -1
  362. package/ui/overlayLayer.ts +39 -0
  363. package/ui/recipe/badgeRecipe.ts +22 -3
  364. package/ui/recipe/buttonRecipe.ts +51 -2
  365. package/ui/recipe/factory.ts +2 -2
  366. package/ui/recipe/inputRecipe.ts +18 -4
  367. package/vendor/use-agentic/AgentProvider.tsx +39 -0
  368. package/vendor/use-agentic/AgentScope.tsx +20 -0
  369. package/vendor/use-agentic/AgentSession.ts +292 -0
  370. package/vendor/use-agentic/Agentic.tsx +44 -0
  371. package/vendor/use-agentic/AgenticSurface.ts +294 -0
  372. package/vendor/use-agentic/WIRE.md +57 -0
  373. package/vendor/use-agentic/httpRunner.ts +115 -0
  374. package/vendor/use-agentic/index.ts +14 -0
  375. package/vendor/use-agentic/surfaceContext.ts +9 -0
  376. package/vendor/use-agentic/types.ts +144 -0
  377. package/vendor/use-agentic/useAgent.ts +17 -0
  378. package/vendor/use-agentic/useAgentGuide.ts +16 -0
  379. package/vendor/use-agentic/useAgentResource.ts +30 -0
  380. package/vendor/use-agentic/useAgentState.ts +61 -0
  381. package/vendor/use-agentic/useAgentTool.ts +55 -0
  382. package/webkit/bootCsr.tsx +2 -33
  383. package/webkit/index.ts +3 -0
  384. package/webkit/lazy.tsx +27 -3
  385. package/webkit/useCsrValues.ts +121 -4
  386. package/webkit/useEscapeKey.tsx +42 -0
  387. package/webkit/useFrameRuntime.ts +65 -32
  388. package/webkit/useScreenScope.tsx +49 -0
@@ -0,0 +1,38 @@
1
+ "use client";
2
+ import { AgentContext } from "akanjs/store";
3
+ import { useState } from "react";
4
+ import { AgenticSurface } from "../../vendor/use-agentic";
5
+ import { buttonRecipe } from "../recipe";
6
+
7
+ interface ContextProps {
8
+ className?: string;
9
+ }
10
+
11
+ /**
12
+ * Assembles and shows the exact context blocks a turn would carry, on demand — the one preview of "what does the
13
+ * agent see on this screen" that no amount of reading the source answers.
14
+ */
15
+ export default function Context({ className }: ContextProps) {
16
+ const [shown, setShown] = useState("");
17
+ const assemble = () => {
18
+ try {
19
+ const { guides } = AgenticSurface.shared.snapshot();
20
+ const context = AgentContext.of().blocks(AgenticSurface.shared);
21
+ setShown(JSON.stringify(guides.length ? { guides, context } : context, null, 2));
22
+ } catch (thrown) {
23
+ setShown(thrown instanceof Error ? thrown.message : String(thrown));
24
+ }
25
+ };
26
+ return (
27
+ <div className={className}>
28
+ <button className={buttonRecipe({ size: "xs" })} onClick={assemble} type="button">
29
+ Assemble
30
+ </button>
31
+ {shown ? (
32
+ <pre className="mt-2 max-h-60 overflow-auto rounded-field bg-base-100/60 p-2 text-[10px] leading-tight">
33
+ {shown}
34
+ </pre>
35
+ ) : null}
36
+ </div>
37
+ );
38
+ }
@@ -0,0 +1,72 @@
1
+ "use client";
2
+ import { cn } from "akanjs/client";
3
+ import { type AgentBridge, ensureStoreSurface, StoreRegistry } from "akanjs/store";
4
+ import { useRef, useState } from "react";
5
+ import Context from "./Context";
6
+ import Section from "./Section";
7
+ import StateKey from "./StateKey";
8
+ import Tool from "./Tool";
9
+ import Transcript from "./Transcript";
10
+
11
+ export interface DockProps {
12
+ className?: string;
13
+ /** Pass the bridge an agent is already driving so both write into one transcript. Defaults to the app's own. */
14
+ bridge?: AgentBridge;
15
+ open?: boolean;
16
+ }
17
+
18
+ /**
19
+ * The in-page surface of the agent bridge: what this page lets an agent do, what it refused, and what it has done.
20
+ *
21
+ * It drives the store directly rather than talking to a model, because a model is not the framework's to choose —
22
+ * there is no provider or key here. An app wires its own agent to `bridge.tools` / `bridge.call` and can render this
23
+ * beside it; on its own it is the way to see the catalogue a page actually publishes, which is the one thing no
24
+ * amount of reading the source answers.
25
+ */
26
+ export const Dock = ({ className, bridge, open = false }: DockProps) => {
27
+ const held = useRef<AgentBridge | null>(null);
28
+ held.current ??= bridge ?? ensureStoreSurface().bridge;
29
+ const agent = held.current;
30
+ const [ran, setRan] = useState(0);
31
+ const liveKeys = StoreRegistry.instance.liveKeys;
32
+ const stateEntries = Object.entries(agent.state).sort(([a], [b]) => {
33
+ const [liveA, liveB] = [liveKeys.has(a), liveKeys.has(b)];
34
+ if (liveA !== liveB) return liveA ? -1 : 1;
35
+ return a < b ? -1 : 1;
36
+ });
37
+ return (
38
+ <aside
39
+ data-agent-ui=""
40
+ className={cn(
41
+ "fixed right-4 bottom-4 z-50 flex max-h-[70vh] w-80 flex-col gap-2 overflow-y-auto rounded-box border border-base-content/10 bg-base-100/95 p-3 shadow-lg",
42
+ className,
43
+ )}
44
+ >
45
+ <h2 className="font-semibold text-sm">Agent</h2>
46
+ <Section count={agent.tools.length} open={open} title="Actions">
47
+ {agent.tools.map((tool) => (
48
+ <Tool bridge={agent} key={tool.name} onRun={() => setRan(ran + 1)} tool={tool} />
49
+ ))}
50
+ </Section>
51
+ <Section count={Object.keys(agent.state).length} title="State">
52
+ {stateEntries.map(([name, entry]) => (
53
+ <StateKey bridge={agent} entry={entry} key={name} live={liveKeys.has(name)} name={name} />
54
+ ))}
55
+ </Section>
56
+ <Section count={liveKeys.size} title="Context">
57
+ <Context />
58
+ </Section>
59
+ <Section count={agent.refusals.length} title="Refused">
60
+ {agent.refusals.map((refusal) => (
61
+ <div className="flex flex-col" key={refusal.key}>
62
+ <span className="truncate font-mono text-xs">{refusal.key}</span>
63
+ <span className="text-[10px] text-foreground/50">{refusal.reason}</span>
64
+ </div>
65
+ ))}
66
+ </Section>
67
+ <Section count={agent.transcript.length} open title="Transcript">
68
+ <Transcript calls={agent.transcript} />
69
+ </Section>
70
+ </aside>
71
+ );
72
+ };
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { useAgentGuide } from "../../vendor/use-agentic";
3
+
4
+ export interface GuideProps {
5
+ instructions: string;
6
+ }
7
+
8
+ /**
9
+ * Standing agent guidance scoped to a route subtree: render it from a `_layout.tsx` or a page and the text joins
10
+ * the turn's instructions while that subtree is mounted. Nesting layers naturally — each mounted Guide contributes
11
+ * its block, and navigating away withdraws it. Renders nothing.
12
+ */
13
+ export const Guide = ({ instructions }: GuideProps) => {
14
+ useAgentGuide(instructions);
15
+ return null;
16
+ };
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { cn } from "akanjs/client";
3
+ import type { ReactNode } from "react";
4
+
5
+ interface SectionProps {
6
+ className?: string;
7
+ title: string;
8
+ count: number;
9
+ children: ReactNode;
10
+ open?: boolean;
11
+ }
12
+
13
+ export default function Section({ className, title, count, children, open }: SectionProps) {
14
+ return (
15
+ <details className={cn("group rounded-box bg-muted", className)} open={open}>
16
+ <summary className="flex cursor-pointer list-none items-center gap-2 px-3 py-2 [&::-webkit-details-marker]:hidden">
17
+ <span className="font-semibold text-sm">{title}</span>
18
+ <span className="text-foreground/50 text-xs">{count}</span>
19
+ <span className="ml-auto text-foreground/40 transition-transform group-open:rotate-180">▾</span>
20
+ </summary>
21
+ <div className="flex flex-col gap-1 px-3 pb-3">{children}</div>
22
+ </details>
23
+ );
24
+ }
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { cn } from "akanjs/client";
3
+ import type { AgentBridge, SerializedStoreState } from "akanjs/store";
4
+ import { useState } from "react";
5
+
6
+ interface StateKeyProps {
7
+ className?: string;
8
+ bridge: AgentBridge;
9
+ name: string;
10
+ entry: SerializedStoreState;
11
+ live?: boolean;
12
+ }
13
+
14
+ /**
15
+ * One readable state key, read on demand rather than rendered with the rest.
16
+ *
17
+ * Reading is where masking happens, so a key that holds an object no model claims refuses here instead of in the
18
+ * catalogue — whether it is readable depends on what is in it, which the catalogue cannot know ahead of time.
19
+ */
20
+ export default function StateKey({ className, bridge, name, entry, live }: StateKeyProps) {
21
+ const [shown, setShown] = useState("");
22
+ const read = () => {
23
+ try {
24
+ setShown(JSON.stringify(bridge.read(name), null, 2));
25
+ } catch (thrown) {
26
+ setShown(thrown instanceof Error ? thrown.message : String(thrown));
27
+ }
28
+ };
29
+ return (
30
+ <div className={cn("flex flex-col gap-1", className)}>
31
+ <button className="flex items-center gap-2 text-left" type="button" onClick={read}>
32
+ <span className="truncate font-mono text-xs">{name}</span>
33
+ <span className="ml-auto shrink-0 text-[10px] text-foreground/40">
34
+ {live ? "live · " : ""}
35
+ {entry.refName ? `${entry.refName}.${entry.modelType ?? ""}` : entry.type}
36
+ {entry.derived ? " · derived" : ""}
37
+ </span>
38
+ </button>
39
+ {shown ? (
40
+ <pre className="max-h-40 overflow-auto rounded-field bg-muted p-2 text-[10px] leading-tight">{shown}</pre>
41
+ ) : null}
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,66 @@
1
+ "use client";
2
+ import { cn } from "akanjs/client";
3
+ import type { AgentBridge, AgentTool } from "akanjs/store";
4
+ import { useState } from "react";
5
+ import { buttonRecipe } from "../recipe";
6
+
7
+ const effectClass: { [key in AgentTool["effect"]]: string } = {
8
+ state: "bg-muted text-foreground/70",
9
+ query: "bg-info/15 text-info",
10
+ mutation: "bg-warning/15 text-warning",
11
+ };
12
+
13
+ interface ToolProps {
14
+ className?: string;
15
+ bridge: AgentBridge;
16
+ tool: AgentTool;
17
+ onRun: () => void;
18
+ }
19
+
20
+ /**
21
+ * One published action, with the arguments as JSON rather than as a generated form.
22
+ *
23
+ * A form per argument is what the API explorer does, and it is the wrong trade here: the point of the dock is to
24
+ * watch a call land in the running app, and every schema shape the store publishes is already legible as JSON.
25
+ */
26
+ export default function Tool({ className, bridge, tool, onRun }: ToolProps) {
27
+ const [args, setArgs] = useState("{}");
28
+ const [error, setError] = useState("");
29
+ const run = async () => {
30
+ setError("");
31
+ try {
32
+ await bridge.call(tool.name, JSON.parse(args) as Record<string, unknown>);
33
+ } catch (thrown) {
34
+ setError(thrown instanceof Error ? thrown.message : String(thrown));
35
+ }
36
+ onRun();
37
+ };
38
+ return (
39
+ <details className={cn("rounded-field bg-base-100/60 px-2 py-1", className)}>
40
+ <summary className="flex cursor-pointer list-none items-center gap-2 [&::-webkit-details-marker]:hidden">
41
+ <span className={cn("rounded-field px-1.5 py-0.5 text-[10px] uppercase", effectClass[tool.effect])}>
42
+ {tool.effect}
43
+ </span>
44
+ <span className="truncate font-mono text-xs">{tool.name}</span>
45
+ </summary>
46
+ <div className="flex flex-col gap-2 py-2">
47
+ {tool.description ? <p className="text-foreground/70 text-xs">{tool.description}</p> : null}
48
+ <pre className="overflow-x-auto rounded-field bg-muted p-2 text-[10px] leading-tight">
49
+ {JSON.stringify(tool.inputSchema.properties, null, 2)}
50
+ </pre>
51
+ <textarea
52
+ className="w-full rounded-field bg-muted p-2 font-mono text-xs"
53
+ rows={2}
54
+ value={args}
55
+ onChange={(event) => setArgs(event.target.value)}
56
+ />
57
+ {/* `buttonRecipe` rather than `Button`, which reads the app runtime through `usePage()` for labels this
58
+ developer surface does not localize anyway — the same English the API explorer uses. */}
59
+ <button className={buttonRecipe({ size: "xs" })} onClick={run} type="button">
60
+ Run
61
+ </button>
62
+ {error ? <p className="text-error text-xs">{error}</p> : null}
63
+ </div>
64
+ </details>
65
+ );
66
+ }
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { cn } from "akanjs/client";
3
+ import type { AgentCall } from "akanjs/store";
4
+
5
+ interface TranscriptProps {
6
+ className?: string;
7
+ calls: readonly AgentCall[];
8
+ }
9
+
10
+ /**
11
+ * What the agent did, newest last, so the user can check it against what they saw the page do.
12
+ *
13
+ * There is no undo here. Every model removal in this framework is soft, so one is possible in principle, but which
14
+ * writes are reversible is a per-module judgement and `local/agent-native/PLAN.md` §9-3 leaves it open.
15
+ */
16
+ export default function Transcript({ className, calls }: TranscriptProps) {
17
+ return (
18
+ <div className={cn("flex flex-col gap-1", className)}>
19
+ {calls.map((call, idx) => (
20
+ <div className="flex flex-col rounded-field bg-base-100/60 px-2 py-1" key={idx}>
21
+ <div className="flex items-baseline gap-2">
22
+ <span className="truncate font-mono text-xs">{call.name}</span>
23
+ <span className="ml-auto shrink-0 text-[10px] text-foreground/40">
24
+ {call.at.toISOString().slice(11, 19)}
25
+ </span>
26
+ </div>
27
+ <span className="truncate font-mono text-[10px] text-foreground/50">{JSON.stringify(call.args)}</span>
28
+ {call.error ? <span className="text-[10px] text-error">{call.error}</span> : null}
29
+ </div>
30
+ ))}
31
+ </div>
32
+ );
33
+ }
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { AgentContext, ensureStoreSurface } from "akanjs/store";
3
+ import { type ReactNode, useMemo, useRef } from "react";
4
+ import { AgenticSurface, type AgentRunner, AgentScope, AgentSession, SessionContext, useScopePath } from "../../vendor/use-agentic";
5
+ import { fetchRunner } from "./fetchRunner";
6
+ import { Guide } from "./Guide";
7
+ import { type PersistOption, sessionHistoryOf } from "./sessionHistory";
8
+
9
+ export interface ZoneProps {
10
+ className?: string;
11
+ /** Names the zone; the scope id and the `data-agent-zone` container both derive from it. */
12
+ id: string;
13
+ label?: string;
14
+ /** Zone-scoped guidance — a mounted Guide, so the root agent reads it too (ancestor rule), a sibling zone never does. */
15
+ instructions?: string;
16
+ runner?: AgentRunner;
17
+ maxTurns?: number;
18
+ /** Keeps this zone's transcript across reloads, keyed by the zone's scope path. */
19
+ persist?: PersistOption;
20
+ children: ReactNode;
21
+ }
22
+
23
+ /**
24
+ * A zone agent: one subtree with its own conversation over a scoped view of the same surface. Everything mounted
25
+ * inside — hook tools, `st.use` subscriptions, guides — belongs to this zone's session *and* to the root agent:
26
+ * zones are views, never walls. An `Agent.Chat` mounted inside binds to this session automatically, so two zones
27
+ * on one screen run two conversations in parallel, each seeing only its own subtree.
28
+ */
29
+ export const Zone = ({ className, id, label, instructions, runner, maxTurns, persist, children }: ZoneProps) => {
30
+ const parent = useScopePath();
31
+ const path = useMemo(() => AgenticSurface.childPath(parent, id), [parent.join("."), id]);
32
+ const held = useRef<AgentSession | null>(null);
33
+ held.current ??= new AgentSession(ensureStoreSurface().surface.view(path), runner ?? fetchRunner(), {
34
+ buildContext: (view) => AgentContext.of().blocks(view, path),
35
+ ...(maxTurns ? { maxTurns } : {}),
36
+ ...(persist ? { history: sessionHistoryOf(persist, path.join(".")) } : {}),
37
+ });
38
+ return (
39
+ <AgentScope id={id} kind="zone" label={label}>
40
+ <SessionContext.Provider value={held.current}>
41
+ <div className={className} data-agent-zone={path.join(".")}>
42
+ {instructions ? <Guide instructions={instructions} /> : null}
43
+ {children}
44
+ </div>
45
+ </SessionContext.Provider>
46
+ </AgentScope>
47
+ );
48
+ };
@@ -0,0 +1,30 @@
1
+ import { getEnv } from "akanjs/base";
2
+ import { fetch } from "akanjs/client";
3
+ import { type AgentRunner, httpRunner } from "../../vendor/use-agentic";
4
+
5
+ /**
6
+ * Runs each assistant turn against the app's own `runAgentTurn` route — service signals mount unprefixed, so the
7
+ * URL is `<serverHttpUri>/runAgentTurn` — through the shared `httpRunner`, which negotiates streaming via
8
+ * `accept`: a server that streams answers SSE and the text arrives as it is generated; one that does not answers
9
+ * the same JSON turn. The client runtime's fetch proxy is only probed for whether the endpoint exists (the util
10
+ * lib ships one) and for the signed-in JWT; cookies ride the same-origin request on their own. The endpoint is a
11
+ * stateless relay; the loop and every tool execution stay in this browser session.
12
+ */
13
+ export const fetchRunner = (options: { fetcher?: typeof globalThis.fetch } = {}): AgentRunner => ({
14
+ async *run(request) {
15
+ const client = fetch as { runAgentTurn?: unknown; instance?: { jwt?: string | null } };
16
+ if (typeof client.runAgentTurn !== "function") {
17
+ yield { type: "error", message: "No runAgentTurn endpoint is mounted on this app, so the agent cannot answer." };
18
+ return;
19
+ }
20
+ const runner = httpRunner({
21
+ url: `${getEnv().serverHttpUri}/runAgentTurn`,
22
+ headers: (): Record<string, string> => {
23
+ const jwt = client.instance?.jwt;
24
+ return jwt ? { authorization: `Bearer ${jwt}` } : {};
25
+ },
26
+ ...(options.fetcher ? { fetcher: options.fetcher } : {}),
27
+ });
28
+ yield* runner.run(request);
29
+ },
30
+ });
@@ -0,0 +1,12 @@
1
+ import { AgentScope } from "../../vendor/use-agentic";
2
+ import Context from "./Context";
3
+ import { Dock } from "./Dock";
4
+ import { Guide } from "./Guide";
5
+ import { Chat } from "./index_";
6
+ import Section from "./Section";
7
+ import StateKey from "./StateKey";
8
+ import Tool from "./Tool";
9
+ import Transcript from "./Transcript";
10
+ import { Zone } from "./Zone";
11
+
12
+ export const Agent = { Chat, Context, Dock, Guide, Scope: AgentScope, Section, StateKey, Tool, Transcript, Zone };
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ import { lazy } from "akanjs/webkit";
3
+
4
+ export const Chat = lazy(() => import("./Chat"), { ssr: false });
@@ -0,0 +1,33 @@
1
+ import { getEnv } from "akanjs/base";
2
+ import type { ChatMessage, SessionHistory } from "../../vendor/use-agentic";
3
+
4
+ export type PersistOption = boolean | { storage?: "session" | "local"; key?: string };
5
+
6
+ /**
7
+ * Maps the `persist` prop onto a `SessionHistory` over web storage. Session storage is the default on purpose:
8
+ * surviving a refresh is the whole ask, and a transcript that dies with the tab never lingers on a shared machine
9
+ * or collides across tabs. `"local"` is the explicit opt-up. The envelope is versioned so a wire change discards
10
+ * stale transcripts instead of replaying them, and only the newest messages are kept under the cap.
11
+ */
12
+ export const sessionHistoryOf = (persist: PersistOption | undefined, pathKey = ""): SessionHistory | undefined => {
13
+ if (!persist || typeof window === "undefined") return undefined;
14
+ const option = persist === true ? {} : persist;
15
+ const storage = option.storage === "local" ? window.localStorage : window.sessionStorage;
16
+ const key = option.key ?? `akan.agent.${getEnv().appName}${pathKey ? `.${pathKey}` : ""}`;
17
+ const version = 1;
18
+ const cap = 50;
19
+ return {
20
+ load: () => {
21
+ const raw = storage.getItem(key);
22
+ if (!raw) return null;
23
+ const parsed = JSON.parse(raw) as { v?: number; messages?: ChatMessage[] };
24
+ return parsed.v === version && Array.isArray(parsed.messages) ? parsed.messages : null;
25
+ },
26
+ save: (messages) => {
27
+ storage.setItem(key, JSON.stringify({ v: version, messages: messages.slice(-cap) }));
28
+ },
29
+ clear: () => {
30
+ storage.removeItem(key);
31
+ },
32
+ };
33
+ };
package/ui/Badge.tsx CHANGED
@@ -3,14 +3,14 @@ import type { HTMLAttributes } from "react";
3
3
  import { type BadgeVariants, badgeRecipe } from "./recipe";
4
4
  import { createOverridable, useUiRecipe } from "./UiOverride";
5
5
 
6
- export { badgeRecipe, type BadgeVariants };
6
+ export { type BadgeVariants, badgeRecipe };
7
7
 
8
8
  export type BadgeProps = HTMLAttributes<HTMLSpanElement> & BadgeVariants;
9
9
 
10
- const DefaultBadge = ({ className, variant, ...rest }: BadgeProps) => {
10
+ const DefaultBadge = ({ className, variant, size, outline, ...rest }: BadgeProps) => {
11
11
 
12
12
  const recipe = useUiRecipe("badge") ?? badgeRecipe;
13
- return <span className={recipe({ variant }, className)} {...rest} />;
13
+ return <span className={recipe({ variant, size, outline }, className)} {...rest} />;
14
14
  };
15
15
 
16
16
  /** Status/label pill. Route-overridable via `page/**\/_overrides.tsx` (slot `Badge`). */
@@ -3,6 +3,7 @@ import { useDrag } from "@use-gesture/react";
3
3
  import { cn } from "akanjs/client";
4
4
  import { st } from "akanjs/store";
5
5
  import { animated } from "akanjs/ui";
6
+ import { useEscapeKey } from "akanjs/webkit";
6
7
  import { forwardRef, type ReactNode, useEffect, useImperativeHandle, useRef } from "react";
7
8
  import { BiX } from "react-icons/bi";
8
9
  import { config, useSpring } from "react-spring";
@@ -54,6 +55,10 @@ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
54
55
  close: closeModal,
55
56
  }));
56
57
 
58
+ useEscapeKey(open, () => {
59
+ void closeModal();
60
+ });
61
+
57
62
  useEffect(() => {
58
63
  if (open) void openModal();
59
64
  else void closeModal();
package/ui/Button.tsx CHANGED
@@ -4,10 +4,11 @@ import { isThenable } from "akanjs/common";
4
4
  import type React from "react";
5
5
  import { type ButtonHTMLAttributes, type ComponentType, createElement, useState } from "react";
6
6
  import { AiFillCheckCircle, AiOutlineLoading3Quarters } from "react-icons/ai";
7
+ import { agentAttrs } from "./agentAttrs";
7
8
  import { type ButtonVariants, buttonRecipe } from "./recipe";
8
9
  import { useUiOverride, useUiRecipe } from "./UiOverride";
9
10
 
10
- export { buttonRecipe, type ButtonVariants };
11
+ export { type ButtonVariants, buttonRecipe };
11
12
 
12
13
  export type ButtonProps<Result> = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> &
13
14
  ButtonVariants & {
@@ -61,6 +62,8 @@ const DefaultButton = <Result = unknown>({
61
62
  className,
62
63
  variant,
63
64
  size,
65
+ shape,
66
+ outline,
64
67
  type = "button",
65
68
  loadingMode = "hold",
66
69
  showError = true,
@@ -84,11 +87,12 @@ const DefaultButton = <Result = unknown>({
84
87
  <button
85
88
  type={type}
86
89
  className={recipe(
87
- { variant, size },
90
+ { variant, size, shape, outline },
88
91
 
89
92
  cn(loadingMode === "hold" && "relative", busy && !rest.disabled && "disabled:opacity-100", className),
90
93
  )}
91
94
  {...rest}
95
+ {...agentAttrs(onClick)}
92
96
  disabled={!!rest.disabled || busy}
93
97
  onClick={(e) => {
94
98
  if (!onClick) return;
@@ -238,7 +238,7 @@ const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
238
238
  const { l } = usePage();
239
239
  return (
240
240
  <div className="overflow-x-auto rounded-xl bg-muted p-3">
241
- <table className="table">
241
+ <table className={tableClass}>
242
242
  <thead>
243
243
  <tr>
244
244
  <th>Key</th>
package/ui/CsrImage.tsx CHANGED
@@ -5,7 +5,7 @@ import type { ImgHTMLAttributes } from "react";
5
5
  type CsrImageProps = Omit<ImgHTMLAttributes<HTMLImageElement>, "alt" | "src"> & {
6
6
  src?: string;
7
7
  file?: ProtoFile | { url: string; imageSize: [number, number]; abstractData?: string | null } | null;
8
- abstractData?: string;
8
+ abstractData?: string | null;
9
9
  priority?: boolean;
10
10
  preload?: boolean;
11
11
  quality?: number;
@@ -268,7 +268,7 @@ export default function ListContainer<
268
268
  <div className={cn("m-4", className)}>
269
269
  <div className="mb-3 flex flex-wrap justify-between">
270
270
  <div className="flex pb-1">
271
- <p className="prose text-lg">
271
+ <p className="text-lg">
272
272
  {title ?? l._(`${sliceName}.modelName`)}({modelInsight.count})
273
273
  </p>
274
274
  <div className="ml-3 flex items-center">
package/ui/DatePicker.tsx CHANGED
@@ -5,6 +5,7 @@ import { lazy } from "akanjs/webkit";
5
5
  import { type FocusEvent, useEffect, useRef } from "react";
6
6
  import { AiOutlineSwapRight } from "react-icons/ai";
7
7
 
8
+ import { inputRecipe } from "./recipe";
8
9
  import { createOverridable } from "./UiOverride";
9
10
 
10
11
  const reactDatePickerPackage = "react-datepicker";
@@ -58,7 +59,7 @@ const DefaultDatePicker = ({
58
59
 
59
60
  return (
60
61
  <ReactDatePicker
61
- className={cn("input text-center", className)}
62
+ className={inputRecipe({}, ["text-center", className])}
62
63
  selected={value ? value.toDate() : new Date()}
63
64
  disabledKeyboardNavigation
64
65
  onFocus={(e: FocusEvent<HTMLInputElement>) => {
@@ -110,9 +111,9 @@ const DefaultRangePicker = ({
110
111
  onChange([value[0] ?? dayjs(), dayjs(date)]);
111
112
  };
112
113
 
113
- const pickerClassName = "m-0 input focus:outline-hidden z-50 p-3 text-center h-full w-full ";
114
+ const pickerClassName = "m-0 h-full w-full border-none bg-transparent p-3 text-center focus:outline-hidden z-50";
114
115
  return (
115
- <div className={cn("input flex h-full w-fit items-center gap-2 p-0", className)}>
116
+ <div className={inputRecipe({}, ["flex h-full w-fit items-center gap-2 p-0", className])}>
116
117
  <ReactDatePicker
117
118
  className={pickerClassName}
118
119
  selected={value[0] ? value[0].toDate() : undefined}
@@ -136,7 +137,7 @@ const DefaultRangePicker = ({
136
137
  showTimeSelect={showTime}
137
138
  timeIntervals={timeIntervals}
138
139
  filterDate={(date: Date) =>
139
- !disabledDate?.(dayjs(date)) && !!value[0] && !dayjs(date).add(1, "day").isBefore(value[0]) ? true : false
140
+ !disabledDate?.(dayjs(date)) && value[0] && !dayjs(date).add(1, "day").isBefore(value[0]) ? true : false
140
141
  }
141
142
  filterTime={(time: Date) => !!value[0] && dayjs(time).isAfter(value[0])}
142
143
  dateFormat={format}
@@ -2,11 +2,13 @@
2
2
  import { useDrag } from "@use-gesture/react";
3
3
  import { cn, usePage } from "akanjs/client";
4
4
  import { animated } from "akanjs/ui";
5
+ import { useEscapeKey } from "akanjs/webkit";
5
6
  import { type ReactNode, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
6
7
  import { createPortal } from "react-dom";
7
8
  import { BiX } from "react-icons/bi";
8
9
  import { config, useSpring } from "react-spring";
9
10
  import { buttonRecipe } from "../Button";
11
+ import { useOverlayLayerProps } from "../overlayLayer";
10
12
 
11
13
  import { DialogContext } from "./context";
12
14
 
@@ -35,6 +37,8 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
35
37
  const focusedElementRef = useRef<HTMLElement | null>(null);
36
38
  const titleId = useId();
37
39
  const contentId = useId();
40
+
41
+ const overlayLayerProps = useOverlayLayerProps();
38
42
  const [{ translate }, api] = useSpring(() => ({ translate: 1 }));
39
43
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null);
40
44
  const [isMounted, setIsMounted] = useState(open);
@@ -160,20 +164,7 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
160
164
  };
161
165
  }, [isMounted, portalElement]);
162
166
 
163
- useEffect(() => {
164
- if (!isMounted) return;
165
-
166
- const onKeyDown = (event: KeyboardEvent) => {
167
- if (event.key !== "Escape") return;
168
- event.preventDefault();
169
- requestClose();
170
- };
171
-
172
- window.addEventListener("keydown", onKeyDown);
173
- return () => {
174
- window.removeEventListener("keydown", onKeyDown);
175
- };
176
- }, [isMounted, requestClose]);
167
+ useEscapeKey(isMounted, requestClose);
177
168
 
178
169
  useEffect(() => {
179
170
  return () => {
@@ -186,17 +177,23 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
186
177
  return createPortal(
187
178
  <>
188
179
  <div
180
+ {...overlayLayerProps}
189
181
  className={cn("fixed inset-0 z-10", showBackground && "animate-fadeIn bg-black/50 backdrop-blur-md")}
190
182
  onClick={(event) => {
191
183
  if (event.target !== event.currentTarget) return;
192
184
  requestClose();
193
185
  }}
194
186
  />
195
- <div className="fixed top-1/2 left-1/2 z-10 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center">
187
+ <div
188
+ {...overlayLayerProps}
189
+ className="fixed top-1/2 left-1/2 z-10 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center"
190
+ >
196
191
  <div className="z-10">
197
192
  <animated.div
198
193
  ref={ref}
199
194
  style={{ translateY, opacity }}
195
+
196
+ className="outline-none"
200
197
  role="dialog"
201
198
  aria-modal="true"
202
199
  aria-labelledby={title ? titleId : undefined}