@lattice-php/lattice 0.2.0 → 0.4.0

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 (512) hide show
  1. package/README.md +3 -1
  2. package/dist/action/components/action-form.d.ts +2 -2
  3. package/dist/action/components/action-form.js +35 -67
  4. package/dist/action/components/action-form.js.map +1 -1
  5. package/dist/action/components/action-group.js +18 -6
  6. package/dist/action/components/action-group.js.map +1 -1
  7. package/dist/action/components/action-menu-context.d.ts +6 -0
  8. package/dist/action/components/action-menu-context.js +18 -0
  9. package/dist/action/components/action-menu-context.js.map +1 -0
  10. package/dist/action/components/action.js +20 -13
  11. package/dist/action/components/action.js.map +1 -1
  12. package/dist/action/index.js.map +1 -1
  13. package/dist/appearance/index.js +7 -2
  14. package/dist/appearance/index.js.map +1 -1
  15. package/dist/chat/components/chat-box.d.ts +3 -0
  16. package/dist/chat/components/chat-box.js +53 -0
  17. package/dist/chat/components/chat-box.js.map +1 -0
  18. package/dist/chat/components/message-list.d.ts +5 -0
  19. package/dist/chat/components/message-list.js +22 -0
  20. package/dist/chat/components/message-list.js.map +1 -0
  21. package/dist/chat/components/message.d.ts +5 -0
  22. package/dist/chat/components/message.js +20 -0
  23. package/dist/chat/components/message.js.map +1 -0
  24. package/dist/chat/components/prompt-input.d.ts +8 -0
  25. package/dist/chat/components/prompt-input.js +49 -0
  26. package/dist/chat/components/prompt-input.js.map +1 -0
  27. package/dist/chat/index.d.ts +1 -0
  28. package/dist/chat/index.js +15 -0
  29. package/dist/chat/index.js.map +1 -0
  30. package/dist/chat/parts/text.d.ts +3 -0
  31. package/dist/chat/parts/text.js +12 -0
  32. package/dist/chat/parts/text.js.map +1 -0
  33. package/dist/chat/parts/tool-call.d.ts +3 -0
  34. package/dist/chat/parts/tool-call.js +20 -0
  35. package/dist/chat/parts/tool-call.js.map +1 -0
  36. package/dist/chat/transport.d.ts +4 -0
  37. package/dist/chat/transport.js +67 -0
  38. package/dist/chat/transport.js.map +1 -0
  39. package/dist/chat/types.d.ts +39 -0
  40. package/dist/chat/use-chat.d.ts +15 -0
  41. package/dist/chat/use-chat.js +161 -0
  42. package/dist/chat/use-chat.js.map +1 -0
  43. package/dist/core/api.d.ts +25 -0
  44. package/dist/core/api.js +127 -0
  45. package/dist/core/api.js.map +1 -0
  46. package/dist/core/collapsed-context.d.ts +2 -0
  47. package/dist/core/collapsed-context.js +10 -0
  48. package/dist/core/collapsed-context.js.map +1 -0
  49. package/dist/core/column-sizing.d.ts +17 -0
  50. package/dist/core/column-sizing.js +61 -0
  51. package/dist/core/column-sizing.js.map +1 -0
  52. package/dist/core/components/badge.js +3 -3
  53. package/dist/core/components/badge.js.map +1 -1
  54. package/dist/core/components/button.d.ts +1 -1
  55. package/dist/core/components/button.js +19 -15
  56. package/dist/core/components/button.js.map +1 -1
  57. package/dist/core/components/card.js +1 -1
  58. package/dist/core/components/card.js.map +1 -1
  59. package/dist/core/components/chart.d.ts +3 -0
  60. package/dist/core/components/chart.js +175 -0
  61. package/dist/core/components/chart.js.map +1 -0
  62. package/dist/{form/components/base → core/components}/checkbox.js +4 -4
  63. package/dist/core/components/checkbox.js.map +1 -0
  64. package/dist/core/components/combobox.d.ts +33 -0
  65. package/dist/core/components/combobox.js +99 -0
  66. package/dist/core/components/combobox.js.map +1 -0
  67. package/dist/core/components/confirm-dialog.js +6 -12
  68. package/dist/core/components/confirm-dialog.js.map +1 -1
  69. package/dist/core/components/control.d.ts +13 -0
  70. package/dist/core/components/control.js +27 -0
  71. package/dist/core/components/control.js.map +1 -0
  72. package/dist/core/components/dialog.d.ts +19 -0
  73. package/dist/core/components/dialog.js +76 -0
  74. package/dist/core/components/dialog.js.map +1 -0
  75. package/dist/core/components/dropdown-menu.d.ts +14 -0
  76. package/dist/core/components/dropdown-menu.js +42 -0
  77. package/dist/core/components/dropdown-menu.js.map +1 -0
  78. package/dist/core/components/floating-panel.d.ts +3 -0
  79. package/dist/core/components/floating-panel.js +65 -0
  80. package/dist/core/components/floating-panel.js.map +1 -0
  81. package/dist/core/components/fragment.js +25 -13
  82. package/dist/core/components/fragment.js.map +1 -1
  83. package/dist/core/components/grid.js.map +1 -1
  84. package/dist/core/components/heading.js +1 -1
  85. package/dist/core/components/heading.js.map +1 -1
  86. package/dist/core/components/icon.js +1 -0
  87. package/dist/core/components/icon.js.map +1 -1
  88. package/dist/core/components/index.js +8 -1
  89. package/dist/core/components/index.js.map +1 -1
  90. package/dist/core/components/info-tooltip.d.ts +3 -0
  91. package/dist/core/components/info-tooltip.js +26 -0
  92. package/dist/core/components/info-tooltip.js.map +1 -0
  93. package/dist/core/components/link.js +12 -6
  94. package/dist/core/components/link.js.map +1 -1
  95. package/dist/core/components/modal.js +9 -31
  96. package/dist/core/components/modal.js.map +1 -1
  97. package/dist/core/components/popover.d.ts +8 -0
  98. package/dist/core/components/popover.js +37 -0
  99. package/dist/core/components/popover.js.map +1 -0
  100. package/dist/core/components/raw-block.d.ts +3 -0
  101. package/dist/core/components/raw-block.js +10 -0
  102. package/dist/core/components/raw-block.js.map +1 -0
  103. package/dist/core/components/section.js +8 -12
  104. package/dist/core/components/section.js.map +1 -1
  105. package/dist/core/components/segmented-control.js.map +1 -1
  106. package/dist/core/components/segmented-pills.js +1 -1
  107. package/dist/core/components/segmented-pills.js.map +1 -1
  108. package/dist/core/components/skeleton.d.ts +3 -0
  109. package/dist/core/components/skeleton.js +16 -0
  110. package/dist/core/components/skeleton.js.map +1 -0
  111. package/dist/core/components/spinner.js.map +1 -1
  112. package/dist/core/components/stack.js +25 -8
  113. package/dist/core/components/stack.js.map +1 -1
  114. package/dist/core/components/tabs.js +1 -1
  115. package/dist/core/components/tabs.js.map +1 -1
  116. package/dist/core/components/text.js +17 -1
  117. package/dist/core/components/text.js.map +1 -1
  118. package/dist/core/headers.d.ts +1 -0
  119. package/dist/core/headers.js +14 -0
  120. package/dist/core/headers.js.map +1 -0
  121. package/dist/core/registry-context.d.ts +21 -0
  122. package/dist/core/registry-context.js +40 -0
  123. package/dist/core/registry-context.js.map +1 -0
  124. package/dist/core/registry.d.ts +4 -1
  125. package/dist/core/registry.js +10 -1
  126. package/dist/core/registry.js.map +1 -1
  127. package/dist/core/renderer.d.ts +8 -14
  128. package/dist/core/renderer.js +17 -27
  129. package/dist/core/renderer.js.map +1 -1
  130. package/dist/core/test-id.d.ts +8 -0
  131. package/dist/core/test-id.js +21 -0
  132. package/dist/core/test-id.js.map +1 -0
  133. package/dist/core/types.d.ts +25 -9
  134. package/dist/core/use-column-resizing.d.ts +27 -0
  135. package/dist/core/use-column-resizing.js +228 -0
  136. package/dist/core/use-column-resizing.js.map +1 -0
  137. package/dist/effects/dispatch.d.ts +20 -0
  138. package/dist/effects/dispatch.js +39 -0
  139. package/dist/effects/dispatch.js.map +1 -0
  140. package/dist/effects/registry.d.ts +38 -0
  141. package/dist/effects/registry.js +51 -0
  142. package/dist/effects/registry.js.map +1 -0
  143. package/dist/effects/use-effect-dispatcher.d.ts +8 -0
  144. package/dist/effects/use-effect-dispatcher.js +20 -0
  145. package/dist/effects/use-effect-dispatcher.js.map +1 -0
  146. package/dist/effects/use-flash-effects.d.ts +5 -0
  147. package/dist/effects/use-flash-effects.js +22 -0
  148. package/dist/effects/use-flash-effects.js.map +1 -0
  149. package/dist/events/event-bridge.d.ts +3 -7
  150. package/dist/events/event-bridge.js +17 -47
  151. package/dist/events/event-bridge.js.map +1 -1
  152. package/dist/events/event-names.d.ts +3 -1
  153. package/dist/events/event-names.js +3 -1
  154. package/dist/events/event-names.js.map +1 -1
  155. package/dist/form/components/base/affix-group.d.ts +17 -0
  156. package/dist/form/components/base/affix-group.js +49 -0
  157. package/dist/form/components/base/affix-group.js.map +1 -0
  158. package/dist/form/components/base/field.d.ts +2 -1
  159. package/dist/form/components/base/field.js +17 -2
  160. package/dist/form/components/base/field.js.map +1 -1
  161. package/dist/form/components/base/input-error.js +1 -1
  162. package/dist/form/components/base/input-error.js.map +1 -1
  163. package/dist/form/components/base/input.js +2 -1
  164. package/dist/form/components/base/input.js.map +1 -1
  165. package/dist/form/components/base/label.js +1 -1
  166. package/dist/form/components/base/label.js.map +1 -1
  167. package/dist/form/components/base/password-input.js.map +1 -1
  168. package/dist/form/components/base/submit-button.js +4 -2
  169. package/dist/form/components/base/submit-button.js.map +1 -1
  170. package/dist/form/components/base/textarea.js +2 -1
  171. package/dist/form/components/base/textarea.js.map +1 -1
  172. package/dist/form/components/conditions.js.map +1 -1
  173. package/dist/form/components/context.d.ts +1 -0
  174. package/dist/form/components/context.js +1 -0
  175. package/dist/form/components/context.js.map +1 -1
  176. package/dist/form/components/field-props.d.ts +4 -0
  177. package/dist/form/components/field-props.js.map +1 -1
  178. package/dist/form/components/field-scope.d.ts +21 -0
  179. package/dist/form/components/field-scope.js +54 -0
  180. package/dist/form/components/field-scope.js.map +1 -0
  181. package/dist/form/components/fields/block-add-menu.d.ts +9 -0
  182. package/dist/form/components/fields/block-add-menu.js +27 -0
  183. package/dist/form/components/fields/block-add-menu.js.map +1 -0
  184. package/dist/form/components/fields/builder.d.ts +2 -0
  185. package/dist/form/components/fields/builder.js +124 -0
  186. package/dist/form/components/fields/builder.js.map +1 -0
  187. package/dist/form/components/fields/checkbox.d.ts +1 -1
  188. package/dist/form/components/fields/checkbox.js +14 -11
  189. package/dist/form/components/fields/checkbox.js.map +1 -1
  190. package/dist/form/components/fields/choice.d.ts +1 -1
  191. package/dist/form/components/fields/choice.js +5 -4
  192. package/dist/form/components/fields/choice.js.map +1 -1
  193. package/dist/form/components/fields/date-input.d.ts +1 -1
  194. package/dist/form/components/fields/date-input.js +2 -1
  195. package/dist/form/components/fields/date-input.js.map +1 -1
  196. package/dist/form/components/fields/file-upload.d.ts +2 -0
  197. package/dist/form/components/fields/file-upload.js +282 -0
  198. package/dist/form/components/fields/file-upload.js.map +1 -0
  199. package/dist/form/components/fields/hidden-input.d.ts +1 -1
  200. package/dist/form/components/fields/hidden-input.js +11 -5
  201. package/dist/form/components/fields/hidden-input.js.map +1 -1
  202. package/dist/form/components/fields/number-input.d.ts +1 -1
  203. package/dist/form/components/fields/number-input.js +23 -15
  204. package/dist/form/components/fields/number-input.js.map +1 -1
  205. package/dist/form/components/fields/password-input.d.ts +1 -1
  206. package/dist/form/components/fields/password-input.js +42 -27
  207. package/dist/form/components/fields/password-input.js.map +1 -1
  208. package/dist/form/components/fields/repeater-rows.d.ts +12 -0
  209. package/dist/form/components/fields/repeater-rows.js +46 -0
  210. package/dist/form/components/fields/repeater-rows.js.map +1 -0
  211. package/dist/form/components/fields/repeater.d.ts +2 -0
  212. package/dist/form/components/fields/repeater.js +97 -0
  213. package/dist/form/components/fields/repeater.js.map +1 -0
  214. package/dist/form/components/fields/rich-editor.d.ts +1 -1
  215. package/dist/form/components/fields/rich-editor.js +39 -11
  216. package/dist/form/components/fields/rich-editor.js.map +1 -1
  217. package/dist/form/components/fields/row-action-menu.d.ts +17 -0
  218. package/dist/form/components/fields/row-action-menu.js +61 -0
  219. package/dist/form/components/fields/row-action-menu.js.map +1 -0
  220. package/dist/form/components/fields/row-actions.d.ts +10 -0
  221. package/dist/form/components/fields/row-actions.js +45 -0
  222. package/dist/form/components/fields/row-actions.js.map +1 -0
  223. package/dist/form/components/fields/row-item.d.ts +27 -0
  224. package/dist/form/components/fields/row-item.js +69 -0
  225. package/dist/form/components/fields/row-item.js.map +1 -0
  226. package/dist/form/components/fields/select.d.ts +1 -1
  227. package/dist/form/components/fields/select.js +69 -104
  228. package/dist/form/components/fields/select.js.map +1 -1
  229. package/dist/form/components/fields/simple-field.js +1 -0
  230. package/dist/form/components/fields/simple-field.js.map +1 -1
  231. package/dist/form/components/fields/table-rows.d.ts +32 -0
  232. package/dist/form/components/fields/table-rows.js +188 -0
  233. package/dist/form/components/fields/table-rows.js.map +1 -0
  234. package/dist/form/components/fields/text-input.d.ts +1 -1
  235. package/dist/form/components/fields/text-input.js +19 -12
  236. package/dist/form/components/fields/text-input.js.map +1 -1
  237. package/dist/form/components/fields/textarea.d.ts +1 -1
  238. package/dist/form/components/fields/textarea.js +2 -1
  239. package/dist/form/components/fields/textarea.js.map +1 -1
  240. package/dist/form/components/fields/use-flip-reorder.d.ts +6 -0
  241. package/dist/form/components/fields/use-flip-reorder.js +51 -0
  242. package/dist/form/components/fields/use-flip-reorder.js.map +1 -0
  243. package/dist/form/components/fields/use-row-collection.d.ts +11 -0
  244. package/dist/form/components/fields/use-row-collection.js +44 -0
  245. package/dist/form/components/fields/use-row-collection.js.map +1 -0
  246. package/dist/form/components/form-path.d.ts +5 -0
  247. package/dist/form/components/form-path.js +40 -0
  248. package/dist/form/components/form-path.js.map +1 -0
  249. package/dist/form/components/form-transport.d.ts +3 -4
  250. package/dist/form/components/form-transport.js +17 -18
  251. package/dist/form/components/form-transport.js.map +1 -1
  252. package/dist/form/components/form.js +24 -18
  253. package/dist/form/components/form.js.map +1 -1
  254. package/dist/form/components/index.d.ts +3 -0
  255. package/dist/form/components/index.js +4 -1
  256. package/dist/form/components/override-keys.d.ts +2 -0
  257. package/dist/form/components/override-keys.js +12 -0
  258. package/dist/form/components/override-keys.js.map +1 -0
  259. package/dist/form/components/prefill-context.d.ts +5 -0
  260. package/dist/form/components/prefill-context.js +11 -0
  261. package/dist/form/components/prefill-context.js.map +1 -0
  262. package/dist/form/components/prefill-targets.d.ts +17 -0
  263. package/dist/form/components/prefill-targets.js +73 -0
  264. package/dist/form/components/prefill-targets.js.map +1 -0
  265. package/dist/form/components/resolved-nodes.js +4 -1
  266. package/dist/form/components/resolved-nodes.js.map +1 -1
  267. package/dist/form/components/row-layout-context.d.ts +5 -0
  268. package/dist/form/components/row-layout-context.js +18 -0
  269. package/dist/form/components/row-layout-context.js.map +1 -0
  270. package/dist/form/components/use-controlled-field.d.ts +2 -0
  271. package/dist/form/components/use-controlled-field.js +13 -5
  272. package/dist/form/components/use-controlled-field.js.map +1 -1
  273. package/dist/form/components/use-dependent-field.js +7 -1
  274. package/dist/form/components/use-dependent-field.js.map +1 -1
  275. package/dist/form/components/use-field-commit.d.ts +4 -0
  276. package/dist/form/components/use-field-commit.js +21 -7
  277. package/dist/form/components/use-field-commit.js.map +1 -1
  278. package/dist/form/components/use-form-resolver.d.ts +6 -1
  279. package/dist/form/components/use-form-resolver.js +50 -5
  280. package/dist/form/components/use-form-resolver.js.map +1 -1
  281. package/dist/form/components/use-seed-default.js +8 -3
  282. package/dist/form/components/use-seed-default.js.map +1 -1
  283. package/dist/form/components/values.js +20 -5
  284. package/dist/form/components/values.js.map +1 -1
  285. package/dist/form/index.js +13 -10
  286. package/dist/form/index.js.map +1 -1
  287. package/dist/form/skeleton.js +5 -4
  288. package/dist/form/skeleton.js.map +1 -1
  289. package/dist/i18n/backend.d.ts +7 -5
  290. package/dist/i18n/backend.js +23 -8
  291. package/dist/i18n/backend.js.map +1 -1
  292. package/dist/i18n/config.d.ts +6 -0
  293. package/dist/i18n/config.js +36 -0
  294. package/dist/i18n/config.js.map +1 -0
  295. package/dist/i18n/index.d.ts +7 -1
  296. package/dist/i18n/index.js +5 -1
  297. package/dist/i18n/instance.d.ts +27 -0
  298. package/dist/i18n/instance.js +63 -16
  299. package/dist/i18n/instance.js.map +1 -1
  300. package/dist/i18n/locale-reload.d.ts +3 -0
  301. package/dist/i18n/locale-reload.js +17 -0
  302. package/dist/i18n/locale-reload.js.map +1 -0
  303. package/dist/i18n/locale-switcher.d.ts +21 -0
  304. package/dist/i18n/locale-switcher.js +25 -0
  305. package/dist/i18n/locale-switcher.js.map +1 -0
  306. package/dist/i18n/locale.d.ts +9 -0
  307. package/dist/i18n/locale.js +93 -0
  308. package/dist/i18n/locale.js.map +1 -0
  309. package/dist/i18n/page-props.d.ts +3 -0
  310. package/dist/i18n/page-props.js +24 -0
  311. package/dist/i18n/page-props.js.map +1 -0
  312. package/dist/i18n/translatable.d.ts +4 -0
  313. package/dist/i18n/translatable.js +24 -0
  314. package/dist/i18n/translatable.js.map +1 -0
  315. package/dist/index.d.ts +20 -8
  316. package/dist/index.js +19 -7
  317. package/dist/inertia.d.ts +2 -1
  318. package/dist/inertia.js +9 -2
  319. package/dist/inertia.js.map +1 -1
  320. package/dist/lattice.css +148 -22
  321. package/dist/layout/breadcrumbs.d.ts +3 -0
  322. package/dist/layout/breadcrumbs.js +34 -0
  323. package/dist/layout/breadcrumbs.js.map +1 -0
  324. package/dist/layout/callouts.d.ts +3 -0
  325. package/dist/layout/callouts.js +67 -0
  326. package/dist/layout/callouts.js.map +1 -0
  327. package/dist/layout/components.js +9 -1
  328. package/dist/layout/components.js.map +1 -1
  329. package/dist/layout/context.d.ts +2 -10
  330. package/dist/layout/context.js +3 -14
  331. package/dist/layout/context.js.map +1 -1
  332. package/dist/layout/dropdown.d.ts +3 -0
  333. package/dist/layout/dropdown.js +24 -0
  334. package/dist/layout/dropdown.js.map +1 -0
  335. package/dist/layout/index.d.ts +2 -1
  336. package/dist/layout/index.js +3 -1
  337. package/dist/layout/menu-item.js +54 -62
  338. package/dist/layout/menu-item.js.map +1 -1
  339. package/dist/layout/menu.js.map +1 -1
  340. package/dist/layout/outlet.js +2 -2
  341. package/dist/layout/outlet.js.map +1 -1
  342. package/dist/layout/popover.d.ts +17 -0
  343. package/dist/layout/popover.js +46 -0
  344. package/dist/layout/popover.js.map +1 -0
  345. package/dist/layout/schema-layout.js +2 -9
  346. package/dist/layout/schema-layout.js.map +1 -1
  347. package/dist/layout/sidebar.js +4 -4
  348. package/dist/layout/sidebar.js.map +1 -1
  349. package/dist/layout/topbar.d.ts +3 -0
  350. package/dist/layout/topbar.js +15 -0
  351. package/dist/layout/topbar.js.map +1 -0
  352. package/dist/page.js +16 -17
  353. package/dist/page.js.map +1 -1
  354. package/dist/provider.d.ts +2 -4
  355. package/dist/provider.js +5 -9
  356. package/dist/provider.js.map +1 -1
  357. package/dist/realtime/build-effects.d.ts +4 -0
  358. package/dist/realtime/build-effects.js +23 -0
  359. package/dist/realtime/build-effects.js.map +1 -0
  360. package/dist/realtime/listeners.d.ts +8 -0
  361. package/dist/realtime/listeners.js +31 -0
  362. package/dist/realtime/listeners.js.map +1 -0
  363. package/dist/realtime/subscriptions.d.ts +4 -0
  364. package/dist/realtime/subscriptions.js +45 -0
  365. package/dist/realtime/subscriptions.js.map +1 -0
  366. package/dist/registry.js +3 -1
  367. package/dist/registry.js.map +1 -1
  368. package/dist/remote/components/chat-box.d.ts +3 -0
  369. package/dist/remote/components/chat-box.js +65 -0
  370. package/dist/remote/components/chat-box.js.map +1 -0
  371. package/dist/remote/components/data-list.d.ts +10 -0
  372. package/dist/remote/components/data-list.js +106 -0
  373. package/dist/remote/components/data-list.js.map +1 -0
  374. package/dist/remote/index.d.ts +1 -0
  375. package/dist/remote/index.js +15 -0
  376. package/dist/remote/index.js.map +1 -0
  377. package/dist/svg-sprite-client/index.d.ts +1 -0
  378. package/dist/svg-sprite-client/index.js +0 -0
  379. package/dist/svg-sprite-client.d.ts +1 -0
  380. package/dist/table/align.d.ts +4 -0
  381. package/dist/table/align.js +23 -0
  382. package/dist/table/align.js.map +1 -0
  383. package/dist/table/bulk.js +1 -1
  384. package/dist/table/bulk.js.map +1 -1
  385. package/dist/table/components/bulk-bar.js +8 -5
  386. package/dist/table/components/bulk-bar.js.map +1 -1
  387. package/dist/table/components/cells/badge-cell.d.ts +2 -5
  388. package/dist/table/components/cells/badge-cell.js +3 -3
  389. package/dist/table/components/cells/badge-cell.js.map +1 -1
  390. package/dist/table/components/cells/boolean-cell.d.ts +3 -0
  391. package/dist/table/components/cells/boolean-cell.js +23 -0
  392. package/dist/table/components/cells/boolean-cell.js.map +1 -0
  393. package/dist/table/components/cells/icon-cell.d.ts +2 -5
  394. package/dist/table/components/cells/icon-cell.js +4 -5
  395. package/dist/table/components/cells/icon-cell.js.map +1 -1
  396. package/dist/table/components/cells/image-cell.d.ts +2 -5
  397. package/dist/table/components/cells/image-cell.js +4 -5
  398. package/dist/table/components/cells/image-cell.js.map +1 -1
  399. package/dist/table/components/cells/money-cell.d.ts +2 -0
  400. package/dist/table/components/cells/money-cell.js +28 -0
  401. package/dist/table/components/cells/money-cell.js.map +1 -0
  402. package/dist/table/components/cells/number-cell.d.ts +2 -0
  403. package/dist/table/components/cells/number-cell.js +25 -0
  404. package/dist/table/components/cells/number-cell.js.map +1 -0
  405. package/dist/table/components/cells/numeric.d.ts +2 -0
  406. package/dist/table/components/cells/numeric.js +10 -0
  407. package/dist/table/components/cells/numeric.js.map +1 -0
  408. package/dist/table/components/cells/stack-cell.d.ts +3 -0
  409. package/dist/table/components/cells/stack-cell.js +17 -0
  410. package/dist/table/components/cells/stack-cell.js.map +1 -0
  411. package/dist/table/components/cells/text-cell.d.ts +2 -6
  412. package/dist/table/components/cells/text-cell.js +6 -7
  413. package/dist/table/components/cells/text-cell.js.map +1 -1
  414. package/dist/table/components/column-filter-control.d.ts +4 -1
  415. package/dist/table/components/column-filter-control.js +82 -11
  416. package/dist/table/components/column-filter-control.js.map +1 -1
  417. package/dist/table/components/column-header.d.ts +3 -1
  418. package/dist/table/components/column-header.js +11 -8
  419. package/dist/table/components/column-header.js.map +1 -1
  420. package/dist/table/components/filter-bar.d.ts +16 -0
  421. package/dist/table/components/filter-bar.js +104 -0
  422. package/dist/table/components/filter-bar.js.map +1 -0
  423. package/dist/table/components/filter-controls.d.ts +18 -0
  424. package/dist/table/components/filter-controls.js +256 -0
  425. package/dist/table/components/filter-controls.js.map +1 -0
  426. package/dist/table/components/filter-stack-bar.js +4 -3
  427. package/dist/table/components/filter-stack-bar.js.map +1 -1
  428. package/dist/table/components/filter-value-input.d.ts +1 -0
  429. package/dist/table/components/filter-value-input.js +7 -6
  430. package/dist/table/components/filter-value-input.js.map +1 -1
  431. package/dist/table/components/pagination.js +1 -1
  432. package/dist/table/components/pagination.js.map +1 -1
  433. package/dist/table/components/sort-bar.js +1 -1
  434. package/dist/table/components/sort-bar.js.map +1 -1
  435. package/dist/table/components/table-action-node.js.map +1 -1
  436. package/dist/table/components/table-cell.d.ts +1 -1
  437. package/dist/table/components/table-cell.js +18 -28
  438. package/dist/table/components/table-cell.js.map +1 -1
  439. package/dist/table/components/table.js +200 -152
  440. package/dist/table/components/table.js.map +1 -1
  441. package/dist/table/filter-values.d.ts +13 -0
  442. package/dist/table/filter-values.js +30 -0
  443. package/dist/table/filter-values.js.map +1 -0
  444. package/dist/table/format.js.map +1 -1
  445. package/dist/table/index.js.map +1 -1
  446. package/dist/table/payload.js +24 -3
  447. package/dist/table/payload.js.map +1 -1
  448. package/dist/table/query.d.ts +10 -1
  449. package/dist/table/query.js +60 -6
  450. package/dist/table/query.js.map +1 -1
  451. package/dist/table/registry.d.ts +19 -0
  452. package/dist/table/registry.js +14 -0
  453. package/dist/table/registry.js.map +1 -0
  454. package/dist/table/types.d.ts +9 -19
  455. package/dist/table/use-table.d.ts +8 -2
  456. package/dist/table/use-table.js +61 -7
  457. package/dist/table/use-table.js.map +1 -1
  458. package/dist/toast/callout.d.ts +6 -0
  459. package/dist/toast/callout.js +31 -0
  460. package/dist/toast/callout.js.map +1 -0
  461. package/dist/toast/index.d.ts +4 -0
  462. package/dist/toast/index.js +3 -1
  463. package/dist/toast/toast.d.ts +14 -0
  464. package/dist/toast/toast.js +54 -0
  465. package/dist/toast/toast.js.map +1 -0
  466. package/dist/toast/toaster.js +14 -77
  467. package/dist/toast/toaster.js.map +1 -1
  468. package/dist/toast/variant-styles.d.ts +6 -0
  469. package/dist/toast/variant-styles.js +37 -0
  470. package/dist/toast/variant-styles.js.map +1 -0
  471. package/dist/types/generated.d.ts +547 -103
  472. package/dist/types/vite-env.d.ts +1 -0
  473. package/dist/vite.d.ts +25 -0
  474. package/dist/vite.js +72 -0
  475. package/dist/vite.js.map +1 -0
  476. package/package.json +130 -13
  477. package/resources/icons/rotate-ccw.svg +16 -0
  478. package/dist/_virtual/_rolldown/runtime.js +0 -8
  479. package/dist/action/effects.d.ts +0 -11
  480. package/dist/action/effects.js +0 -44
  481. package/dist/action/effects.js.map +0 -1
  482. package/dist/form/components/base/checkbox.js.map +0 -1
  483. package/dist/node_modules/i18next/dist/esm/i18next.js +0 -1982
  484. package/dist/node_modules/i18next/dist/esm/i18next.js.map +0 -1
  485. package/dist/node_modules/i18next-http-backend/esm/index.js +0 -352
  486. package/dist/node_modules/i18next-http-backend/esm/index.js.map +0 -1
  487. package/dist/node_modules/react-i18next/dist/es/context.js +0 -23
  488. package/dist/node_modules/react-i18next/dist/es/context.js.map +0 -1
  489. package/dist/node_modules/react-i18next/dist/es/defaults.js +0 -29
  490. package/dist/node_modules/react-i18next/dist/es/defaults.js.map +0 -1
  491. package/dist/node_modules/react-i18next/dist/es/i18nInstance.js +0 -10
  492. package/dist/node_modules/react-i18next/dist/es/i18nInstance.js.map +0 -1
  493. package/dist/node_modules/react-i18next/dist/es/initReactI18next.js +0 -14
  494. package/dist/node_modules/react-i18next/dist/es/initReactI18next.js.map +0 -1
  495. package/dist/node_modules/react-i18next/dist/es/unescape.js +0 -30
  496. package/dist/node_modules/react-i18next/dist/es/unescape.js.map +0 -1
  497. package/dist/node_modules/react-i18next/dist/es/useTranslation.js +0 -157
  498. package/dist/node_modules/react-i18next/dist/es/useTranslation.js.map +0 -1
  499. package/dist/node_modules/react-i18next/dist/es/utils.js +0 -58
  500. package/dist/node_modules/react-i18next/dist/es/utils.js.map +0 -1
  501. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js +0 -70
  502. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js.map +0 -1
  503. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js +0 -61
  504. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js.map +0 -1
  505. package/dist/node_modules/use-sync-external-store/shim/index.js +0 -13
  506. package/dist/node_modules/use-sync-external-store/shim/index.js.map +0 -1
  507. package/dist/table/column-registry.d.ts +0 -9
  508. package/dist/test-support.d.ts +0 -14
  509. package/dist/test-support.js +0 -14
  510. package/dist/test-support.js.map +0 -1
  511. /package/dist/{table/column-registry.js → chat/types.js} +0 -0
  512. /package/dist/{form/components/base → core/components}/checkbox.d.ts +0 -0
@@ -0,0 +1,53 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { testIdentity } from "../../core/test-id.js";
3
+ import { useT } from "../../i18n/instance.js";
4
+ import { apiFetch } from "../../core/api.js";
5
+ import { useChat } from "../use-chat.js";
6
+ import { MessageList } from "./message-list.js";
7
+ import { PromptInput } from "./prompt-input.js";
8
+ import { useCallback, useEffect, useRef } from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ //#region resources/js/chat/components/chat-box.tsx
11
+ var ChatBox = ({ node }) => {
12
+ const { streamEndpoint, historyEndpoint, placeholder, title, fill } = node.props;
13
+ const { t } = useT("lattice");
14
+ const { messages, status, sendMessage, setMessages } = useChat({ endpoint: streamEndpoint ?? "" });
15
+ const seededRef = useRef(false);
16
+ const seedHistory = useCallback(async () => {
17
+ if (seededRef.current || !historyEndpoint) return;
18
+ seededRef.current = true;
19
+ const response = await apiFetch(historyEndpoint, { throwOnError: false });
20
+ if (!response.ok) return;
21
+ setMessages((await response.json()).messages);
22
+ }, [historyEndpoint, setMessages]);
23
+ useEffect(() => {
24
+ seedHistory();
25
+ }, [seedHistory]);
26
+ const busy = status === "submitted" || status === "streaming";
27
+ return /* @__PURE__ */ jsxs("div", {
28
+ className: cn("flex flex-col overflow-hidden border border-lt-border bg-lt-bg", fill ? "sticky top-0 h-full min-h-[28rem] w-full" : "h-[28rem] w-80 rounded-lt shadow-lt-lg"),
29
+ "data-test": testIdentity("chat-box"),
30
+ children: [
31
+ /* @__PURE__ */ jsx("div", {
32
+ className: "flex items-center border-b border-lt-border px-3 py-2",
33
+ children: /* @__PURE__ */ jsx("span", {
34
+ className: "text-sm font-medium text-lt-fg",
35
+ children: title ?? t("chat.title", "Chat")
36
+ })
37
+ }),
38
+ /* @__PURE__ */ jsx("div", {
39
+ className: "flex-1 overflow-y-auto",
40
+ children: /* @__PURE__ */ jsx(MessageList, { messages })
41
+ }),
42
+ /* @__PURE__ */ jsx(PromptInput, {
43
+ disabled: busy,
44
+ onSubmit: sendMessage,
45
+ placeholder: placeholder ?? void 0
46
+ })
47
+ ]
48
+ });
49
+ };
50
+ //#endregion
51
+ export { ChatBox, ChatBox as default };
52
+
53
+ //# sourceMappingURL=chat-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-box.js","names":[],"sources":["../../../resources/js/chat/components/chat-box.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { useChat } from \"../use-chat\";\nimport type { ChatMessage } from \"../types\";\nimport { MessageList } from \"./message-list\";\nimport { PromptInput } from \"./prompt-input\";\n\ntype ChatHistoryResponse = { messages: ChatMessage[] };\n\nexport const ChatBox: RendererComponent<\"chat.box\"> = ({ node }) => {\n const { streamEndpoint, historyEndpoint, placeholder, title, fill } = node.props;\n const { t } = useT(\"lattice\");\n const { messages, status, sendMessage, setMessages } = useChat({\n endpoint: streamEndpoint ?? \"\",\n });\n\n const seededRef = useRef(false);\n\n const seedHistory = useCallback(async (): Promise<void> => {\n if (seededRef.current || !historyEndpoint) {\n return;\n }\n\n seededRef.current = true;\n\n const response = await apiFetch(historyEndpoint, { throwOnError: false });\n\n if (!response.ok) {\n return;\n }\n\n const payload = (await response.json()) as ChatHistoryResponse;\n setMessages(payload.messages);\n }, [historyEndpoint, setMessages]);\n\n useEffect(() => {\n void seedHistory();\n }, [seedHistory]);\n\n const busy = status === \"submitted\" || status === \"streaming\";\n\n return (\n <div\n className={cn(\n \"flex flex-col overflow-hidden border border-lt-border bg-lt-bg\",\n fill\n ? \"sticky top-0 h-full min-h-[28rem] w-full\"\n : \"h-[28rem] w-80 rounded-lt shadow-lt-lg\",\n )}\n data-test={testIdentity(\"chat-box\")}\n >\n <div className=\"flex items-center border-b border-lt-border px-3 py-2\">\n <span className=\"text-sm font-medium text-lt-fg\">{title ?? t(\"chat.title\", \"Chat\")}</span>\n </div>\n <div className=\"flex-1 overflow-y-auto\">\n <MessageList messages={messages} />\n </div>\n <PromptInput disabled={busy} onSubmit={sendMessage} placeholder={placeholder ?? undefined} />\n </div>\n );\n};\n\nexport default ChatBox;\n"],"mappings":";;;;;;;;;;AAaA,IAAa,WAA0C,EAAE,WAAW;CAClE,MAAM,EAAE,gBAAgB,iBAAiB,aAAa,OAAO,SAAS,KAAK;CAC3E,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,EAAE,UAAU,QAAQ,aAAa,gBAAgB,QAAQ,EAC7D,UAAU,kBAAkB,GAC9B,CAAC;CAED,MAAM,YAAY,OAAO,KAAK;CAE9B,MAAM,cAAc,YAAY,YAA2B;EACzD,IAAI,UAAU,WAAW,CAAC,iBACxB;EAGF,UAAU,UAAU;EAEpB,MAAM,WAAW,MAAM,SAAS,iBAAiB,EAAE,cAAc,MAAM,CAAC;EAExE,IAAI,CAAC,SAAS,IACZ;EAIF,aAAY,MADW,SAAS,KAAK,GACjB,QAAQ;CAC9B,GAAG,CAAC,iBAAiB,WAAW,CAAC;CAEjC,gBAAgB;EACd,YAAiB;CACnB,GAAG,CAAC,WAAW,CAAC;CAEhB,MAAM,OAAO,WAAW,eAAe,WAAW;CAElD,OACE,qBAAC,OAAD;EACE,WAAW,GACT,kEACA,OACI,6CACA,wCACN;EACA,aAAW,aAAa,UAAU;YAPpC;GASE,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,QAAD;KAAM,WAAU;eAAkC,SAAS,EAAE,cAAc,MAAM;IAAQ,CAAA;GACtF,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,aAAD,EAAuB,SAAW,CAAA;GAC/B,CAAA;GACL,oBAAC,aAAD;IAAa,UAAU;IAAM,UAAU;IAAa,aAAa,eAAe,KAAA;GAAY,CAAA;EACzF;;AAET"}
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+ import { ChatMessage } from '../types';
3
+ export declare function MessageList({ messages }: {
4
+ messages: ChatMessage[];
5
+ }): ReactNode;
@@ -0,0 +1,22 @@
1
+ import { testIdentity } from "../../core/test-id.js";
2
+ import { Message } from "./message.js";
3
+ import { useEffect, useRef } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region resources/js/chat/components/message-list.tsx
6
+ function MessageList({ messages }) {
7
+ const bottomRef = useRef(null);
8
+ const lastMessage = messages.at(-1);
9
+ const lastPartLength = lastMessage?.parts.at(-1) !== void 0 ? JSON.stringify(lastMessage.parts.at(-1)).length : 0;
10
+ useEffect(() => {
11
+ if (bottomRef.current && typeof bottomRef.current.scrollIntoView === "function") bottomRef.current.scrollIntoView({ behavior: "smooth" });
12
+ }, [messages.length, lastPartLength]);
13
+ return /* @__PURE__ */ jsxs("div", {
14
+ className: "flex flex-col gap-2 overflow-y-auto p-3",
15
+ "data-test": testIdentity("chat-messages"),
16
+ children: [messages.map((message) => /* @__PURE__ */ jsx(Message, { message }, message.id)), /* @__PURE__ */ jsx("div", { ref: bottomRef })]
17
+ });
18
+ }
19
+ //#endregion
20
+ export { MessageList };
21
+
22
+ //# sourceMappingURL=message-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-list.js","names":[],"sources":["../../../resources/js/chat/components/message-list.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { ChatMessage } from \"../types\";\nimport { Message } from \"./message\";\n\nexport function MessageList({ messages }: { messages: ChatMessage[] }): ReactNode {\n const bottomRef = useRef<HTMLDivElement>(null);\n const lastMessage = messages.at(-1);\n const lastPartLength =\n lastMessage?.parts.at(-1) !== undefined ? JSON.stringify(lastMessage.parts.at(-1)).length : 0;\n\n useEffect(() => {\n if (bottomRef.current && typeof bottomRef.current.scrollIntoView === \"function\") {\n bottomRef.current.scrollIntoView({ behavior: \"smooth\" });\n }\n }, [messages.length, lastPartLength]);\n\n return (\n <div\n className=\"flex flex-col gap-2 overflow-y-auto p-3\"\n data-test={testIdentity(\"chat-messages\")}\n >\n {messages.map((message) => (\n <Message key={message.id} message={message} />\n ))}\n <div ref={bottomRef} />\n </div>\n );\n}\n"],"mappings":";;;;;AAMA,SAAgB,YAAY,EAAE,YAAoD;CAChF,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,cAAc,SAAS,GAAG,EAAE;CAClC,MAAM,iBACJ,aAAa,MAAM,GAAG,EAAE,MAAM,KAAA,IAAY,KAAK,UAAU,YAAY,MAAM,GAAG,EAAE,CAAC,EAAE,SAAS;CAE9F,gBAAgB;EACd,IAAI,UAAU,WAAW,OAAO,UAAU,QAAQ,mBAAmB,YACnE,UAAU,QAAQ,eAAe,EAAE,UAAU,SAAS,CAAC;CAE3D,GAAG,CAAC,SAAS,QAAQ,cAAc,CAAC;CAEpC,OACE,qBAAC,OAAD;EACE,WAAU;EACV,aAAW,aAAa,eAAe;YAFzC,CAIG,SAAS,KAAK,YACb,oBAAC,SAAD,EAAmC,QAAU,GAA/B,QAAQ,EAAuB,CAC9C,GACD,oBAAC,OAAD,EAAK,KAAK,UAAY,CAAA,CACnB;;AAET"}
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+ import { ChatMessage } from '../types';
3
+ export declare function Message({ message }: {
4
+ message: ChatMessage;
5
+ }): ReactNode;
@@ -0,0 +1,20 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { testIdentity } from "../../core/test-id.js";
3
+ import { RenderNode } from "../../core/renderer.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region resources/js/chat/components/message.tsx
6
+ function Message({ message }) {
7
+ const isUser = message.role === "user";
8
+ return /* @__PURE__ */ jsx("div", {
9
+ className: cn("flex flex-col gap-1", isUser ? "items-end" : "items-start"),
10
+ "data-test": testIdentity(`chat-message-${message.role}`),
11
+ children: /* @__PURE__ */ jsx("div", {
12
+ className: cn("max-w-[80%] rounded-lt px-3 py-2 text-sm", isUser ? "bg-lt-primary text-lt-primary-fg" : "bg-lt-muted text-lt-fg"),
13
+ children: message.parts.map((part, index) => /* @__PURE__ */ jsx(RenderNode, { node: part }, part.key ?? index))
14
+ })
15
+ });
16
+ }
17
+ //#endregion
18
+ export { Message };
19
+
20
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","names":[],"sources":["../../../resources/js/chat/components/message.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { ChatMessage } from \"../types\";\n\nexport function Message({ message }: { message: ChatMessage }): ReactNode {\n const isUser = message.role === \"user\";\n\n return (\n <div\n className={cn(\"flex flex-col gap-1\", isUser ? \"items-end\" : \"items-start\")}\n data-test={testIdentity(`chat-message-${message.role}`)}\n >\n <div\n className={cn(\n \"max-w-[80%] rounded-lt px-3 py-2 text-sm\",\n isUser ? \"bg-lt-primary text-lt-primary-fg\" : \"bg-lt-muted text-lt-fg\",\n )}\n >\n {message.parts.map((part, index) => (\n <RenderNode key={part.key ?? index} node={part} />\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAMA,SAAgB,QAAQ,EAAE,WAAgD;CACxE,MAAM,SAAS,QAAQ,SAAS;CAEhC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,uBAAuB,SAAS,cAAc,aAAa;EACzE,aAAW,aAAa,gBAAgB,QAAQ,MAAM;YAEtD,oBAAC,OAAD;GACE,WAAW,GACT,4CACA,SAAS,qCAAqC,wBAChD;aAEC,QAAQ,MAAM,KAAK,MAAM,UACxB,oBAAC,YAAD,EAAoC,MAAM,KAAO,GAAhC,KAAK,OAAO,KAAoB,CAClD;EACE,CAAA;CACF,CAAA;AAET"}
@@ -0,0 +1,8 @@
1
+ import { ReactNode } from 'react';
2
+ type PromptInputProps = {
3
+ onSubmit: (text: string) => void;
4
+ disabled?: boolean;
5
+ placeholder?: string;
6
+ };
7
+ export declare function PromptInput({ onSubmit, disabled, placeholder, }: PromptInputProps): ReactNode;
8
+ export {};
@@ -0,0 +1,49 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { testIdentity } from "../../core/test-id.js";
3
+ import { Button } from "../../core/components/button.js";
4
+ import { useT } from "../../i18n/instance.js";
5
+ import { useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region resources/js/chat/components/prompt-input.tsx
8
+ function PromptInput({ onSubmit, disabled = false, placeholder }) {
9
+ const { t } = useT("lattice");
10
+ const [value, setValue] = useState("");
11
+ function submit() {
12
+ const trimmed = value.trim();
13
+ if (trimmed === "" || disabled) return;
14
+ onSubmit(trimmed);
15
+ setValue("");
16
+ }
17
+ function handleKeyDown(event) {
18
+ if (event.key === "Enter" && !event.shiftKey) {
19
+ event.preventDefault();
20
+ submit();
21
+ }
22
+ }
23
+ return /* @__PURE__ */ jsxs("div", {
24
+ className: "flex items-end gap-2 border-t border-lt-border p-3",
25
+ children: [/* @__PURE__ */ jsx("textarea", {
26
+ "aria-label": t("chat.input-label", "Message input"),
27
+ className: cn("min-h-[2.5rem] flex-1 resize-none rounded-lt-sm border border-lt-input bg-lt-bg px-3 py-2 text-sm text-lt-fg placeholder:text-lt-muted-fg focus:outline-none focus:ring-1 focus:ring-lt-ring disabled:opacity-50"),
28
+ "data-test": testIdentity("chat-input"),
29
+ disabled,
30
+ onChange: (e) => setValue(e.target.value),
31
+ onKeyDown: handleKeyDown,
32
+ placeholder,
33
+ rows: 1,
34
+ value
35
+ }), /* @__PURE__ */ jsx(Button, {
36
+ "data-test": testIdentity("chat-send"),
37
+ disabled,
38
+ onClick: submit,
39
+ size: "sm",
40
+ type: "button",
41
+ variant: "default",
42
+ children: t("chat.send", "Send")
43
+ })]
44
+ });
45
+ }
46
+ //#endregion
47
+ export { PromptInput };
48
+
49
+ //# sourceMappingURL=prompt-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-input.js","names":[],"sources":["../../../resources/js/chat/components/prompt-input.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\n\ntype PromptInputProps = {\n onSubmit: (text: string) => void;\n disabled?: boolean;\n placeholder?: string;\n};\n\nexport function PromptInput({\n onSubmit,\n disabled = false,\n placeholder,\n}: PromptInputProps): ReactNode {\n const { t } = useT(\"lattice\");\n const [value, setValue] = useState(\"\");\n\n function submit(): void {\n const trimmed = value.trim();\n if (trimmed === \"\" || disabled) {\n return;\n }\n\n onSubmit(trimmed);\n setValue(\"\");\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLTextAreaElement>): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n submit();\n }\n }\n\n return (\n <div className=\"flex items-end gap-2 border-t border-lt-border p-3\">\n <textarea\n aria-label={t(\"chat.input-label\", \"Message input\")}\n className={cn(\n \"min-h-[2.5rem] flex-1 resize-none rounded-lt-sm border border-lt-input bg-lt-bg px-3 py-2 text-sm text-lt-fg placeholder:text-lt-muted-fg focus:outline-none focus:ring-1 focus:ring-lt-ring disabled:opacity-50\",\n )}\n data-test={testIdentity(\"chat-input\")}\n disabled={disabled}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n rows={1}\n value={value}\n />\n <Button\n data-test={testIdentity(\"chat-send\")}\n disabled={disabled}\n onClick={submit}\n size=\"sm\"\n type=\"button\"\n variant=\"default\"\n >\n {t(\"chat.send\", \"Send\")}\n </Button>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,YAAY,EAC1B,UACA,WAAW,OACX,eAC8B;CAC9B,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CAErC,SAAS,SAAe;EACtB,MAAM,UAAU,MAAM,KAAK;EAC3B,IAAI,YAAY,MAAM,UACpB;EAGF,SAAS,OAAO;EAChB,SAAS,EAAE;CACb;CAEA,SAAS,cAAc,OAAiD;EACtE,IAAI,MAAM,QAAQ,WAAW,CAAC,MAAM,UAAU;GAC5C,MAAM,eAAe;GACrB,OAAO;EACT;CACF;CAEA,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,YAAD;GACE,cAAY,EAAE,oBAAoB,eAAe;GACjD,WAAW,GACT,kNACF;GACA,aAAW,aAAa,YAAY;GAC1B;GACV,WAAW,MAAM,SAAS,EAAE,OAAO,KAAK;GACxC,WAAW;GACE;GACb,MAAM;GACC;EACR,CAAA,GACD,oBAAC,QAAD;GACE,aAAW,aAAa,WAAW;GACzB;GACV,SAAS;GACT,MAAK;GACL,MAAK;GACL,SAAQ;aAEP,EAAE,aAAa,MAAM;EAChB,CAAA,CACL;;AAET"}
@@ -0,0 +1 @@
1
+ export declare const chatPlugin: import('../core/registry').Plugin;
@@ -0,0 +1,15 @@
1
+ import { createPlugin, eagerComponent } from "../core/registry.js";
2
+ import { TextPart } from "./parts/text.js";
3
+ import { ToolCallPart } from "./parts/tool-call.js";
4
+ //#region resources/js/chat/index.ts
5
+ var chatPlugin = createPlugin({
6
+ name: "chat",
7
+ components: {
8
+ "chat.part.text": eagerComponent(TextPart),
9
+ "chat.part.tool-call": eagerComponent(ToolCallPart)
10
+ }
11
+ });
12
+ //#endregion
13
+ export { chatPlugin };
14
+
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/chat/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport { TextPart } from \"./parts/text\";\nimport { ToolCallPart } from \"./parts/tool-call\";\n\nexport const chatPlugin = createPlugin({\n name: \"chat\",\n components: {\n \"chat.part.text\": eagerComponent(TextPart),\n \"chat.part.tool-call\": eagerComponent(ToolCallPart),\n },\n});\n"],"mappings":";;;;AAIA,IAAa,aAAa,aAAa;CACrC,MAAM;CACN,YAAY;EACV,kBAAkB,eAAe,QAAQ;EACzC,uBAAuB,eAAe,YAAY;CACpD;AACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { RendererComponent } from '../../core/types';
2
+ export declare const TextPart: RendererComponent<"chat.part.text">;
3
+ export default TextPart;
@@ -0,0 +1,12 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ //#region resources/js/chat/parts/text.tsx
3
+ var TextPart = ({ node }) => {
4
+ return /* @__PURE__ */ jsx("div", {
5
+ className: "whitespace-pre-wrap text-sm",
6
+ children: node.props.text
7
+ });
8
+ };
9
+ //#endregion
10
+ export { TextPart, TextPart as default };
11
+
12
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../resources/js/chat/parts/text.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\n\nexport const TextPart: RendererComponent<\"chat.part.text\"> = ({ node }) => {\n return <div className=\"whitespace-pre-wrap text-sm\">{node.props.text}</div>;\n};\n\nexport default TextPart;\n"],"mappings":";;AAEA,IAAa,YAAiD,EAAE,WAAW;CACzE,OAAO,oBAAC,OAAD;EAAK,WAAU;YAA+B,KAAK,MAAM;CAAU,CAAA;AAC5E"}
@@ -0,0 +1,3 @@
1
+ import { RendererComponent } from '../../core/types';
2
+ export declare const ToolCallPart: RendererComponent<"chat.part.tool-call">;
3
+ export default ToolCallPart;
@@ -0,0 +1,20 @@
1
+ import { testIdentity } from "../../core/test-id.js";
2
+ import { jsxs } from "react/jsx-runtime";
3
+ //#region resources/js/chat/parts/tool-call.tsx
4
+ var ToolCallPart = ({ node }) => {
5
+ return /* @__PURE__ */ jsxs("div", {
6
+ className: "mt-1 inline-flex items-center gap-1 rounded-lt-sm bg-lt-muted px-2 py-0.5 font-mono text-xs text-lt-muted-fg",
7
+ "data-test": testIdentity("chat-tool-call"),
8
+ children: [
9
+ "🔧 ",
10
+ node.props.name,
11
+ "(",
12
+ JSON.stringify(node.props.args),
13
+ ")"
14
+ ]
15
+ });
16
+ };
17
+ //#endregion
18
+ export { ToolCallPart, ToolCallPart as default };
19
+
20
+ //# sourceMappingURL=tool-call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-call.js","names":[],"sources":["../../../resources/js/chat/parts/tool-call.tsx"],"sourcesContent":["import { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\n\nexport const ToolCallPart: RendererComponent<\"chat.part.tool-call\"> = ({ node }) => {\n return (\n <div\n className=\"mt-1 inline-flex items-center gap-1 rounded-lt-sm bg-lt-muted px-2 py-0.5 font-mono text-xs text-lt-muted-fg\"\n data-test={testIdentity(\"chat-tool-call\")}\n >\n 🔧 {node.props.name}({JSON.stringify(node.props.args)})\n </div>\n );\n};\n\nexport default ToolCallPart;\n"],"mappings":";;;AAGA,IAAa,gBAA0D,EAAE,WAAW;CAClF,OACE,qBAAC,OAAD;EACE,WAAU;EACV,aAAW,aAAa,gBAAgB;YAF1C;GAGC;GACK,KAAK,MAAM;GAAK;GAAE,KAAK,UAAU,KAAK,MAAM,IAAI;GAAE;EACnD;;AAET"}
@@ -0,0 +1,4 @@
1
+ import { RemoteAccess } from '../core/api';
2
+ import { ChatFrame, ChatTransportRequest } from './types';
3
+ export declare function ndjsonChatTransport({ url, body, signal, }: ChatTransportRequest): AsyncGenerator<ChatFrame>;
4
+ export declare function createRemoteNdjsonChatTransport(remote: RemoteAccess): ({ url, body, signal, }: ChatTransportRequest) => AsyncGenerator<ChatFrame>;
@@ -0,0 +1,67 @@
1
+ import { apiFetch, remoteFetch } from "../core/api.js";
2
+ //#region resources/js/chat/transport.ts
3
+ function parseFrame(line) {
4
+ try {
5
+ return JSON.parse(line);
6
+ } catch {
7
+ return null;
8
+ }
9
+ }
10
+ async function* ndjsonChatTransport({ url, body, signal }) {
11
+ const res = await apiFetch(url, {
12
+ method: "POST",
13
+ signal,
14
+ headers: { Accept: "application/x-ndjson" },
15
+ body: JSON.stringify(body),
16
+ throwOnError: false
17
+ });
18
+ if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
19
+ yield* readNdjsonFrames(res.body);
20
+ }
21
+ function createRemoteNdjsonChatTransport(remote) {
22
+ return async function* remoteNdjsonChatTransport({ url, body, signal }) {
23
+ const res = await remoteFetch(url, {
24
+ remote,
25
+ method: "POST",
26
+ signal,
27
+ headers: {
28
+ Accept: "application/x-ndjson",
29
+ "Content-Type": "application/json"
30
+ },
31
+ body: JSON.stringify(body),
32
+ throwOnError: false
33
+ });
34
+ if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
35
+ yield* readNdjsonFrames(res.body);
36
+ };
37
+ }
38
+ async function* readNdjsonFrames(body) {
39
+ const reader = body.getReader();
40
+ const decoder = new TextDecoder();
41
+ let buffer = "";
42
+ try {
43
+ for (;;) {
44
+ const { done, value } = await reader.read();
45
+ if (done) break;
46
+ buffer += decoder.decode(value, { stream: true });
47
+ const lines = buffer.split("\n");
48
+ buffer = lines.pop() ?? "";
49
+ for (const line of lines) {
50
+ if (line.trim() === "") continue;
51
+ const frame = parseFrame(line);
52
+ if (frame) yield frame;
53
+ }
54
+ }
55
+ buffer += decoder.decode();
56
+ if (buffer.trim() !== "") {
57
+ const frame = parseFrame(buffer);
58
+ if (frame) yield frame;
59
+ }
60
+ } finally {
61
+ await reader.cancel().catch(() => {});
62
+ }
63
+ }
64
+ //#endregion
65
+ export { createRemoteNdjsonChatTransport, ndjsonChatTransport };
66
+
67
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","names":[],"sources":["../../resources/js/chat/transport.ts"],"sourcesContent":["import { apiFetch, remoteFetch, type RemoteAccess } from \"../core/api\";\nimport type { ChatFrame, ChatTransportRequest } from \"./types\";\n\nfunction parseFrame(line: string): ChatFrame | null {\n try {\n return JSON.parse(line) as ChatFrame;\n } catch {\n return null;\n }\n}\n\nexport async function* ndjsonChatTransport({\n url,\n body,\n signal,\n}: ChatTransportRequest): AsyncGenerator<ChatFrame> {\n const res = await apiFetch(url, {\n method: \"POST\",\n signal,\n headers: { Accept: \"application/x-ndjson\" },\n body: JSON.stringify(body),\n throwOnError: false,\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Chat stream failed (${res.status})`);\n }\n\n yield* readNdjsonFrames(res.body);\n}\n\nexport function createRemoteNdjsonChatTransport(remote: RemoteAccess) {\n return async function* remoteNdjsonChatTransport({\n url,\n body,\n signal,\n }: ChatTransportRequest): AsyncGenerator<ChatFrame> {\n const res = await remoteFetch(url, {\n remote,\n method: \"POST\",\n signal,\n headers: {\n Accept: \"application/x-ndjson\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n throwOnError: false,\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Chat stream failed (${res.status})`);\n }\n\n yield* readNdjsonFrames(res.body);\n };\n}\n\nasync function* readNdjsonFrames(body: ReadableStream<Uint8Array>): AsyncGenerator<ChatFrame> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.trim() === \"\") {\n continue;\n }\n\n const frame = parseFrame(line);\n if (frame) {\n yield frame;\n }\n }\n }\n\n buffer += decoder.decode();\n if (buffer.trim() !== \"\") {\n const frame = parseFrame(buffer);\n if (frame) {\n yield frame;\n }\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n"],"mappings":";;AAGA,SAAS,WAAW,MAAgC;CAClD,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,gBAAuB,oBAAoB,EACzC,KACA,MACA,UACkD;CAClD,MAAM,MAAM,MAAM,SAAS,KAAK;EAC9B,QAAQ;EACR;EACA,SAAS,EAAE,QAAQ,uBAAuB;EAC1C,MAAM,KAAK,UAAU,IAAI;EACzB,cAAc;CAChB,CAAC;CAED,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAClB,MAAM,IAAI,MAAM,uBAAuB,IAAI,OAAO,EAAE;CAGtD,OAAO,iBAAiB,IAAI,IAAI;AAClC;AAEA,SAAgB,gCAAgC,QAAsB;CACpE,OAAO,gBAAgB,0BAA0B,EAC/C,KACA,MACA,UACkD;EAClD,MAAM,MAAM,MAAM,YAAY,KAAK;GACjC;GACA,QAAQ;GACR;GACA,SAAS;IACP,QAAQ;IACR,gBAAgB;GAClB;GACA,MAAM,KAAK,UAAU,IAAI;GACzB,cAAc;EAChB,CAAC;EAED,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAClB,MAAM,IAAI,MAAM,uBAAuB,IAAI,OAAO,EAAE;EAGtD,OAAO,iBAAiB,IAAI,IAAI;CAClC;AACF;AAEA,gBAAgB,iBAAiB,MAA6D;CAC5F,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CAEb,IAAI;EACF,SAAS;GACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAC1C,IAAI,MACF;GAGF,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;GAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;GAC/B,SAAS,MAAM,IAAI,KAAK;GAExB,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,KAAK,KAAK,MAAM,IAClB;IAGF,MAAM,QAAQ,WAAW,IAAI;IAC7B,IAAI,OACF,MAAM;GAEV;EACF;EAEA,UAAU,QAAQ,OAAO;EACzB,IAAI,OAAO,KAAK,MAAM,IAAI;GACxB,MAAM,QAAQ,WAAW,MAAM;GAC/B,IAAI,OACF,MAAM;EAEV;CACF,UAAU;EACR,MAAM,OAAO,OAAO,EAAE,YAAY,CAAC,CAAC;CACtC;AACF"}
@@ -0,0 +1,39 @@
1
+ import { Node } from '../core/types';
2
+ import { ChatMessage as GeneratedChatMessage, ChatRole } from '../types/generated';
3
+ export type { ChatRole };
4
+ /**
5
+ * The generated message shape, but `parts` is widened from the generated
6
+ * `ChatNode` union to open `Node`s — a part is just a component node rendered by
7
+ * `type`, so a message can also carry a consumer's custom part.
8
+ */
9
+ export type ChatMessage = Omit<GeneratedChatMessage, "parts"> & {
10
+ parts: Node[];
11
+ };
12
+ export type ChatStatus = "idle" | "submitted" | "streaming" | "error";
13
+ export type ChatFrame = {
14
+ type: "text";
15
+ value: string;
16
+ } | {
17
+ type: "part";
18
+ part: Node;
19
+ } | {
20
+ type: "done";
21
+ } | {
22
+ type: "error";
23
+ message?: string;
24
+ };
25
+ export type ChatTransportRequest = {
26
+ url: string;
27
+ body: unknown;
28
+ signal: AbortSignal;
29
+ };
30
+ export type ChatTransport = (request: ChatTransportRequest) => AsyncGenerator<ChatFrame>;
31
+ export type UseChatReturn = {
32
+ messages: ChatMessage[];
33
+ status: ChatStatus;
34
+ error: string | null;
35
+ sendMessage: (text: string) => void;
36
+ setMessages: (messages: ChatMessage[]) => void;
37
+ stop: () => void;
38
+ regenerate: () => void;
39
+ };
@@ -0,0 +1,15 @@
1
+ import { ChatFrame, ChatMessage, ChatTransport, UseChatReturn } from './types';
2
+ export type UseChatOptions = {
3
+ endpoint: string;
4
+ transport?: ChatTransport;
5
+ initialMessages?: ChatMessage[];
6
+ generateId?: () => string;
7
+ };
8
+ /**
9
+ * Pure reducer for a single streamed frame: a `text` frame appends to the open
10
+ * assistant text part (opening one if the last part is not text); a `part` frame
11
+ * pushes a complete part, which closes the open text part. Operates immutably on
12
+ * the last assistant message.
13
+ */
14
+ export declare function foldFrame(messages: ChatMessage[], frame: ChatFrame): ChatMessage[];
15
+ export declare function useChat({ endpoint, transport, initialMessages, generateId, }: UseChatOptions): UseChatReturn;
@@ -0,0 +1,161 @@
1
+ import { ndjsonChatTransport } from "./transport.js";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ //#region resources/js/chat/use-chat.ts
4
+ var idCounter = 0;
5
+ function defaultGenerateId() {
6
+ idCounter += 1;
7
+ return `chat-${idCounter}`;
8
+ }
9
+ function isAbortError(error) {
10
+ return error instanceof DOMException && error.name === "AbortError";
11
+ }
12
+ function errorMessage(error) {
13
+ return error instanceof Error ? error.message : String(error);
14
+ }
15
+ function lastIsAssistant(messages) {
16
+ const last = messages.at(-1);
17
+ return last !== void 0 && last.role === "assistant";
18
+ }
19
+ /**
20
+ * Pure reducer for a single streamed frame: a `text` frame appends to the open
21
+ * assistant text part (opening one if the last part is not text); a `part` frame
22
+ * pushes a complete part, which closes the open text part. Operates immutably on
23
+ * the last assistant message.
24
+ */
25
+ function foldFrame(messages, frame) {
26
+ if (!lastIsAssistant(messages)) return messages;
27
+ const index = messages.length - 1;
28
+ const target = messages[index];
29
+ if (frame.type === "text") {
30
+ const parts = [...target.parts];
31
+ const openIndex = parts.length - 1;
32
+ const open = parts[openIndex];
33
+ if (open !== void 0 && open.type === "chat.part.text") parts[openIndex] = {
34
+ type: "chat.part.text",
35
+ props: { text: `${open.props.text}${frame.value}` }
36
+ };
37
+ else parts.push({
38
+ type: "chat.part.text",
39
+ props: { text: frame.value }
40
+ });
41
+ const next = [...messages];
42
+ next[index] = {
43
+ ...target,
44
+ parts
45
+ };
46
+ return next;
47
+ }
48
+ if (frame.type === "part") {
49
+ const next = [...messages];
50
+ next[index] = {
51
+ ...target,
52
+ parts: [...target.parts, frame.part]
53
+ };
54
+ return next;
55
+ }
56
+ return messages;
57
+ }
58
+ function useChat({ endpoint, transport = ndjsonChatTransport, initialMessages = [], generateId = defaultGenerateId }) {
59
+ const [messages, setMessagesState] = useState(initialMessages);
60
+ const [status, setStatus] = useState("idle");
61
+ const [error, setError] = useState(null);
62
+ const abortRef = useRef(null);
63
+ const lastUserTextRef = useRef(null);
64
+ const messagesRef = useRef(messages);
65
+ messagesRef.current = messages;
66
+ const commitMessages = useCallback((next) => {
67
+ messagesRef.current = next;
68
+ setMessagesState(next);
69
+ }, []);
70
+ const runTurn = useCallback(async (history, userText) => {
71
+ abortRef.current?.abort();
72
+ const controller = new AbortController();
73
+ abortRef.current = controller;
74
+ setError(null);
75
+ setStatus("submitted");
76
+ const userMessage = {
77
+ id: generateId(),
78
+ role: "user",
79
+ parts: [{
80
+ type: "chat.part.text",
81
+ props: { text: userText }
82
+ }]
83
+ };
84
+ const assistantMessage = {
85
+ id: generateId(),
86
+ role: "assistant",
87
+ parts: []
88
+ };
89
+ commitMessages([
90
+ ...history,
91
+ userMessage,
92
+ assistantMessage
93
+ ]);
94
+ setStatus("streaming");
95
+ try {
96
+ for await (const frame of transport({
97
+ url: endpoint,
98
+ body: { message: userText },
99
+ signal: controller.signal
100
+ })) {
101
+ if (frame.type === "done") {
102
+ setStatus("idle");
103
+ continue;
104
+ }
105
+ if (frame.type === "error") {
106
+ setError(frame.message ?? "Chat failed");
107
+ setStatus("error");
108
+ continue;
109
+ }
110
+ commitMessages(foldFrame(messagesRef.current, frame));
111
+ }
112
+ setStatus((current) => current === "streaming" || current === "submitted" ? "idle" : current);
113
+ } catch (caught) {
114
+ if (isAbortError(caught)) {
115
+ setStatus("idle");
116
+ return;
117
+ }
118
+ setError(errorMessage(caught));
119
+ setStatus("error");
120
+ }
121
+ }, [
122
+ commitMessages,
123
+ endpoint,
124
+ generateId,
125
+ transport
126
+ ]);
127
+ const sendMessage = useCallback((text) => {
128
+ const trimmed = text.trim();
129
+ if (trimmed === "") return;
130
+ lastUserTextRef.current = trimmed;
131
+ runTurn(messagesRef.current, trimmed);
132
+ }, [runTurn]);
133
+ const stop = useCallback(() => {
134
+ abortRef.current?.abort();
135
+ setStatus("idle");
136
+ }, []);
137
+ const regenerate = useCallback(() => {
138
+ const userText = lastUserTextRef.current;
139
+ if (userText === null) return;
140
+ const current = messagesRef.current;
141
+ runTurn(lastIsAssistant(current) ? current.slice(0, -2) : current, userText);
142
+ }, [runTurn]);
143
+ useEffect(() => {
144
+ return () => {
145
+ abortRef.current?.abort();
146
+ };
147
+ }, []);
148
+ return {
149
+ messages,
150
+ status,
151
+ error,
152
+ sendMessage,
153
+ setMessages: commitMessages,
154
+ stop,
155
+ regenerate
156
+ };
157
+ }
158
+ //#endregion
159
+ export { foldFrame, useChat };
160
+
161
+ //# sourceMappingURL=use-chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chat.js","names":[],"sources":["../../resources/js/chat/use-chat.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { ndjsonChatTransport } from \"./transport\";\nimport type { ChatFrame, ChatMessage, ChatStatus, ChatTransport, UseChatReturn } from \"./types\";\n\nexport type UseChatOptions = {\n endpoint: string;\n transport?: ChatTransport;\n initialMessages?: ChatMessage[];\n generateId?: () => string;\n};\n\nlet idCounter = 0;\n\nfunction defaultGenerateId(): string {\n idCounter += 1;\n\n return `chat-${idCounter}`;\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === \"AbortError\";\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction lastIsAssistant(messages: ChatMessage[]): boolean {\n const last = messages.at(-1);\n\n return last !== undefined && last.role === \"assistant\";\n}\n\n/**\n * Pure reducer for a single streamed frame: a `text` frame appends to the open\n * assistant text part (opening one if the last part is not text); a `part` frame\n * pushes a complete part, which closes the open text part. Operates immutably on\n * the last assistant message.\n */\nexport function foldFrame(messages: ChatMessage[], frame: ChatFrame): ChatMessage[] {\n if (!lastIsAssistant(messages)) {\n return messages;\n }\n\n const index = messages.length - 1;\n const target = messages[index];\n\n if (frame.type === \"text\") {\n const parts = [...target.parts];\n const openIndex = parts.length - 1;\n const open = parts[openIndex];\n\n if (open !== undefined && open.type === \"chat.part.text\") {\n const openText = (open.props as { text: string }).text;\n parts[openIndex] = { type: \"chat.part.text\", props: { text: `${openText}${frame.value}` } };\n } else {\n parts.push({ type: \"chat.part.text\", props: { text: frame.value } });\n }\n\n const next = [...messages];\n next[index] = { ...target, parts };\n\n return next;\n }\n\n if (frame.type === \"part\") {\n const next = [...messages];\n next[index] = { ...target, parts: [...target.parts, frame.part] };\n\n return next;\n }\n\n return messages;\n}\n\nexport function useChat({\n endpoint,\n transport = ndjsonChatTransport,\n initialMessages = [],\n generateId = defaultGenerateId,\n}: UseChatOptions): UseChatReturn {\n const [messages, setMessagesState] = useState<ChatMessage[]>(initialMessages);\n const [status, setStatus] = useState<ChatStatus>(\"idle\");\n const [error, setError] = useState<string | null>(null);\n\n const abortRef = useRef<AbortController | null>(null);\n const lastUserTextRef = useRef<string | null>(null);\n const messagesRef = useRef<ChatMessage[]>(messages);\n messagesRef.current = messages;\n\n const commitMessages = useCallback((next: ChatMessage[]): void => {\n messagesRef.current = next;\n setMessagesState(next);\n }, []);\n\n const runTurn = useCallback(\n async (history: ChatMessage[], userText: string): Promise<void> => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setError(null);\n setStatus(\"submitted\");\n\n const userMessage: ChatMessage = {\n id: generateId(),\n role: \"user\",\n parts: [{ type: \"chat.part.text\", props: { text: userText } }],\n };\n const assistantMessage: ChatMessage = { id: generateId(), role: \"assistant\", parts: [] };\n commitMessages([...history, userMessage, assistantMessage]);\n setStatus(\"streaming\");\n\n try {\n for await (const frame of transport({\n url: endpoint,\n body: { message: userText },\n signal: controller.signal,\n })) {\n if (frame.type === \"done\") {\n setStatus(\"idle\");\n continue;\n }\n\n if (frame.type === \"error\") {\n setError(frame.message ?? \"Chat failed\");\n setStatus(\"error\");\n continue;\n }\n\n commitMessages(foldFrame(messagesRef.current, frame));\n }\n\n setStatus((current) =>\n current === \"streaming\" || current === \"submitted\" ? \"idle\" : current,\n );\n } catch (caught) {\n if (isAbortError(caught)) {\n setStatus(\"idle\");\n\n return;\n }\n\n setError(errorMessage(caught));\n setStatus(\"error\");\n }\n },\n [commitMessages, endpoint, generateId, transport],\n );\n\n const sendMessage = useCallback(\n (text: string): void => {\n const trimmed = text.trim();\n if (trimmed === \"\") {\n return;\n }\n\n lastUserTextRef.current = trimmed;\n void runTurn(messagesRef.current, trimmed);\n },\n [runTurn],\n );\n\n const stop = useCallback((): void => {\n abortRef.current?.abort();\n setStatus(\"idle\");\n }, []);\n\n const regenerate = useCallback((): void => {\n const userText = lastUserTextRef.current;\n if (userText === null) {\n return;\n }\n\n const current = messagesRef.current;\n const history = lastIsAssistant(current) ? current.slice(0, -2) : current;\n void runTurn(history, userText);\n }, [runTurn]);\n\n useEffect(() => {\n return () => {\n abortRef.current?.abort();\n };\n }, []);\n\n return { messages, status, error, sendMessage, setMessages: commitMessages, stop, regenerate };\n}\n"],"mappings":";;;AAWA,IAAI,YAAY;AAEhB,SAAS,oBAA4B;CACnC,aAAa;CAEb,OAAO,QAAQ;AACjB;AAEA,SAAS,aAAa,OAAyB;CAC7C,OAAO,iBAAiB,gBAAgB,MAAM,SAAS;AACzD;AAEA,SAAS,aAAa,OAAwB;CAC5C,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,SAAS,gBAAgB,UAAkC;CACzD,MAAM,OAAO,SAAS,GAAG,EAAE;CAE3B,OAAO,SAAS,KAAA,KAAa,KAAK,SAAS;AAC7C;;;;;;;AAQA,SAAgB,UAAU,UAAyB,OAAiC;CAClF,IAAI,CAAC,gBAAgB,QAAQ,GAC3B,OAAO;CAGT,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,SAAS,SAAS;CAExB,IAAI,MAAM,SAAS,QAAQ;EACzB,MAAM,QAAQ,CAAC,GAAG,OAAO,KAAK;EAC9B,MAAM,YAAY,MAAM,SAAS;EACjC,MAAM,OAAO,MAAM;EAEnB,IAAI,SAAS,KAAA,KAAa,KAAK,SAAS,kBAEtC,MAAM,aAAa;GAAE,MAAM;GAAkB,OAAO,EAAE,MAAM,GAD1C,KAAK,MAA2B,OACwB,MAAM,QAAQ;EAAE;OAE1F,MAAM,KAAK;GAAE,MAAM;GAAkB,OAAO,EAAE,MAAM,MAAM,MAAM;EAAE,CAAC;EAGrE,MAAM,OAAO,CAAC,GAAG,QAAQ;EACzB,KAAK,SAAS;GAAE,GAAG;GAAQ;EAAM;EAEjC,OAAO;CACT;CAEA,IAAI,MAAM,SAAS,QAAQ;EACzB,MAAM,OAAO,CAAC,GAAG,QAAQ;EACzB,KAAK,SAAS;GAAE,GAAG;GAAQ,OAAO,CAAC,GAAG,OAAO,OAAO,MAAM,IAAI;EAAE;EAEhE,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAgB,QAAQ,EACtB,UACA,YAAY,qBACZ,kBAAkB,CAAC,GACnB,aAAa,qBACmB;CAChC,MAAM,CAAC,UAAU,oBAAoB,SAAwB,eAAe;CAC5E,MAAM,CAAC,QAAQ,aAAa,SAAqB,MAAM;CACvD,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CAEtD,MAAM,WAAW,OAA+B,IAAI;CACpD,MAAM,kBAAkB,OAAsB,IAAI;CAClD,MAAM,cAAc,OAAsB,QAAQ;CAClD,YAAY,UAAU;CAEtB,MAAM,iBAAiB,aAAa,SAA8B;EAChE,YAAY,UAAU;EACtB,iBAAiB,IAAI;CACvB,GAAG,CAAC,CAAC;CAEL,MAAM,UAAU,YACd,OAAO,SAAwB,aAAoC;EACjE,SAAS,SAAS,MAAM;EACxB,MAAM,aAAa,IAAI,gBAAgB;EACvC,SAAS,UAAU;EAEnB,SAAS,IAAI;EACb,UAAU,WAAW;EAErB,MAAM,cAA2B;GAC/B,IAAI,WAAW;GACf,MAAM;GACN,OAAO,CAAC;IAAE,MAAM;IAAkB,OAAO,EAAE,MAAM,SAAS;GAAE,CAAC;EAC/D;EACA,MAAM,mBAAgC;GAAE,IAAI,WAAW;GAAG,MAAM;GAAa,OAAO,CAAC;EAAE;EACvF,eAAe;GAAC,GAAG;GAAS;GAAa;EAAgB,CAAC;EAC1D,UAAU,WAAW;EAErB,IAAI;GACF,WAAW,MAAM,SAAS,UAAU;IAClC,KAAK;IACL,MAAM,EAAE,SAAS,SAAS;IAC1B,QAAQ,WAAW;GACrB,CAAC,GAAG;IACF,IAAI,MAAM,SAAS,QAAQ;KACzB,UAAU,MAAM;KAChB;IACF;IAEA,IAAI,MAAM,SAAS,SAAS;KAC1B,SAAS,MAAM,WAAW,aAAa;KACvC,UAAU,OAAO;KACjB;IACF;IAEA,eAAe,UAAU,YAAY,SAAS,KAAK,CAAC;GACtD;GAEA,WAAW,YACT,YAAY,eAAe,YAAY,cAAc,SAAS,OAChE;EACF,SAAS,QAAQ;GACf,IAAI,aAAa,MAAM,GAAG;IACxB,UAAU,MAAM;IAEhB;GACF;GAEA,SAAS,aAAa,MAAM,CAAC;GAC7B,UAAU,OAAO;EACnB;CACF,GACA;EAAC;EAAgB;EAAU;EAAY;CAAS,CAClD;CAEA,MAAM,cAAc,aACjB,SAAuB;EACtB,MAAM,UAAU,KAAK,KAAK;EAC1B,IAAI,YAAY,IACd;EAGF,gBAAgB,UAAU;EAC1B,QAAa,YAAY,SAAS,OAAO;CAC3C,GACA,CAAC,OAAO,CACV;CAEA,MAAM,OAAO,kBAAwB;EACnC,SAAS,SAAS,MAAM;EACxB,UAAU,MAAM;CAClB,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,kBAAwB;EACzC,MAAM,WAAW,gBAAgB;EACjC,IAAI,aAAa,MACf;EAGF,MAAM,UAAU,YAAY;EAE5B,QADgB,gBAAgB,OAAO,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI,SAC5C,QAAQ;CAChC,GAAG,CAAC,OAAO,CAAC;CAEZ,gBAAgB;EACd,aAAa;GACX,SAAS,SAAS,MAAM;EAC1B;CACF,GAAG,CAAC,CAAC;CAEL,OAAO;EAAE;EAAU;EAAQ;EAAO;EAAa,aAAa;EAAgB;EAAM;CAAW;AAC/F"}
@@ -0,0 +1,25 @@
1
+ import { BrowserToken as GeneratedBrowserToken, RemoteAccess as GeneratedRemoteAccess } from '../types/generated';
2
+ export declare class ApiError extends Error {
3
+ readonly response: Response;
4
+ constructor(response: Response);
5
+ }
6
+ export type ApiInit = Omit<RequestInit, "headers"> & {
7
+ ref?: string;
8
+ headers?: Record<string, string>;
9
+ throwOnError?: boolean;
10
+ };
11
+ export type BrowserToken = GeneratedBrowserToken;
12
+ export type RemoteAccess = GeneratedRemoteAccess;
13
+ export type RemoteInit = Omit<RequestInit, "credentials" | "headers"> & {
14
+ headers?: Record<string, string>;
15
+ remote: RemoteAccess;
16
+ retryOnUnauthorized?: boolean;
17
+ throwOnError?: boolean;
18
+ };
19
+ export declare function apiFetch(url: string, init?: ApiInit): Promise<Response>;
20
+ export declare function apiJson<T>(url: string, init?: ApiInit): Promise<T>;
21
+ export declare function clearRemoteTokenCache(): void;
22
+ export declare function invalidateRemoteToken(remote: RemoteAccess): void;
23
+ export declare function remoteToken(remote: RemoteAccess): Promise<BrowserToken>;
24
+ export declare function remoteFetch(url: string, init: RemoteInit): Promise<Response>;
25
+ export declare function remoteJson<T>(url: string, init: RemoteInit): Promise<T>;