@lattice-php/lattice 0.2.0 → 0.3.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 (476) 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 +2 -0
  37. package/dist/chat/transport.js +47 -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 +18 -0
  44. package/dist/core/api.js +51 -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.map +1 -1
  53. package/dist/core/components/button.d.ts +1 -1
  54. package/dist/core/components/button.js +4 -0
  55. package/dist/core/components/button.js.map +1 -1
  56. package/dist/core/components/card.js.map +1 -1
  57. package/dist/core/components/chart.d.ts +3 -0
  58. package/dist/core/components/chart.js +175 -0
  59. package/dist/core/components/chart.js.map +1 -0
  60. package/dist/{form/components/base → core/components}/checkbox.js +3 -3
  61. package/dist/{form/components/base → core/components}/checkbox.js.map +1 -1
  62. package/dist/core/components/combobox.d.ts +33 -0
  63. package/dist/core/components/combobox.js +99 -0
  64. package/dist/core/components/combobox.js.map +1 -0
  65. package/dist/core/components/confirm-dialog.js +6 -12
  66. package/dist/core/components/confirm-dialog.js.map +1 -1
  67. package/dist/core/components/control.d.ts +13 -0
  68. package/dist/core/components/control.js +27 -0
  69. package/dist/core/components/control.js.map +1 -0
  70. package/dist/core/components/dialog.d.ts +19 -0
  71. package/dist/core/components/dialog.js +75 -0
  72. package/dist/core/components/dialog.js.map +1 -0
  73. package/dist/core/components/dropdown-menu.d.ts +14 -0
  74. package/dist/core/components/dropdown-menu.js +42 -0
  75. package/dist/core/components/dropdown-menu.js.map +1 -0
  76. package/dist/core/components/floating-panel.d.ts +3 -0
  77. package/dist/core/components/floating-panel.js +65 -0
  78. package/dist/core/components/floating-panel.js.map +1 -0
  79. package/dist/core/components/fragment.js +25 -13
  80. package/dist/core/components/fragment.js.map +1 -1
  81. package/dist/core/components/grid.js.map +1 -1
  82. package/dist/core/components/heading.js.map +1 -1
  83. package/dist/core/components/icon.js +1 -0
  84. package/dist/core/components/icon.js.map +1 -1
  85. package/dist/core/components/index.js +8 -1
  86. package/dist/core/components/index.js.map +1 -1
  87. package/dist/core/components/info-tooltip.d.ts +3 -0
  88. package/dist/core/components/info-tooltip.js +26 -0
  89. package/dist/core/components/info-tooltip.js.map +1 -0
  90. package/dist/core/components/link.js +12 -6
  91. package/dist/core/components/link.js.map +1 -1
  92. package/dist/core/components/modal.js +9 -31
  93. package/dist/core/components/modal.js.map +1 -1
  94. package/dist/core/components/popover.d.ts +8 -0
  95. package/dist/core/components/popover.js +37 -0
  96. package/dist/core/components/popover.js.map +1 -0
  97. package/dist/core/components/raw-block.d.ts +3 -0
  98. package/dist/core/components/raw-block.js +10 -0
  99. package/dist/core/components/raw-block.js.map +1 -0
  100. package/dist/core/components/section.js +6 -10
  101. package/dist/core/components/section.js.map +1 -1
  102. package/dist/core/components/segmented-control.js.map +1 -1
  103. package/dist/core/components/segmented-pills.js.map +1 -1
  104. package/dist/core/components/skeleton.d.ts +3 -0
  105. package/dist/core/components/skeleton.js +16 -0
  106. package/dist/core/components/skeleton.js.map +1 -0
  107. package/dist/core/components/spinner.js.map +1 -1
  108. package/dist/core/components/stack.js +19 -8
  109. package/dist/core/components/stack.js.map +1 -1
  110. package/dist/core/components/tabs.js.map +1 -1
  111. package/dist/core/components/text.js +17 -1
  112. package/dist/core/components/text.js.map +1 -1
  113. package/dist/core/headers.d.ts +1 -0
  114. package/dist/core/headers.js +14 -0
  115. package/dist/core/headers.js.map +1 -0
  116. package/dist/core/registry-context.d.ts +21 -0
  117. package/dist/core/registry-context.js +40 -0
  118. package/dist/core/registry-context.js.map +1 -0
  119. package/dist/core/registry.d.ts +4 -1
  120. package/dist/core/registry.js +10 -1
  121. package/dist/core/registry.js.map +1 -1
  122. package/dist/core/renderer.d.ts +8 -14
  123. package/dist/core/renderer.js +17 -27
  124. package/dist/core/renderer.js.map +1 -1
  125. package/dist/core/test-id.d.ts +8 -0
  126. package/dist/core/test-id.js +21 -0
  127. package/dist/core/test-id.js.map +1 -0
  128. package/dist/core/types.d.ts +22 -8
  129. package/dist/core/use-column-resizing.d.ts +27 -0
  130. package/dist/core/use-column-resizing.js +228 -0
  131. package/dist/core/use-column-resizing.js.map +1 -0
  132. package/dist/effects/dispatch.d.ts +20 -0
  133. package/dist/effects/dispatch.js +39 -0
  134. package/dist/effects/dispatch.js.map +1 -0
  135. package/dist/effects/registry.d.ts +38 -0
  136. package/dist/effects/registry.js +51 -0
  137. package/dist/effects/registry.js.map +1 -0
  138. package/dist/effects/use-effect-dispatcher.d.ts +8 -0
  139. package/dist/effects/use-effect-dispatcher.js +20 -0
  140. package/dist/effects/use-effect-dispatcher.js.map +1 -0
  141. package/dist/effects/use-flash-effects.d.ts +5 -0
  142. package/dist/effects/use-flash-effects.js +22 -0
  143. package/dist/effects/use-flash-effects.js.map +1 -0
  144. package/dist/events/event-bridge.d.ts +3 -7
  145. package/dist/events/event-bridge.js +17 -47
  146. package/dist/events/event-bridge.js.map +1 -1
  147. package/dist/events/event-names.d.ts +3 -1
  148. package/dist/events/event-names.js +3 -1
  149. package/dist/events/event-names.js.map +1 -1
  150. package/dist/form/components/base/field.d.ts +2 -1
  151. package/dist/form/components/base/field.js +17 -2
  152. package/dist/form/components/base/field.js.map +1 -1
  153. package/dist/form/components/base/input-error.js +1 -1
  154. package/dist/form/components/base/input-error.js.map +1 -1
  155. package/dist/form/components/base/input.js +2 -1
  156. package/dist/form/components/base/input.js.map +1 -1
  157. package/dist/form/components/base/label.js.map +1 -1
  158. package/dist/form/components/base/password-input.js.map +1 -1
  159. package/dist/form/components/base/submit-button.js +3 -1
  160. package/dist/form/components/base/submit-button.js.map +1 -1
  161. package/dist/form/components/base/textarea.js +2 -1
  162. package/dist/form/components/base/textarea.js.map +1 -1
  163. package/dist/form/components/conditions.js.map +1 -1
  164. package/dist/form/components/context.d.ts +1 -0
  165. package/dist/form/components/context.js +1 -0
  166. package/dist/form/components/context.js.map +1 -1
  167. package/dist/form/components/field-props.d.ts +4 -0
  168. package/dist/form/components/field-props.js.map +1 -1
  169. package/dist/form/components/field-scope.d.ts +21 -0
  170. package/dist/form/components/field-scope.js +54 -0
  171. package/dist/form/components/field-scope.js.map +1 -0
  172. package/dist/form/components/fields/block-add-menu.d.ts +9 -0
  173. package/dist/form/components/fields/block-add-menu.js +27 -0
  174. package/dist/form/components/fields/block-add-menu.js.map +1 -0
  175. package/dist/form/components/fields/builder.d.ts +2 -0
  176. package/dist/form/components/fields/builder.js +124 -0
  177. package/dist/form/components/fields/builder.js.map +1 -0
  178. package/dist/form/components/fields/checkbox.d.ts +1 -1
  179. package/dist/form/components/fields/checkbox.js +14 -11
  180. package/dist/form/components/fields/checkbox.js.map +1 -1
  181. package/dist/form/components/fields/choice.d.ts +1 -1
  182. package/dist/form/components/fields/choice.js +5 -4
  183. package/dist/form/components/fields/choice.js.map +1 -1
  184. package/dist/form/components/fields/date-input.d.ts +1 -1
  185. package/dist/form/components/fields/date-input.js +2 -1
  186. package/dist/form/components/fields/date-input.js.map +1 -1
  187. package/dist/form/components/fields/file-upload.d.ts +2 -0
  188. package/dist/form/components/fields/file-upload.js +250 -0
  189. package/dist/form/components/fields/file-upload.js.map +1 -0
  190. package/dist/form/components/fields/hidden-input.d.ts +1 -1
  191. package/dist/form/components/fields/hidden-input.js +11 -5
  192. package/dist/form/components/fields/hidden-input.js.map +1 -1
  193. package/dist/form/components/fields/number-input.d.ts +1 -1
  194. package/dist/form/components/fields/number-input.js +3 -1
  195. package/dist/form/components/fields/number-input.js.map +1 -1
  196. package/dist/form/components/fields/password-input.d.ts +1 -1
  197. package/dist/form/components/fields/password-input.js +31 -22
  198. package/dist/form/components/fields/password-input.js.map +1 -1
  199. package/dist/form/components/fields/repeater-rows.d.ts +12 -0
  200. package/dist/form/components/fields/repeater-rows.js +46 -0
  201. package/dist/form/components/fields/repeater-rows.js.map +1 -0
  202. package/dist/form/components/fields/repeater.d.ts +2 -0
  203. package/dist/form/components/fields/repeater.js +97 -0
  204. package/dist/form/components/fields/repeater.js.map +1 -0
  205. package/dist/form/components/fields/rich-editor.d.ts +1 -1
  206. package/dist/form/components/fields/rich-editor.js +37 -9
  207. package/dist/form/components/fields/rich-editor.js.map +1 -1
  208. package/dist/form/components/fields/row-action-menu.d.ts +17 -0
  209. package/dist/form/components/fields/row-action-menu.js +61 -0
  210. package/dist/form/components/fields/row-action-menu.js.map +1 -0
  211. package/dist/form/components/fields/row-actions.d.ts +10 -0
  212. package/dist/form/components/fields/row-actions.js +45 -0
  213. package/dist/form/components/fields/row-actions.js.map +1 -0
  214. package/dist/form/components/fields/row-item.d.ts +27 -0
  215. package/dist/form/components/fields/row-item.js +69 -0
  216. package/dist/form/components/fields/row-item.js.map +1 -0
  217. package/dist/form/components/fields/select.d.ts +1 -1
  218. package/dist/form/components/fields/select.js +69 -104
  219. package/dist/form/components/fields/select.js.map +1 -1
  220. package/dist/form/components/fields/simple-field.js +1 -0
  221. package/dist/form/components/fields/simple-field.js.map +1 -1
  222. package/dist/form/components/fields/table-rows.d.ts +32 -0
  223. package/dist/form/components/fields/table-rows.js +188 -0
  224. package/dist/form/components/fields/table-rows.js.map +1 -0
  225. package/dist/form/components/fields/text-input.d.ts +1 -1
  226. package/dist/form/components/fields/text-input.js +2 -1
  227. package/dist/form/components/fields/text-input.js.map +1 -1
  228. package/dist/form/components/fields/textarea.d.ts +1 -1
  229. package/dist/form/components/fields/textarea.js +2 -1
  230. package/dist/form/components/fields/textarea.js.map +1 -1
  231. package/dist/form/components/fields/use-flip-reorder.d.ts +6 -0
  232. package/dist/form/components/fields/use-flip-reorder.js +51 -0
  233. package/dist/form/components/fields/use-flip-reorder.js.map +1 -0
  234. package/dist/form/components/fields/use-row-collection.d.ts +11 -0
  235. package/dist/form/components/fields/use-row-collection.js +44 -0
  236. package/dist/form/components/fields/use-row-collection.js.map +1 -0
  237. package/dist/form/components/form-path.d.ts +5 -0
  238. package/dist/form/components/form-path.js +40 -0
  239. package/dist/form/components/form-path.js.map +1 -0
  240. package/dist/form/components/form-transport.d.ts +3 -4
  241. package/dist/form/components/form-transport.js +17 -18
  242. package/dist/form/components/form-transport.js.map +1 -1
  243. package/dist/form/components/form.js +24 -18
  244. package/dist/form/components/form.js.map +1 -1
  245. package/dist/form/components/index.d.ts +3 -0
  246. package/dist/form/components/index.js +4 -1
  247. package/dist/form/components/override-keys.d.ts +2 -0
  248. package/dist/form/components/override-keys.js +12 -0
  249. package/dist/form/components/override-keys.js.map +1 -0
  250. package/dist/form/components/prefill-context.d.ts +5 -0
  251. package/dist/form/components/prefill-context.js +11 -0
  252. package/dist/form/components/prefill-context.js.map +1 -0
  253. package/dist/form/components/prefill-targets.d.ts +17 -0
  254. package/dist/form/components/prefill-targets.js +73 -0
  255. package/dist/form/components/prefill-targets.js.map +1 -0
  256. package/dist/form/components/resolved-nodes.js +4 -1
  257. package/dist/form/components/resolved-nodes.js.map +1 -1
  258. package/dist/form/components/row-layout-context.d.ts +5 -0
  259. package/dist/form/components/row-layout-context.js +18 -0
  260. package/dist/form/components/row-layout-context.js.map +1 -0
  261. package/dist/form/components/use-controlled-field.d.ts +2 -0
  262. package/dist/form/components/use-controlled-field.js +13 -5
  263. package/dist/form/components/use-controlled-field.js.map +1 -1
  264. package/dist/form/components/use-dependent-field.js +7 -1
  265. package/dist/form/components/use-dependent-field.js.map +1 -1
  266. package/dist/form/components/use-field-commit.d.ts +4 -0
  267. package/dist/form/components/use-field-commit.js +21 -7
  268. package/dist/form/components/use-field-commit.js.map +1 -1
  269. package/dist/form/components/use-form-resolver.d.ts +6 -1
  270. package/dist/form/components/use-form-resolver.js +50 -5
  271. package/dist/form/components/use-form-resolver.js.map +1 -1
  272. package/dist/form/components/use-seed-default.js +8 -3
  273. package/dist/form/components/use-seed-default.js.map +1 -1
  274. package/dist/form/components/values.js +20 -5
  275. package/dist/form/components/values.js.map +1 -1
  276. package/dist/form/index.js +13 -10
  277. package/dist/form/index.js.map +1 -1
  278. package/dist/form/skeleton.js +5 -4
  279. package/dist/form/skeleton.js.map +1 -1
  280. package/dist/i18n/backend.d.ts +7 -5
  281. package/dist/i18n/backend.js +23 -8
  282. package/dist/i18n/backend.js.map +1 -1
  283. package/dist/i18n/config.d.ts +6 -0
  284. package/dist/i18n/config.js +36 -0
  285. package/dist/i18n/config.js.map +1 -0
  286. package/dist/i18n/index.d.ts +7 -1
  287. package/dist/i18n/index.js +5 -1
  288. package/dist/i18n/instance.d.ts +27 -0
  289. package/dist/i18n/instance.js +63 -16
  290. package/dist/i18n/instance.js.map +1 -1
  291. package/dist/i18n/locale-reload.d.ts +3 -0
  292. package/dist/i18n/locale-reload.js +17 -0
  293. package/dist/i18n/locale-reload.js.map +1 -0
  294. package/dist/i18n/locale-switcher.d.ts +21 -0
  295. package/dist/i18n/locale-switcher.js +25 -0
  296. package/dist/i18n/locale-switcher.js.map +1 -0
  297. package/dist/i18n/locale.d.ts +9 -0
  298. package/dist/i18n/locale.js +93 -0
  299. package/dist/i18n/locale.js.map +1 -0
  300. package/dist/i18n/page-props.d.ts +3 -0
  301. package/dist/i18n/page-props.js +24 -0
  302. package/dist/i18n/page-props.js.map +1 -0
  303. package/dist/index.d.ts +18 -8
  304. package/dist/index.js +18 -7
  305. package/dist/inertia.d.ts +2 -1
  306. package/dist/inertia.js +9 -2
  307. package/dist/inertia.js.map +1 -1
  308. package/dist/lattice.css +49 -16
  309. package/dist/layout/breadcrumbs.d.ts +3 -0
  310. package/dist/layout/breadcrumbs.js +34 -0
  311. package/dist/layout/breadcrumbs.js.map +1 -0
  312. package/dist/layout/callouts.d.ts +3 -0
  313. package/dist/layout/callouts.js +67 -0
  314. package/dist/layout/callouts.js.map +1 -0
  315. package/dist/layout/components.js +6 -0
  316. package/dist/layout/components.js.map +1 -1
  317. package/dist/layout/context.d.ts +2 -10
  318. package/dist/layout/context.js +3 -14
  319. package/dist/layout/context.js.map +1 -1
  320. package/dist/layout/dropdown.d.ts +3 -0
  321. package/dist/layout/dropdown.js +23 -0
  322. package/dist/layout/dropdown.js.map +1 -0
  323. package/dist/layout/index.d.ts +2 -1
  324. package/dist/layout/index.js +3 -1
  325. package/dist/layout/menu-item.js +30 -59
  326. package/dist/layout/menu-item.js.map +1 -1
  327. package/dist/layout/menu.js.map +1 -1
  328. package/dist/layout/outlet.js +2 -2
  329. package/dist/layout/outlet.js.map +1 -1
  330. package/dist/layout/popover.d.ts +17 -0
  331. package/dist/layout/popover.js +46 -0
  332. package/dist/layout/popover.js.map +1 -0
  333. package/dist/layout/schema-layout.js +2 -9
  334. package/dist/layout/schema-layout.js.map +1 -1
  335. package/dist/layout/sidebar.js +3 -3
  336. package/dist/layout/sidebar.js.map +1 -1
  337. package/dist/page.js +3 -9
  338. package/dist/page.js.map +1 -1
  339. package/dist/provider.d.ts +2 -4
  340. package/dist/provider.js +5 -9
  341. package/dist/provider.js.map +1 -1
  342. package/dist/registry.js +2 -1
  343. package/dist/registry.js.map +1 -1
  344. package/dist/svg-sprite-client/index.d.ts +1 -0
  345. package/dist/svg-sprite-client/index.js +0 -0
  346. package/dist/svg-sprite-client.d.ts +1 -0
  347. package/dist/table/align.d.ts +4 -0
  348. package/dist/table/align.js +23 -0
  349. package/dist/table/align.js.map +1 -0
  350. package/dist/table/bulk.js +1 -1
  351. package/dist/table/bulk.js.map +1 -1
  352. package/dist/table/components/bulk-bar.js +8 -5
  353. package/dist/table/components/bulk-bar.js.map +1 -1
  354. package/dist/table/components/cells/badge-cell.d.ts +2 -5
  355. package/dist/table/components/cells/badge-cell.js +3 -3
  356. package/dist/table/components/cells/badge-cell.js.map +1 -1
  357. package/dist/table/components/cells/boolean-cell.d.ts +3 -0
  358. package/dist/table/components/cells/boolean-cell.js +23 -0
  359. package/dist/table/components/cells/boolean-cell.js.map +1 -0
  360. package/dist/table/components/cells/icon-cell.d.ts +2 -5
  361. package/dist/table/components/cells/icon-cell.js +4 -5
  362. package/dist/table/components/cells/icon-cell.js.map +1 -1
  363. package/dist/table/components/cells/image-cell.d.ts +2 -5
  364. package/dist/table/components/cells/image-cell.js +4 -5
  365. package/dist/table/components/cells/image-cell.js.map +1 -1
  366. package/dist/table/components/cells/money-cell.d.ts +2 -0
  367. package/dist/table/components/cells/money-cell.js +28 -0
  368. package/dist/table/components/cells/money-cell.js.map +1 -0
  369. package/dist/table/components/cells/number-cell.d.ts +2 -0
  370. package/dist/table/components/cells/number-cell.js +25 -0
  371. package/dist/table/components/cells/number-cell.js.map +1 -0
  372. package/dist/table/components/cells/numeric.d.ts +2 -0
  373. package/dist/table/components/cells/numeric.js +10 -0
  374. package/dist/table/components/cells/numeric.js.map +1 -0
  375. package/dist/table/components/cells/stack-cell.d.ts +3 -0
  376. package/dist/table/components/cells/stack-cell.js +17 -0
  377. package/dist/table/components/cells/stack-cell.js.map +1 -0
  378. package/dist/table/components/cells/text-cell.d.ts +2 -6
  379. package/dist/table/components/cells/text-cell.js +5 -6
  380. package/dist/table/components/cells/text-cell.js.map +1 -1
  381. package/dist/table/components/column-filter-control.d.ts +3 -1
  382. package/dist/table/components/column-filter-control.js +73 -11
  383. package/dist/table/components/column-filter-control.js.map +1 -1
  384. package/dist/table/components/column-header.d.ts +3 -1
  385. package/dist/table/components/column-header.js +11 -8
  386. package/dist/table/components/column-header.js.map +1 -1
  387. package/dist/table/components/filter-bar.d.ts +15 -0
  388. package/dist/table/components/filter-bar.js +81 -0
  389. package/dist/table/components/filter-bar.js.map +1 -0
  390. package/dist/table/components/filter-controls.d.ts +18 -0
  391. package/dist/table/components/filter-controls.js +256 -0
  392. package/dist/table/components/filter-controls.js.map +1 -0
  393. package/dist/table/components/filter-stack-bar.js.map +1 -1
  394. package/dist/table/components/filter-value-input.d.ts +1 -0
  395. package/dist/table/components/filter-value-input.js +6 -5
  396. package/dist/table/components/filter-value-input.js.map +1 -1
  397. package/dist/table/components/pagination.js +1 -1
  398. package/dist/table/components/pagination.js.map +1 -1
  399. package/dist/table/components/sort-bar.js.map +1 -1
  400. package/dist/table/components/table-action-node.js.map +1 -1
  401. package/dist/table/components/table-cell.d.ts +1 -1
  402. package/dist/table/components/table-cell.js +18 -28
  403. package/dist/table/components/table-cell.js.map +1 -1
  404. package/dist/table/components/table.js +191 -152
  405. package/dist/table/components/table.js.map +1 -1
  406. package/dist/table/filter-values.d.ts +13 -0
  407. package/dist/table/filter-values.js +30 -0
  408. package/dist/table/filter-values.js.map +1 -0
  409. package/dist/table/format.js.map +1 -1
  410. package/dist/table/index.js.map +1 -1
  411. package/dist/table/payload.js +24 -3
  412. package/dist/table/payload.js.map +1 -1
  413. package/dist/table/query.d.ts +10 -1
  414. package/dist/table/query.js +60 -6
  415. package/dist/table/query.js.map +1 -1
  416. package/dist/table/registry.d.ts +19 -0
  417. package/dist/table/registry.js +14 -0
  418. package/dist/table/registry.js.map +1 -0
  419. package/dist/table/types.d.ts +9 -19
  420. package/dist/table/use-table.d.ts +7 -2
  421. package/dist/table/use-table.js +57 -7
  422. package/dist/table/use-table.js.map +1 -1
  423. package/dist/toast/callout.d.ts +6 -0
  424. package/dist/toast/callout.js +31 -0
  425. package/dist/toast/callout.js.map +1 -0
  426. package/dist/toast/index.d.ts +4 -0
  427. package/dist/toast/index.js +3 -1
  428. package/dist/toast/toast.d.ts +14 -0
  429. package/dist/toast/toast.js +51 -0
  430. package/dist/toast/toast.js.map +1 -0
  431. package/dist/toast/toaster.js +10 -74
  432. package/dist/toast/toaster.js.map +1 -1
  433. package/dist/toast/variant-styles.d.ts +6 -0
  434. package/dist/toast/variant-styles.js +37 -0
  435. package/dist/toast/variant-styles.js.map +1 -0
  436. package/dist/types/generated.d.ts +461 -101
  437. package/dist/types/vite-env.d.ts +1 -0
  438. package/dist/vite.d.ts +25 -0
  439. package/dist/vite.js +72 -0
  440. package/dist/vite.js.map +1 -0
  441. package/package.json +111 -13
  442. package/resources/icons/rotate-ccw.svg +16 -0
  443. package/dist/_virtual/_rolldown/runtime.js +0 -8
  444. package/dist/action/effects.d.ts +0 -11
  445. package/dist/action/effects.js +0 -44
  446. package/dist/action/effects.js.map +0 -1
  447. package/dist/node_modules/i18next/dist/esm/i18next.js +0 -1982
  448. package/dist/node_modules/i18next/dist/esm/i18next.js.map +0 -1
  449. package/dist/node_modules/i18next-http-backend/esm/index.js +0 -352
  450. package/dist/node_modules/i18next-http-backend/esm/index.js.map +0 -1
  451. package/dist/node_modules/react-i18next/dist/es/context.js +0 -23
  452. package/dist/node_modules/react-i18next/dist/es/context.js.map +0 -1
  453. package/dist/node_modules/react-i18next/dist/es/defaults.js +0 -29
  454. package/dist/node_modules/react-i18next/dist/es/defaults.js.map +0 -1
  455. package/dist/node_modules/react-i18next/dist/es/i18nInstance.js +0 -10
  456. package/dist/node_modules/react-i18next/dist/es/i18nInstance.js.map +0 -1
  457. package/dist/node_modules/react-i18next/dist/es/initReactI18next.js +0 -14
  458. package/dist/node_modules/react-i18next/dist/es/initReactI18next.js.map +0 -1
  459. package/dist/node_modules/react-i18next/dist/es/unescape.js +0 -30
  460. package/dist/node_modules/react-i18next/dist/es/unescape.js.map +0 -1
  461. package/dist/node_modules/react-i18next/dist/es/useTranslation.js +0 -157
  462. package/dist/node_modules/react-i18next/dist/es/useTranslation.js.map +0 -1
  463. package/dist/node_modules/react-i18next/dist/es/utils.js +0 -58
  464. package/dist/node_modules/react-i18next/dist/es/utils.js.map +0 -1
  465. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js +0 -70
  466. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js.map +0 -1
  467. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js +0 -61
  468. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js.map +0 -1
  469. package/dist/node_modules/use-sync-external-store/shim/index.js +0 -13
  470. package/dist/node_modules/use-sync-external-store/shim/index.js.map +0 -1
  471. package/dist/table/column-registry.d.ts +0 -9
  472. package/dist/test-support.d.ts +0 -14
  473. package/dist/test-support.js +0 -14
  474. package/dist/test-support.js.map +0 -1
  475. /package/dist/{table/column-registry.js → chat/types.js} +0 -0
  476. /package/dist/{form/components/base → core/components}/checkbox.d.ts +0 -0
package/README.md CHANGED
@@ -9,6 +9,8 @@
9
9
  <a href="https://packagist.org/packages/lattice-php/lattice"><img alt="Latest version on Packagist" src="https://img.shields.io/packagist/v/lattice-php/lattice.svg?style=flat-square"></a>
10
10
  <a href="https://www.npmjs.com/package/@lattice-php/lattice"><img alt="Latest version on npm" src="https://img.shields.io/npm/v/@lattice-php/lattice.svg?style=flat-square"></a>
11
11
  <a href="https://github.com/lattice-php/lattice/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/lattice-php/lattice/ci.yml?branch=main&label=CI&style=flat-square"></a>
12
+ <a href="https://app.codecov.io/gh/lattice-php/lattice"><img alt="Pest coverage" src="https://img.shields.io/codecov/c/github/lattice-php/lattice/main?flag=pest&label=pest&style=flat-square"></a>
13
+ <a href="https://app.codecov.io/gh/lattice-php/lattice"><img alt="Vitest coverage" src="https://img.shields.io/codecov/c/github/lattice-php/lattice/main?flag=vitest&label=vitest&style=flat-square"></a>
12
14
  <a href="https://packagist.org/packages/lattice-php/lattice"><img alt="Total downloads" src="https://img.shields.io/packagist/dt/lattice-php/lattice.svg?style=flat-square"></a>
13
15
  <a href="https://packagist.org/packages/lattice-php/lattice"><img alt="License" src="https://img.shields.io/packagist/l/lattice-php/lattice.svg?style=flat-square"></a>
14
16
  </p>
@@ -28,7 +30,7 @@ composer require lattice-php/lattice
28
30
  npm install @lattice-php/lattice
29
31
  ```
30
32
 
31
- See [Installation](https://latticephp.com/getting-started/installation/) and [Frontend Setup](https://latticephp.com/getting-started/frontend-setup/) for the full setup.
33
+ See [Installation](https://latticephp.com/introduction/installation/) for the full setup.
32
34
 
33
35
  ## Documentation
34
36
 
@@ -1,5 +1,5 @@
1
1
  import { Node } from '../../core/types';
2
- import { ActionResponse } from '../effects';
2
+ import { ActionResponse } from '../../effects/dispatch';
3
3
  type ActionFormProps = {
4
4
  cancelLabel: string;
5
5
  componentRef: string;
@@ -19,6 +19,6 @@ type ActionFormProps = {
19
19
  * Fetch a lazily-served form schema from the action endpoint while `enabled`,
20
20
  * so it can be prefilled per record. Returns null until it arrives.
21
21
  */
22
- export declare function useLazyActionForm(endpoint: string, method: string, componentRef: string, enabled: boolean): Node | null;
22
+ export declare function useLazyActionForm(endpoint: string, componentRef: string, enabled: boolean): Node | null;
23
23
  export declare function ActionForm({ description, formNode, onClose, title, ...rest }: ActionFormProps): import("react").JSX.Element;
24
24
  export {};
@@ -1,35 +1,26 @@
1
- import { withRefHeader } from "../../core/component-ref.js";
2
1
  import { Button } from "../../core/components/button.js";
3
- import { Icon } from "../../icons/sprite.js";
2
+ import { Dialog, DialogContent, DialogHeader } from "../../core/components/dialog.js";
4
3
  import { useT } from "../../i18n/instance.js";
5
4
  import { Spinner } from "../../core/components/spinner.js";
6
- import { dispatchActionError } from "../effects.js";
7
- import { Renderer, useRendererContext } from "../../core/renderer.js";
5
+ import { dispatchActionError } from "../../effects/dispatch.js";
6
+ import { apiFetch } from "../../core/api.js";
7
+ import { Skeleton } from "../../core/components/skeleton.js";
8
+ import { Renderer } from "../../core/renderer.js";
8
9
  import { FormProvider } from "../../form/components/context.js";
9
10
  import { walkFields } from "../../form/components/field-props.js";
10
- import { xsrfToken } from "../../form/components/form-transport.js";
11
+ import "../../form/components/form-transport.js";
12
+ import { PrefillProvider } from "../../form/components/prefill-context.js";
11
13
  import { ResolvedNodesProvider } from "../../form/components/resolved-nodes.js";
12
14
  import { FormValuesProvider, useFormValues } from "../../form/components/values.js";
13
15
  import { useFormResolver } from "../../form/components/use-form-resolver.js";
14
16
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
15
17
  import { jsx, jsxs } from "react/jsx-runtime";
16
- import * as Dialog from "@radix-ui/react-dialog";
17
18
  //#region resources/js/action/components/action-form.tsx
18
- function jsonHeaders(componentRef, extra) {
19
- return {
20
- Accept: "application/json",
21
- "Content-Type": "application/json",
22
- "X-Requested-With": "XMLHttpRequest",
23
- "X-XSRF-TOKEN": xsrfToken(),
24
- ...withRefHeader(componentRef),
25
- ...extra
26
- };
27
- }
28
19
  /**
29
20
  * Fetch a lazily-served form schema from the action endpoint while `enabled`,
30
21
  * so it can be prefilled per record. Returns null until it arrives.
31
22
  */
32
- function useLazyActionForm(endpoint, method, componentRef, enabled) {
23
+ function useLazyActionForm(endpoint, componentRef, enabled) {
33
24
  const [node, setNode] = useState(null);
34
25
  useEffect(() => {
35
26
  if (!enabled) {
@@ -37,18 +28,17 @@ function useLazyActionForm(endpoint, method, componentRef, enabled) {
37
28
  return;
38
29
  }
39
30
  const controller = new AbortController();
40
- fetch(endpoint, {
31
+ apiFetch(endpoint, {
41
32
  body: JSON.stringify({ _form: true }),
42
- credentials: "same-origin",
43
- headers: jsonHeaders(componentRef),
44
- method: method.toUpperCase(),
45
- signal: controller.signal
33
+ ref: componentRef,
34
+ method: "POST",
35
+ signal: controller.signal,
36
+ throwOnError: false
46
37
  }).then((response) => response.ok ? response.json() : null).then((fetched) => setNode(fetched)).catch(() => {});
47
38
  return () => controller.abort();
48
39
  }, [
49
40
  enabled,
50
41
  endpoint,
51
- method,
52
42
  componentRef
53
43
  ]);
54
44
  return node;
@@ -63,9 +53,9 @@ function ActionFormSkeleton() {
63
53
  className: "space-y-4",
64
54
  "data-lattice-action-form-loading": true,
65
55
  children: [
66
- /* @__PURE__ */ jsx("div", { className: "h-4 w-24 animate-pulse rounded bg-lt-muted" }),
67
- /* @__PURE__ */ jsx("div", { className: "h-10 w-full animate-pulse rounded bg-lt-muted" }),
68
- /* @__PURE__ */ jsx("div", { className: "h-10 w-full animate-pulse rounded bg-lt-muted" })
56
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
57
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
58
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
69
59
  ]
70
60
  });
71
61
  }
@@ -86,24 +76,24 @@ function collectFields(formNode) {
86
76
  };
87
77
  }
88
78
  function ActionFormBody({ cancelLabel, componentRef, endpoint, extraData, fieldLabels, formNode, method, onClose, onSuccess, precognitive, submitLabel }) {
89
- const { fallback, missingComponent, registry } = useRendererContext();
90
79
  const values = useFormValues();
91
80
  const valuesRef = useRef(values);
92
81
  valuesRef.current = values;
93
82
  const extraDataRef = useRef(extraData);
94
83
  extraDataRef.current = extraData;
95
- const resolvedNodes = useFormResolver(endpoint, componentRef, formNode.schema);
84
+ const { nodes: resolvedNodes, markUserEdit } = useFormResolver(endpoint, componentRef, formNode.schema);
96
85
  const [errors, setErrors] = useState({});
97
86
  const [processing, setProcessing] = useState(false);
98
87
  const timer = useRef(void 0);
99
- const request = useCallback((extraHeaders) => fetch(endpoint, {
88
+ const request = useCallback((extraHeaders) => apiFetch(endpoint, {
100
89
  body: JSON.stringify({
101
90
  ...valuesRef.current,
102
91
  ...extraDataRef.current
103
92
  }),
104
- credentials: "same-origin",
105
- method: method.toUpperCase(),
106
- headers: jsonHeaders(componentRef, extraHeaders)
93
+ method,
94
+ ref: componentRef,
95
+ headers: extraHeaders,
96
+ throwOnError: false
107
97
  }), [
108
98
  componentRef,
109
99
  endpoint,
@@ -179,13 +169,11 @@ function ActionFormBody({ cancelLabel, componentRef, endpoint, extraData, fieldL
179
169
  event.preventDefault();
180
170
  submit();
181
171
  },
182
- children: [/* @__PURE__ */ jsx(ResolvedNodesProvider, {
183
- nodes: resolvedNodes,
184
- children: /* @__PURE__ */ jsx(Renderer, {
185
- fallback,
186
- missingComponent,
187
- nodes: formNode.schema ?? [],
188
- registry
172
+ children: [/* @__PURE__ */ jsx(PrefillProvider, {
173
+ value: { markUserEdit },
174
+ children: /* @__PURE__ */ jsx(ResolvedNodesProvider, {
175
+ nodes: resolvedNodes,
176
+ children: /* @__PURE__ */ jsx(Renderer, { nodes: formNode.schema ?? [] })
189
177
  })
190
178
  }), /* @__PURE__ */ jsxs("div", {
191
179
  className: "flex justify-end gap-3",
@@ -221,38 +209,18 @@ function ActionFormContent({ formNode, ...rest }) {
221
209
  }
222
210
  function ActionForm({ description, formNode, onClose, title, ...rest }) {
223
211
  const { t } = useT("lattice");
224
- return /* @__PURE__ */ jsx(Dialog.Root, {
212
+ return /* @__PURE__ */ jsx(Dialog, {
225
213
  open: true,
226
214
  onOpenChange: (open) => {
227
215
  if (!open) onClose();
228
216
  },
229
- children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/50" }), /* @__PURE__ */ jsxs(Dialog.Content, {
217
+ children: /* @__PURE__ */ jsxs(DialogContent, {
230
218
  ...description ? {} : { "aria-describedby": void 0 },
231
- className: "fixed left-1/2 top-1/2 z-50 max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lt border border-lt-border bg-lt-bg p-6 shadow-lg",
232
- children: [/* @__PURE__ */ jsxs("div", {
233
- className: "flex items-start justify-between gap-4",
234
- children: [/* @__PURE__ */ jsxs("div", {
235
- className: "grid gap-2",
236
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
237
- className: "text-lg font-semibold leading-none tracking-tight",
238
- children: title
239
- }), description && /* @__PURE__ */ jsx(Dialog.Description, {
240
- className: "text-sm text-lt-muted-fg",
241
- children: description
242
- })]
243
- }), /* @__PURE__ */ jsx(Dialog.Close, {
244
- asChild: true,
245
- children: /* @__PURE__ */ jsx(Button, {
246
- "aria-label": t("a11y.close", "Close"),
247
- size: "icon",
248
- variant: "ghost",
249
- children: /* @__PURE__ */ jsx(Icon, {
250
- name: "x",
251
- "aria-hidden": "true",
252
- className: "size-lt-icon-md"
253
- })
254
- })
255
- })]
219
+ className: "max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg overflow-y-auto",
220
+ children: [/* @__PURE__ */ jsx(DialogHeader, {
221
+ closeLabel: t("a11y.close", "Close"),
222
+ description,
223
+ title
256
224
  }), /* @__PURE__ */ jsx("div", {
257
225
  className: "mt-6",
258
226
  children: formNode ? /* @__PURE__ */ jsx(ActionFormContent, {
@@ -261,7 +229,7 @@ function ActionForm({ description, formNode, onClose, title, ...rest }) {
261
229
  ...rest
262
230
  }) : /* @__PURE__ */ jsx(ActionFormSkeleton, {})
263
231
  })]
264
- })] })
232
+ })
265
233
  });
266
234
  }
267
235
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"action-form.js","names":[],"sources":["../../../resources/js/action/components/action-form.tsx"],"sourcesContent":["import { Icon } from \"@lattice/lattice/icons\";\nimport * as Dialog from \"@radix-ui/react-dialog\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { withRefHeader } from \"@lattice/lattice/core/component-ref\";\nimport { Button } from \"@lattice/lattice/core/components/button\";\nimport { Spinner } from \"@lattice/lattice/core/components/spinner\";\nimport { Renderer, useRendererContext } from \"@lattice/lattice/core/renderer\";\nimport type { Node } from \"@lattice/lattice/core/types\";\nimport { FormProvider } from \"@lattice/lattice/form/components/context\";\nimport { walkFields } from \"@lattice/lattice/form/components/field-props\";\nimport { FORM_DEBOUNCE_MS, xsrfToken } from \"@lattice/lattice/form/components/form-transport\";\nimport { ResolvedNodesProvider } from \"@lattice/lattice/form/components/resolved-nodes\";\nimport { useFormResolver } from \"@lattice/lattice/form/components/use-form-resolver\";\nimport { FormValuesProvider, useFormValues } from \"@lattice/lattice/form/components/values\";\nimport { useT } from \"@lattice/lattice/i18n\";\nimport { dispatchActionError } from \"../effects\";\nimport type { ActionResponse } from \"../effects\";\n\ntype FieldErrors = Record<string, string | undefined>;\n\ntype ActionFormProps = {\n cancelLabel: string;\n componentRef: string;\n description?: string;\n endpoint: string;\n /** Extra payload merged into every request, e.g. a bulk action's selection. */\n extraData?: Record<string, unknown>;\n /** The form to render; null while a lazy schema is still being fetched. */\n formNode: Node | null;\n method: string;\n onClose: () => void;\n onSuccess: (response: ActionResponse) => void;\n submitLabel: string;\n title: string;\n};\n\nfunction jsonHeaders(componentRef: string, extra?: Record<string, string>): Record<string, string> {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"X-XSRF-TOKEN\": xsrfToken(),\n ...withRefHeader(componentRef),\n ...extra,\n };\n}\n\n/**\n * Fetch a lazily-served form schema from the action endpoint while `enabled`,\n * so it can be prefilled per record. Returns null until it arrives.\n */\nexport function useLazyActionForm(\n endpoint: string,\n method: string,\n componentRef: string,\n enabled: boolean,\n): Node | null {\n const [node, setNode] = useState<Node | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n setNode(null);\n\n return;\n }\n\n const controller = new AbortController();\n\n void fetch(endpoint, {\n body: JSON.stringify({ _form: true }),\n credentials: \"same-origin\",\n headers: jsonHeaders(componentRef),\n method: method.toUpperCase(),\n signal: controller.signal,\n })\n .then((response) => (response.ok ? (response.json() as Promise<Node>) : null))\n .then((fetched) => setNode(fetched))\n .catch(() => {});\n\n return () => controller.abort();\n }, [enabled, endpoint, method, componentRef]);\n\n return node;\n}\n\nfunction firstErrors(errors: Record<string, string[] | string> | undefined): FieldErrors {\n const result: FieldErrors = {};\n\n for (const [key, value] of Object.entries(errors ?? {})) {\n result[key] = Array.isArray(value) ? value[0] : value;\n }\n\n return result;\n}\n\nfunction ActionFormSkeleton() {\n return (\n <div className=\"space-y-4\" data-lattice-action-form-loading>\n <div className=\"h-4 w-24 animate-pulse rounded bg-lt-muted\" />\n <div className=\"h-10 w-full animate-pulse rounded bg-lt-muted\" />\n <div className=\"h-10 w-full animate-pulse rounded bg-lt-muted\" />\n </div>\n );\n}\n\ntype CollectedFields = {\n labels: Record<string, string>;\n values: Record<string, unknown>;\n};\n\nfunction collectFields(formNode: Node): CollectedFields {\n const labels: Record<string, string> = {};\n const values: Record<string, unknown> = {};\n\n walkFields(formNode.schema, (props) => {\n if (!props.name) {\n return;\n }\n if (props.label) {\n labels[props.name] = props.label;\n }\n if (props.value !== undefined) {\n values[props.name] = props.value;\n }\n });\n\n return {\n labels,\n values: { ...values, ...(formNode.props?.state as Record<string, unknown> | undefined) },\n };\n}\n\nfunction ActionFormBody({\n cancelLabel,\n componentRef,\n endpoint,\n extraData,\n fieldLabels,\n formNode,\n method,\n onClose,\n onSuccess,\n precognitive,\n submitLabel,\n}: Omit<ActionFormProps, \"description\" | \"title\"> & {\n fieldLabels: Record<string, string>;\n formNode: Node;\n precognitive: boolean;\n}) {\n const { fallback, missingComponent, registry } = useRendererContext();\n const values = useFormValues();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n const extraDataRef = useRef(extraData);\n extraDataRef.current = extraData;\n const resolvedNodes = useFormResolver(endpoint, componentRef, formNode.schema);\n\n const [errors, setErrors] = useState<FieldErrors>({});\n const [processing, setProcessing] = useState(false);\n const timer = useRef<number | undefined>(undefined);\n\n const request = useCallback(\n (extraHeaders?: Record<string, string>): Promise<Response> =>\n fetch(endpoint, {\n body: JSON.stringify({ ...valuesRef.current, ...extraDataRef.current }),\n credentials: \"same-origin\",\n // fetch only upper-cases the standardized methods, leaving PATCH/DELETE as\n // given; some servers reject a lower-case method line, so normalize it.\n method: method.toUpperCase(),\n headers: jsonHeaders(componentRef, extraHeaders),\n }),\n [componentRef, endpoint, method],\n );\n\n const clearErrors = useCallback((field: string) => {\n setErrors((current) =>\n current[field] === undefined ? current : { ...current, [field]: undefined },\n );\n }, []);\n\n const validate = useCallback(\n (field: string) => {\n if (!precognitive) {\n return;\n }\n\n window.clearTimeout(timer.current);\n timer.current = window.setTimeout(() => {\n void request({ Precognition: \"true\", \"Precognition-Validate-Only\": field })\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors((current) => ({ ...current, ...firstErrors(body.errors) }));\n\n return;\n }\n\n clearErrors(field);\n })\n .catch(() => {});\n }, FORM_DEBOUNCE_MS);\n },\n [clearErrors, precognitive, request],\n );\n\n const submit = useCallback(() => {\n setProcessing(true);\n\n void request()\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors(firstErrors(body.errors));\n\n return;\n }\n\n if (!response.ok) {\n dispatchActionError(new Error(`Action request failed with status ${response.status}`));\n\n return;\n }\n\n onSuccess((await response.json()) as ActionResponse);\n })\n .catch((error: unknown) => dispatchActionError(error))\n .finally(() => setProcessing(false));\n }, [onSuccess, request]);\n\n const context = useMemo(\n () => ({\n action: endpoint,\n clearErrors,\n componentRef,\n errors,\n fieldLabels,\n precognitive,\n processing,\n validate,\n }),\n [clearErrors, componentRef, endpoint, errors, fieldLabels, precognitive, processing, validate],\n );\n\n return (\n <FormProvider value={context}>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n <ResolvedNodesProvider nodes={resolvedNodes}>\n <Renderer\n fallback={fallback}\n missingComponent={missingComponent}\n nodes={formNode.schema ?? []}\n registry={registry}\n />\n </ResolvedNodesProvider>\n\n <div className=\"flex justify-end gap-3\">\n <Button\n data-test=\"action-form-cancel\"\n disabled={processing}\n onClick={onClose}\n type=\"button\"\n variant=\"ghost\"\n >\n {cancelLabel}\n </Button>\n\n <Button data-test=\"action-form-submit\" disabled={processing} type=\"submit\">\n {processing && <Spinner />}\n {submitLabel}\n </Button>\n </div>\n </form>\n </FormProvider>\n );\n}\n\nfunction ActionFormContent({\n formNode,\n ...rest\n}: Omit<ActionFormProps, \"description\" | \"title\"> & { formNode: Node }) {\n const precognitive = Boolean(formNode.props?.precognitive);\n const { labels: fieldLabels, values: initialValues } = useMemo(\n () => collectFields(formNode),\n [formNode],\n );\n\n return (\n <FormValuesProvider initial={initialValues}>\n <ActionFormBody\n fieldLabels={fieldLabels}\n formNode={formNode}\n precognitive={precognitive}\n {...rest}\n />\n </FormValuesProvider>\n );\n}\n\nexport function ActionForm({ description, formNode, onClose, title, ...rest }: ActionFormProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <Dialog.Root\n open\n onOpenChange={(open) => {\n if (!open) {\n onClose();\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-50 bg-black/50\" />\n <Dialog.Content\n {...(description ? {} : { \"aria-describedby\": undefined })}\n className=\"fixed left-1/2 top-1/2 z-50 max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lt border border-lt-border bg-lt-bg p-6 shadow-lg\"\n >\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"grid gap-2\">\n <Dialog.Title className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </Dialog.Title>\n\n {description && (\n <Dialog.Description className=\"text-sm text-lt-muted-fg\">\n {description}\n </Dialog.Description>\n )}\n </div>\n\n <Dialog.Close asChild>\n <Button aria-label={t(\"a11y.close\", \"Close\")} size=\"icon\" variant=\"ghost\">\n <Icon name=\"x\" aria-hidden=\"true\" className=\"size-lt-icon-md\" />\n </Button>\n </Dialog.Close>\n </div>\n\n <div className=\"mt-6\">\n {formNode ? (\n <ActionFormContent formNode={formNode} onClose={onClose} {...rest} />\n ) : (\n <ActionFormSkeleton />\n )}\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"action-form.js","names":[],"sources":["../../../resources/js/action/components/action-form.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { Dialog, DialogContent, DialogHeader } from \"@lattice-php/lattice/core/components/dialog\";\nimport { Skeleton } from \"@lattice-php/lattice/core/components/skeleton\";\nimport { Spinner } from \"@lattice-php/lattice/core/components/spinner\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { FormProvider } from \"@lattice-php/lattice/form/components/context\";\nimport { walkFields } from \"@lattice-php/lattice/form/components/field-props\";\nimport { FORM_DEBOUNCE_MS } from \"@lattice-php/lattice/form/components/form-transport\";\nimport { PrefillProvider } from \"@lattice-php/lattice/form/components/prefill-context\";\nimport { ResolvedNodesProvider } from \"@lattice-php/lattice/form/components/resolved-nodes\";\nimport { useFormResolver } from \"@lattice-php/lattice/form/components/use-form-resolver\";\nimport { FormValuesProvider, useFormValues } from \"@lattice-php/lattice/form/components/values\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { dispatchActionError } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\n\ntype FieldErrors = Record<string, string | undefined>;\n\ntype ActionFormProps = {\n cancelLabel: string;\n componentRef: string;\n description?: string;\n endpoint: string;\n /** Extra payload merged into every request, e.g. a bulk action's selection. */\n extraData?: Record<string, unknown>;\n /** The form to render; null while a lazy schema is still being fetched. */\n formNode: Node | null;\n method: string;\n onClose: () => void;\n onSuccess: (response: ActionResponse) => void;\n submitLabel: string;\n title: string;\n};\n\n/**\n * Fetch a lazily-served form schema from the action endpoint while `enabled`,\n * so it can be prefilled per record. Returns null until it arrives.\n */\nexport function useLazyActionForm(\n endpoint: string,\n componentRef: string,\n enabled: boolean,\n): Node | null {\n const [node, setNode] = useState<Node | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n setNode(null);\n\n return;\n }\n\n const controller = new AbortController();\n\n void apiFetch(endpoint, {\n body: JSON.stringify({ _form: true }),\n ref: componentRef,\n method: \"POST\",\n signal: controller.signal,\n throwOnError: false,\n })\n .then((response) => (response.ok ? (response.json() as Promise<Node>) : null))\n .then((fetched) => setNode(fetched))\n .catch(() => {});\n\n return () => controller.abort();\n }, [enabled, endpoint, componentRef]);\n\n return node;\n}\n\nfunction firstErrors(errors: Record<string, string[] | string> | undefined): FieldErrors {\n const result: FieldErrors = {};\n\n for (const [key, value] of Object.entries(errors ?? {})) {\n result[key] = Array.isArray(value) ? value[0] : value;\n }\n\n return result;\n}\n\nfunction ActionFormSkeleton() {\n return (\n <div className=\"space-y-4\" data-lattice-action-form-loading>\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n );\n}\n\ntype CollectedFields = {\n labels: Record<string, string>;\n values: Record<string, unknown>;\n};\n\nfunction collectFields(formNode: Node): CollectedFields {\n const labels: Record<string, string> = {};\n const values: Record<string, unknown> = {};\n\n walkFields(formNode.schema, (props) => {\n if (!props.name) {\n return;\n }\n if (props.label) {\n labels[props.name] = props.label;\n }\n if (props.value !== undefined) {\n values[props.name] = props.value;\n }\n });\n\n return {\n labels,\n values: { ...values, ...(formNode.props?.state as Record<string, unknown> | undefined) },\n };\n}\n\nfunction ActionFormBody({\n cancelLabel,\n componentRef,\n endpoint,\n extraData,\n fieldLabels,\n formNode,\n method,\n onClose,\n onSuccess,\n precognitive,\n submitLabel,\n}: Omit<ActionFormProps, \"description\" | \"title\"> & {\n fieldLabels: Record<string, string>;\n formNode: Node;\n precognitive: boolean;\n}) {\n const values = useFormValues();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n const extraDataRef = useRef(extraData);\n extraDataRef.current = extraData;\n const { nodes: resolvedNodes, markUserEdit } = useFormResolver(\n endpoint,\n componentRef,\n formNode.schema,\n );\n\n const [errors, setErrors] = useState<FieldErrors>({});\n const [processing, setProcessing] = useState(false);\n const timer = useRef<number | undefined>(undefined);\n\n const request = useCallback(\n (extraHeaders?: Record<string, string>): Promise<Response> =>\n apiFetch(endpoint, {\n body: JSON.stringify({ ...valuesRef.current, ...extraDataRef.current }),\n method,\n ref: componentRef,\n headers: extraHeaders,\n throwOnError: false,\n }),\n [componentRef, endpoint, method],\n );\n\n const clearErrors = useCallback((field: string) => {\n setErrors((current) =>\n current[field] === undefined ? current : { ...current, [field]: undefined },\n );\n }, []);\n\n const validate = useCallback(\n (field: string) => {\n if (!precognitive) {\n return;\n }\n\n window.clearTimeout(timer.current);\n timer.current = window.setTimeout(() => {\n void request({ Precognition: \"true\", \"Precognition-Validate-Only\": field })\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors((current) => ({ ...current, ...firstErrors(body.errors) }));\n\n return;\n }\n\n clearErrors(field);\n })\n .catch(() => {});\n }, FORM_DEBOUNCE_MS);\n },\n [clearErrors, precognitive, request],\n );\n\n const submit = useCallback(() => {\n setProcessing(true);\n\n void request()\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors(firstErrors(body.errors));\n\n return;\n }\n\n if (!response.ok) {\n dispatchActionError(new Error(`Action request failed with status ${response.status}`));\n\n return;\n }\n\n onSuccess((await response.json()) as ActionResponse);\n })\n .catch((error: unknown) => dispatchActionError(error))\n .finally(() => setProcessing(false));\n }, [onSuccess, request]);\n\n const context = useMemo(\n () => ({\n action: endpoint,\n clearErrors,\n componentRef,\n errors,\n fieldLabels,\n precognitive,\n processing,\n validate,\n }),\n [clearErrors, componentRef, endpoint, errors, fieldLabels, precognitive, processing, validate],\n );\n\n return (\n <FormProvider value={context}>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n <PrefillProvider value={{ markUserEdit }}>\n <ResolvedNodesProvider nodes={resolvedNodes}>\n <Renderer nodes={formNode.schema ?? []} />\n </ResolvedNodesProvider>\n </PrefillProvider>\n\n <div className=\"flex justify-end gap-3\">\n <Button\n data-test=\"action-form-cancel\"\n disabled={processing}\n onClick={onClose}\n type=\"button\"\n variant=\"ghost\"\n >\n {cancelLabel}\n </Button>\n\n <Button data-test=\"action-form-submit\" disabled={processing} type=\"submit\">\n {processing && <Spinner />}\n {submitLabel}\n </Button>\n </div>\n </form>\n </FormProvider>\n );\n}\n\nfunction ActionFormContent({\n formNode,\n ...rest\n}: Omit<ActionFormProps, \"description\" | \"title\"> & { formNode: Node }) {\n const precognitive = Boolean(formNode.props?.precognitive);\n const { labels: fieldLabels, values: initialValues } = useMemo(\n () => collectFields(formNode),\n [formNode],\n );\n\n return (\n <FormValuesProvider initial={initialValues}>\n <ActionFormBody\n fieldLabels={fieldLabels}\n formNode={formNode}\n precognitive={precognitive}\n {...rest}\n />\n </FormValuesProvider>\n );\n}\n\nexport function ActionForm({ description, formNode, onClose, title, ...rest }: ActionFormProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) {\n onClose();\n }\n }}\n >\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n className=\"max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg overflow-y-auto\"\n >\n <DialogHeader\n closeLabel={t(\"a11y.close\", \"Close\")}\n description={description}\n title={title}\n />\n\n <div className=\"mt-6\">\n {formNode ? (\n <ActionFormContent formNode={formNode} onClose={onClose} {...rest} />\n ) : (\n <ActionFormSkeleton />\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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"}
@@ -1,18 +1,30 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { nodeIdentity } from "../../core/test-id.js";
1
3
  import { Button } from "../../core/components/button.js";
2
4
  import { Icon } from "../../icons/sprite.js";
5
+ import { ActionMenuProvider } from "./action-menu-context.js";
6
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../../core/components/dropdown-menu.js";
3
7
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import * as Popover from "@radix-ui/react-popover";
5
8
  //#region resources/js/action/components/action-group.tsx
6
9
  var ActionGroupComponent = ({ children, node }) => {
7
10
  const label = node.props.label;
11
+ const orientation = node.props.orientation;
12
+ if (orientation) return /* @__PURE__ */ jsx("div", {
13
+ "aria-label": label,
14
+ className: cn("inline-flex max-w-full gap-1", orientation === "vertical" ? "flex-col items-stretch" : "flex-row flex-wrap items-center"),
15
+ "data-lattice-component": node.id,
16
+ role: "group",
17
+ children
18
+ });
8
19
  return /* @__PURE__ */ jsx("div", {
9
20
  className: "inline-flex",
10
21
  "data-lattice-component": node.id,
11
- children: /* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(Popover.Trigger, {
22
+ children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
12
23
  asChild: true,
13
24
  children: /* @__PURE__ */ jsx(Button, {
14
25
  "aria-label": label,
15
26
  className: "size-8 text-lt-muted-fg shadow-none hover:text-lt-fg",
27
+ "data-test": nodeIdentity(node),
16
28
  size: "icon",
17
29
  type: "button",
18
30
  variant: "ghost",
@@ -22,13 +34,13 @@ var ActionGroupComponent = ({ children, node }) => {
22
34
  className: "size-lt-icon-md"
23
35
  })
24
36
  })
25
- }), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Content, {
37
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
26
38
  align: "end",
27
39
  "aria-label": label,
28
- className: "z-50 grid min-w-40 gap-1 rounded-lt-sm border border-lt-border bg-lt-popover p-1 text-lt-popover-fg shadow-md [&>button]:w-full [&>button]:justify-start",
40
+ className: "min-w-44 gap-0.5 p-1.5",
29
41
  sideOffset: 8,
30
- children
31
- }) })] })
42
+ children: /* @__PURE__ */ jsx(ActionMenuProvider, { children })
43
+ })] })
32
44
  });
33
45
  };
34
46
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"action-group.js","names":[],"sources":["../../../resources/js/action/components/action-group.tsx"],"sourcesContent":["import { Icon } from \"@lattice/lattice/icons\";\nimport * as Popover from \"@radix-ui/react-popover\";\nimport { Button } from \"@lattice/lattice/core/components/button\";\nimport type { RendererComponent } from \"@lattice/lattice/core/types\";\n\nconst ActionGroupComponent: RendererComponent<\"action.group\"> = ({ children, node }) => {\n const label = node.props.label;\n\n return (\n <div className=\"inline-flex\" data-lattice-component={node.id}>\n <Popover.Root>\n <Popover.Trigger asChild>\n <Button\n aria-label={label}\n className=\"size-8 text-lt-muted-fg shadow-none hover:text-lt-fg\"\n size=\"icon\"\n type=\"button\"\n variant=\"ghost\"\n >\n <Icon name=\"more-horizontal\" aria-hidden=\"true\" className=\"size-lt-icon-md\" />\n </Button>\n </Popover.Trigger>\n\n <Popover.Portal>\n <Popover.Content\n align=\"end\"\n aria-label={label}\n className=\"z-50 grid min-w-40 gap-1 rounded-lt-sm border border-lt-border bg-lt-popover p-1 text-lt-popover-fg shadow-md [&>button]:w-full [&>button]:justify-start\"\n sideOffset={8}\n >\n {children}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n </div>\n );\n};\n\nexport default ActionGroupComponent;\n"],"mappings":";;;;;AAKA,IAAM,wBAA2D,EAAE,UAAU,WAAW;CACtF,MAAM,QAAQ,KAAK,MAAM;CAEzB,OACE,oBAAC,OAAD;EAAK,WAAU;EAAc,0BAAwB,KAAK;YACxD,qBAAC,QAAQ,MAAT,EAAA,UAAA,CACE,oBAAC,QAAQ,SAAT;GAAiB,SAAA;aACf,oBAAC,QAAD;IACE,cAAY;IACZ,WAAU;IACV,MAAK;IACL,MAAK;IACL,SAAQ;cAER,oBAAC,MAAD;KAAM,MAAK;KAAkB,eAAY;KAAO,WAAU;IAAmB,CAAA;GACvE,CAAA;EACO,CAAA,GAEjB,oBAAC,QAAQ,QAAT,EAAA,UACE,oBAAC,QAAQ,SAAT;GACE,OAAM;GACN,cAAY;GACZ,WAAU;GACV,YAAY;GAEX;EACc,CAAA,EACH,CAAA,CACJ,EAAA,CAAA;CACX,CAAA;AAET"}
1
+ {"version":3,"file":"action-group.js","names":[],"sources":["../../../resources/js/action/components/action-group.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n} from \"@lattice-php/lattice/core/components/dropdown-menu\";\nimport { nodeIdentity } 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 { ActionMenuProvider } from \"./action-menu-context\";\n\nconst ActionGroupComponent: RendererComponent<\"action.group\"> = ({ children, node }) => {\n const label = node.props.label;\n const orientation = node.props.orientation;\n\n if (orientation) {\n return (\n <div\n aria-label={label}\n className={cn(\n \"inline-flex max-w-full gap-1\",\n orientation === \"vertical\" ? \"flex-col items-stretch\" : \"flex-row flex-wrap items-center\",\n )}\n data-lattice-component={node.id}\n role=\"group\"\n >\n {children}\n </div>\n );\n }\n\n return (\n <div className=\"inline-flex\" data-lattice-component={node.id}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n aria-label={label}\n className=\"size-8 text-lt-muted-fg shadow-none hover:text-lt-fg\"\n data-test={nodeIdentity(node)}\n size=\"icon\"\n type=\"button\"\n variant=\"ghost\"\n >\n <Icon name=\"more-horizontal\" aria-hidden=\"true\" className=\"size-lt-icon-md\" />\n </Button>\n </DropdownMenuTrigger>\n\n <DropdownMenuContent\n align=\"end\"\n aria-label={label}\n className=\"min-w-44 gap-0.5 p-1.5\"\n sideOffset={8}\n >\n <ActionMenuProvider>{children}</ActionMenuProvider>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n );\n};\n\nexport default ActionGroupComponent;\n"],"mappings":";;;;;;;;AAYA,IAAM,wBAA2D,EAAE,UAAU,WAAW;CACtF,MAAM,QAAQ,KAAK,MAAM;CACzB,MAAM,cAAc,KAAK,MAAM;CAE/B,IAAI,aACF,OACE,oBAAC,OAAD;EACE,cAAY;EACZ,WAAW,GACT,gCACA,gBAAgB,aAAa,2BAA2B,iCAC1D;EACA,0BAAwB,KAAK;EAC7B,MAAK;EAEJ;CACE,CAAA;CAIT,OACE,oBAAC,OAAD;EAAK,WAAU;EAAc,0BAAwB,KAAK;YACxD,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,qBAAD;GAAqB,SAAA;aACnB,oBAAC,QAAD;IACE,cAAY;IACZ,WAAU;IACV,aAAW,aAAa,IAAI;IAC5B,MAAK;IACL,MAAK;IACL,SAAQ;cAER,oBAAC,MAAD;KAAM,MAAK;KAAkB,eAAY;KAAO,WAAU;IAAmB,CAAA;GACvE,CAAA;EACW,CAAA,GAErB,oBAAC,qBAAD;GACE,OAAM;GACN,cAAY;GACZ,WAAU;GACV,YAAY;aAEZ,oBAAC,oBAAD,EAAqB,SAA6B,CAAA;EAC/B,CAAA,CACT,EAAA,CAAA;CACX,CAAA;AAET"}
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ export declare const actionMenuItemClassName = "flex h-8 w-full items-center justify-start gap-2 rounded-lt-sm px-2.5 text-left text-sm font-normal text-lt-popover-fg no-underline decoration-transparent shadow-none transition-colors hover:bg-lt-accent/70 hover:text-lt-popover-fg focus-visible:bg-lt-accent/70 focus-visible:text-lt-popover-fg focus-visible:ring-0 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-lt-icon-sm [&_svg]:text-lt-muted-fg";
3
+ export declare function ActionMenuProvider({ children }: {
4
+ children: ReactNode;
5
+ }): import("react").JSX.Element;
6
+ export declare function useActionMenu(): boolean;
@@ -0,0 +1,18 @@
1
+ import { createContext, useContext } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region resources/js/action/components/action-menu-context.tsx
4
+ var ActionMenuContext = createContext(false);
5
+ var actionMenuItemClassName = "flex h-8 w-full items-center justify-start gap-2 rounded-lt-sm px-2.5 text-left text-sm font-normal text-lt-popover-fg no-underline decoration-transparent shadow-none transition-colors hover:bg-lt-accent/70 hover:text-lt-popover-fg focus-visible:bg-lt-accent/70 focus-visible:text-lt-popover-fg focus-visible:ring-0 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-lt-icon-sm [&_svg]:text-lt-muted-fg";
6
+ function ActionMenuProvider({ children }) {
7
+ return /* @__PURE__ */ jsx(ActionMenuContext.Provider, {
8
+ value: true,
9
+ children
10
+ });
11
+ }
12
+ function useActionMenu() {
13
+ return useContext(ActionMenuContext);
14
+ }
15
+ //#endregion
16
+ export { ActionMenuProvider, actionMenuItemClassName, useActionMenu };
17
+
18
+ //# sourceMappingURL=action-menu-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-menu-context.js","names":[],"sources":["../../../resources/js/action/components/action-menu-context.tsx"],"sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\n\nconst ActionMenuContext = createContext(false);\n\nexport const actionMenuItemClassName =\n \"flex h-8 w-full items-center justify-start gap-2 rounded-lt-sm px-2.5 text-left text-sm font-normal text-lt-popover-fg no-underline decoration-transparent shadow-none transition-colors hover:bg-lt-accent/70 hover:text-lt-popover-fg focus-visible:bg-lt-accent/70 focus-visible:text-lt-popover-fg focus-visible:ring-0 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-lt-icon-sm [&_svg]:text-lt-muted-fg\";\n\nexport function ActionMenuProvider({ children }: { children: ReactNode }) {\n return <ActionMenuContext.Provider value={true}>{children}</ActionMenuContext.Provider>;\n}\n\nexport function useActionMenu(): boolean {\n return useContext(ActionMenuContext);\n}\n"],"mappings":";;;AAEA,IAAM,oBAAoB,cAAc,KAAK;AAE7C,IAAa,0BACX;AAEF,SAAgB,mBAAmB,EAAE,YAAqC;CACxE,OAAO,oBAAC,kBAAkB,UAAnB;EAA4B,OAAO;EAAO;CAAqC,CAAA;AACxF;AAEA,SAAgB,gBAAyB;CACvC,OAAO,WAAW,iBAAiB;AACrC"}
@@ -1,13 +1,16 @@
1
- import { withRefHeader } from "../../core/component-ref.js";
1
+ import { withHeaders } from "../../core/headers.js";
2
+ import { prefixedTestId } from "../../core/test-id.js";
2
3
  import { Button } from "../../core/components/button.js";
3
4
  import { IconRenderer } from "../../icons/icon-renderer.js";
4
5
  import { Spinner } from "../../core/components/spinner.js";
5
6
  import { ConfirmDialog } from "../../core/components/confirm-dialog.js";
6
- import { dispatchActionEffects, dispatchActionError, getActionEffects } from "../effects.js";
7
+ import { dispatchActionError, getActionEffects } from "../../effects/dispatch.js";
8
+ import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
7
9
  import { ActionForm, useLazyActionForm } from "./action-form.js";
10
+ import { actionMenuItemClassName, useActionMenu } from "./action-menu-context.js";
8
11
  import { useState } from "react";
9
12
  import { router, useHttp } from "@inertiajs/react";
10
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
14
  //#region resources/js/action/components/action.tsx
12
15
  var ActionComponent = ({ node }) => {
13
16
  const endpoint = node.props.endpoint ?? "";
@@ -16,25 +19,27 @@ var ActionComponent = ({ node }) => {
16
19
  const componentRef = node.props.ref ?? "";
17
20
  const method = node.props.method ?? "post";
18
21
  const http = useHttp({});
22
+ const dispatch = useEffectDispatcher();
19
23
  const [isConfirming, setIsConfirming] = useState(false);
20
24
  const [isFilling, setIsFilling] = useState(false);
25
+ const isMenuItem = useActionMenu();
21
26
  const confirmation = node.props.confirmation;
22
27
  const variant = node.props.variant ?? "default";
23
28
  const inlineForm = node.props.form;
24
29
  const lazyForm = node.props.lazyForm === true;
25
30
  const hasForm = Boolean(inlineForm) || lazyForm;
26
- const lazyNode = useLazyActionForm(endpoint, method, componentRef, isFilling && lazyForm);
31
+ const lazyNode = useLazyActionForm(endpoint, componentRef, isFilling && lazyForm);
27
32
  const formNode = lazyForm ? lazyNode : inlineForm;
28
33
  const submit = async () => {
29
34
  if (!endpoint) return;
30
35
  try {
31
36
  if (method === "get") {
32
- router.visit(endpoint, { headers: withRefHeader(componentRef) });
37
+ router.visit(endpoint, { headers: withHeaders(componentRef) });
33
38
  setIsConfirming(false);
34
39
  return;
35
40
  }
36
- const responseEffects = getActionEffects((await http[method](endpoint, { headers: withRefHeader(componentRef) })).effects);
37
- dispatchActionEffects(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));
41
+ const responseEffects = getActionEffects((await http[method](endpoint, { headers: withHeaders(componentRef) })).effects);
42
+ dispatch(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));
38
43
  setIsConfirming(false);
39
44
  } catch (error) {
40
45
  dispatchActionError(error);
@@ -54,16 +59,18 @@ var ActionComponent = ({ node }) => {
54
59
  const confirmationTitle = confirmation?.title ?? label;
55
60
  const confirmationConfirmLabel = confirmation?.confirmLabel ?? label;
56
61
  const confirmationCancelLabel = confirmation?.cancelLabel ?? "Cancel";
57
- return /* @__PURE__ */ jsxs(Fragment, { children: [
62
+ const testId = node.key ?? prefixedTestId("action", node.id);
63
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
58
64
  /* @__PURE__ */ jsxs(Button, {
65
+ className: isMenuItem ? actionMenuItemClassName : void 0,
59
66
  "data-lattice-component": node.id,
60
- "data-test": `action-${label.toLowerCase().replace(/\s+/g, "-")}`,
67
+ "data-test": testId,
61
68
  disabled: http.processing || !endpoint,
62
69
  onClick: requestSubmit,
63
70
  type: "button",
64
- variant,
65
- children: [http.processing ? /* @__PURE__ */ jsx(Spinner, {}) : icon && /* @__PURE__ */ jsx(IconRenderer, {
66
- className: "size-lt-icon-md",
71
+ variant: isMenuItem ? "ghost" : variant,
72
+ children: [http.processing ? /* @__PURE__ */ jsx(Spinner, { className: isMenuItem ? "size-lt-icon-sm" : void 0 }) : icon && /* @__PURE__ */ jsx(IconRenderer, {
73
+ className: isMenuItem ? "size-lt-icon-sm" : "size-lt-icon-md",
67
74
  icon
68
75
  }), label]
69
76
  }),
@@ -88,7 +95,7 @@ var ActionComponent = ({ node }) => {
88
95
  onClose: () => setIsFilling(false),
89
96
  onSuccess: (response) => {
90
97
  const responseEffects = getActionEffects(response.effects);
91
- dispatchActionEffects(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));
98
+ dispatch(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));
92
99
  setIsFilling(false);
93
100
  },
94
101
  submitLabel: confirmationConfirmLabel,
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":[],"sources":["../../../resources/js/action/components/action.tsx"],"sourcesContent":["import { router, useHttp } from \"@inertiajs/react\";\nimport type { Method } from \"@inertiajs/core\";\nimport { useState } from \"react\";\nimport { withRefHeader } from \"@lattice/lattice/core/component-ref\";\nimport { Button } from \"@lattice/lattice/core/components/button\";\nimport { ConfirmDialog } from \"@lattice/lattice/core/components/confirm-dialog\";\nimport { Spinner } from \"@lattice/lattice/core/components/spinner\";\nimport type { Node, RendererComponent } from \"@lattice/lattice/core/types\";\nimport { IconRenderer } from \"@lattice/lattice/icons\";\nimport { dispatchActionEffects, dispatchActionError, getActionEffects } from \"../effects\";\nimport type { ActionResponse } from \"../effects\";\nimport { ActionForm, useLazyActionForm } from \"./action-form\";\n\nconst ActionComponent: RendererComponent<\"action\"> = ({ node }) => {\n const endpoint = node.props.endpoint ?? \"\";\n const icon = node.props.icon;\n const label = node.props.label ?? \"Run action\";\n const componentRef = node.props.ref ?? \"\";\n const method: Method = node.props.method ?? \"post\";\n const http = useHttp<Record<string, never>, ActionResponse>({});\n const [isConfirming, setIsConfirming] = useState(false);\n const [isFilling, setIsFilling] = useState(false);\n const confirmation = node.props.confirmation;\n const variant = node.props.variant ?? \"default\";\n // The wire carries the embedded form as a full node; the generated prop type\n // reflects Form's props, so read it through the Node lens the renderer uses.\n const inlineForm = node.props.form as unknown as Node | null;\n const lazyForm = node.props.lazyForm === true;\n const hasForm = Boolean(inlineForm) || lazyForm;\n const lazyNode = useLazyActionForm(endpoint, method, componentRef, isFilling && lazyForm);\n const formNode = lazyForm ? lazyNode : inlineForm;\n\n const submit = async (): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n try {\n if (method === \"get\") {\n router.visit(endpoint, { headers: withRefHeader(componentRef) });\n setIsConfirming(false);\n\n return;\n }\n\n const response = await http[method](endpoint, { headers: withRefHeader(componentRef) });\n const responseEffects = getActionEffects(response.effects);\n\n dispatchActionEffects(\n responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects),\n );\n setIsConfirming(false);\n } catch (error) {\n dispatchActionError(error);\n }\n };\n\n const requestSubmit = (): void => {\n if (hasForm) {\n setIsFilling(true);\n\n return;\n }\n\n if (confirmation) {\n setIsConfirming(true);\n\n return;\n }\n\n void submit();\n };\n\n const confirmationTitle = confirmation?.title ?? label;\n const confirmationConfirmLabel = confirmation?.confirmLabel ?? label;\n const confirmationCancelLabel = confirmation?.cancelLabel ?? \"Cancel\";\n\n return (\n <>\n <Button\n data-lattice-component={node.id}\n data-test={`action-${label.toLowerCase().replace(/\\s+/g, \"-\")}`}\n disabled={http.processing || !endpoint}\n onClick={requestSubmit}\n type=\"button\"\n variant={variant}\n >\n {http.processing ? (\n <Spinner />\n ) : (\n icon && <IconRenderer className=\"size-lt-icon-md\" icon={icon} />\n )}\n {label}\n </Button>\n\n {isConfirming && confirmation && (\n <ConfirmDialog\n title={confirmationTitle}\n description={confirmation.description ?? undefined}\n confirmLabel={confirmationConfirmLabel}\n cancelLabel={confirmationCancelLabel}\n confirmVariant={variant}\n processing={http.processing}\n confirmDisabled={!endpoint}\n onConfirm={() => void submit()}\n onCancel={() => setIsConfirming(false)}\n />\n )}\n\n {isFilling && hasForm && (\n <ActionForm\n cancelLabel={confirmationCancelLabel}\n componentRef={componentRef}\n description={confirmation?.description ?? undefined}\n endpoint={endpoint}\n formNode={formNode}\n method={method}\n onClose={() => setIsFilling(false)}\n onSuccess={(response) => {\n const responseEffects = getActionEffects(response.effects);\n\n dispatchActionEffects(\n responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects),\n );\n setIsFilling(false);\n }}\n submitLabel={confirmationConfirmLabel}\n title={confirmationTitle}\n />\n )}\n </>\n );\n};\n\nexport default ActionComponent;\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,WAAW,KAAK,MAAM,YAAY;CACxC,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,eAAe,KAAK,MAAM,OAAO;CACvC,MAAM,SAAiB,KAAK,MAAM,UAAU;CAC5C,MAAM,OAAO,QAA+C,CAAC,CAAC;CAC9D,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,eAAe,KAAK,MAAM;CAChC,MAAM,UAAU,KAAK,MAAM,WAAW;CAGtC,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,WAAW,KAAK,MAAM,aAAa;CACzC,MAAM,UAAU,QAAQ,UAAU,KAAK;CACvC,MAAM,WAAW,kBAAkB,UAAU,QAAQ,cAAc,aAAa,QAAQ;CACxF,MAAM,WAAW,WAAW,WAAW;CAEvC,MAAM,SAAS,YAA2B;EACxC,IAAI,CAAC,UACH;EAGF,IAAI;GACF,IAAI,WAAW,OAAO;IACpB,OAAO,MAAM,UAAU,EAAE,SAAS,cAAc,YAAY,EAAE,CAAC;IAC/D,gBAAgB,KAAK;IAErB;GACF;GAGA,MAAM,kBAAkB,kBAAiB,MADlB,KAAK,QAAQ,UAAU,EAAE,SAAS,cAAc,YAAY,EAAE,CAAC,GACpC,OAAO;GAEzD,sBACE,gBAAgB,SAAS,IAAI,kBAAkB,iBAAiB,KAAK,MAAM,OAAO,CACpF;GACA,gBAAgB,KAAK;EACvB,SAAS,OAAO;GACd,oBAAoB,KAAK;EAC3B;CACF;CAEA,MAAM,sBAA4B;EAChC,IAAI,SAAS;GACX,aAAa,IAAI;GAEjB;EACF;EAEA,IAAI,cAAc;GAChB,gBAAgB,IAAI;GAEpB;EACF;EAEA,OAAY;CACd;CAEA,MAAM,oBAAoB,cAAc,SAAS;CACjD,MAAM,2BAA2B,cAAc,gBAAgB;CAC/D,MAAM,0BAA0B,cAAc,eAAe;CAE7D,OACE,qBAAA,UAAA,EAAA,UAAA;EACE,qBAAC,QAAD;GACE,0BAAwB,KAAK;GAC7B,aAAW,UAAU,MAAM,YAAY,EAAE,QAAQ,QAAQ,GAAG;GAC5D,UAAU,KAAK,cAAc,CAAC;GAC9B,SAAS;GACT,MAAK;GACI;aANX,CAQG,KAAK,aACJ,oBAAC,SAAD,CAAU,CAAA,IAEV,QAAQ,oBAAC,cAAD;IAAc,WAAU;IAAwB;GAAO,CAAA,GAEhE,KACK;;EAEP,gBAAgB,gBACf,oBAAC,eAAD;GACE,OAAO;GACP,aAAa,aAAa,eAAe,KAAA;GACzC,cAAc;GACd,aAAa;GACb,gBAAgB;GAChB,YAAY,KAAK;GACjB,iBAAiB,CAAC;GAClB,iBAAiB,KAAK,OAAO;GAC7B,gBAAgB,gBAAgB,KAAK;EACtC,CAAA;EAGF,aAAa,WACZ,oBAAC,YAAD;GACE,aAAa;GACC;GACd,aAAa,cAAc,eAAe,KAAA;GAChC;GACA;GACF;GACR,eAAe,aAAa,KAAK;GACjC,YAAY,aAAa;IACvB,MAAM,kBAAkB,iBAAiB,SAAS,OAAO;IAEzD,sBACE,gBAAgB,SAAS,IAAI,kBAAkB,iBAAiB,KAAK,MAAM,OAAO,CACpF;IACA,aAAa,KAAK;GACpB;GACA,aAAa;GACb,OAAO;EACR,CAAA;CAEH,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"action.js","names":[],"sources":["../../../resources/js/action/components/action.tsx"],"sourcesContent":["import { router, useHttp } from \"@inertiajs/react\";\nimport type { Method } from \"@inertiajs/core\";\nimport { useState } from \"react\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/core/components/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/core/components/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { dispatchActionError, getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { ActionForm, useLazyActionForm } from \"./action-form\";\nimport { actionMenuItemClassName, useActionMenu } from \"./action-menu-context\";\n\nconst ActionComponent: RendererComponent<\"action\"> = ({ node }) => {\n const endpoint = node.props.endpoint ?? \"\";\n const icon = node.props.icon;\n const label = node.props.label ?? \"Run action\";\n const componentRef = node.props.ref ?? \"\";\n const method: Method = node.props.method ?? \"post\";\n const http = useHttp<Record<string, never>, ActionResponse>({});\n const dispatch = useEffectDispatcher();\n const [isConfirming, setIsConfirming] = useState(false);\n const [isFilling, setIsFilling] = useState(false);\n const isMenuItem = useActionMenu();\n const confirmation = node.props.confirmation;\n const variant = node.props.variant ?? \"default\";\n const inlineForm = node.props.form;\n const lazyForm = node.props.lazyForm === true;\n const hasForm = Boolean(inlineForm) || lazyForm;\n const lazyNode = useLazyActionForm(endpoint, componentRef, isFilling && lazyForm);\n const formNode = lazyForm ? lazyNode : inlineForm;\n\n const submit = async (): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n try {\n if (method === \"get\") {\n router.visit(endpoint, { headers: withHeaders(componentRef) });\n setIsConfirming(false);\n\n return;\n }\n\n const response = await http[method](endpoint, { headers: withHeaders(componentRef) });\n const responseEffects = getActionEffects(response.effects);\n\n dispatch(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));\n setIsConfirming(false);\n } catch (error) {\n dispatchActionError(error);\n }\n };\n\n const requestSubmit = (): void => {\n if (hasForm) {\n setIsFilling(true);\n\n return;\n }\n\n if (confirmation) {\n setIsConfirming(true);\n\n return;\n }\n\n void submit();\n };\n\n const confirmationTitle = confirmation?.title ?? label;\n const confirmationConfirmLabel = confirmation?.confirmLabel ?? label;\n const confirmationCancelLabel = confirmation?.cancelLabel ?? \"Cancel\";\n const testId = node.key ?? prefixedTestId(\"action\", node.id);\n\n return (\n <>\n <Button\n className={isMenuItem ? actionMenuItemClassName : undefined}\n data-lattice-component={node.id}\n data-test={testId}\n disabled={http.processing || !endpoint}\n onClick={requestSubmit}\n type=\"button\"\n variant={isMenuItem ? \"ghost\" : variant}\n >\n {http.processing ? (\n <Spinner className={isMenuItem ? \"size-lt-icon-sm\" : undefined} />\n ) : (\n icon && (\n <IconRenderer\n className={isMenuItem ? \"size-lt-icon-sm\" : \"size-lt-icon-md\"}\n icon={icon}\n />\n )\n )}\n {label}\n </Button>\n\n {isConfirming && confirmation && (\n <ConfirmDialog\n title={confirmationTitle}\n description={confirmation.description ?? undefined}\n confirmLabel={confirmationConfirmLabel}\n cancelLabel={confirmationCancelLabel}\n confirmVariant={variant}\n processing={http.processing}\n confirmDisabled={!endpoint}\n onConfirm={() => void submit()}\n onCancel={() => setIsConfirming(false)}\n />\n )}\n\n {isFilling && hasForm && (\n <ActionForm\n cancelLabel={confirmationCancelLabel}\n componentRef={componentRef}\n description={confirmation?.description ?? undefined}\n endpoint={endpoint}\n formNode={formNode}\n method={method}\n onClose={() => setIsFilling(false)}\n onSuccess={(response) => {\n const responseEffects = getActionEffects(response.effects);\n\n dispatch(\n responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects),\n );\n setIsFilling(false);\n }}\n submitLabel={confirmationConfirmLabel}\n title={confirmationTitle}\n />\n )}\n </>\n );\n};\n\nexport default ActionComponent;\n"],"mappings":";;;;;;;;;;;;;;AAgBA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,WAAW,KAAK,MAAM,YAAY;CACxC,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,eAAe,KAAK,MAAM,OAAO;CACvC,MAAM,SAAiB,KAAK,MAAM,UAAU;CAC5C,MAAM,OAAO,QAA+C,CAAC,CAAC;CAC9D,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,aAAa,cAAc;CACjC,MAAM,eAAe,KAAK,MAAM;CAChC,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,WAAW,KAAK,MAAM,aAAa;CACzC,MAAM,UAAU,QAAQ,UAAU,KAAK;CACvC,MAAM,WAAW,kBAAkB,UAAU,cAAc,aAAa,QAAQ;CAChF,MAAM,WAAW,WAAW,WAAW;CAEvC,MAAM,SAAS,YAA2B;EACxC,IAAI,CAAC,UACH;EAGF,IAAI;GACF,IAAI,WAAW,OAAO;IACpB,OAAO,MAAM,UAAU,EAAE,SAAS,YAAY,YAAY,EAAE,CAAC;IAC7D,gBAAgB,KAAK;IAErB;GACF;GAGA,MAAM,kBAAkB,kBAAiB,MADlB,KAAK,QAAQ,UAAU,EAAE,SAAS,YAAY,YAAY,EAAE,CAAC,GAClC,OAAO;GAEzD,SAAS,gBAAgB,SAAS,IAAI,kBAAkB,iBAAiB,KAAK,MAAM,OAAO,CAAC;GAC5F,gBAAgB,KAAK;EACvB,SAAS,OAAO;GACd,oBAAoB,KAAK;EAC3B;CACF;CAEA,MAAM,sBAA4B;EAChC,IAAI,SAAS;GACX,aAAa,IAAI;GAEjB;EACF;EAEA,IAAI,cAAc;GAChB,gBAAgB,IAAI;GAEpB;EACF;EAEA,OAAY;CACd;CAEA,MAAM,oBAAoB,cAAc,SAAS;CACjD,MAAM,2BAA2B,cAAc,gBAAgB;CAC/D,MAAM,0BAA0B,cAAc,eAAe;CAC7D,MAAM,SAAS,KAAK,OAAO,eAAe,UAAU,KAAK,EAAE;CAE3D,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,qBAAC,QAAD;GACE,WAAW,aAAa,0BAA0B,KAAA;GAClD,0BAAwB,KAAK;GAC7B,aAAW;GACX,UAAU,KAAK,cAAc,CAAC;GAC9B,SAAS;GACT,MAAK;GACL,SAAS,aAAa,UAAU;aAPlC,CASG,KAAK,aACJ,oBAAC,SAAD,EAAS,WAAW,aAAa,oBAAoB,KAAA,EAAY,CAAA,IAEjE,QACE,oBAAC,cAAD;IACE,WAAW,aAAa,oBAAoB;IACtC;GACP,CAAA,GAGJ,KACK;;EAEP,gBAAgB,gBACf,oBAAC,eAAD;GACE,OAAO;GACP,aAAa,aAAa,eAAe,KAAA;GACzC,cAAc;GACd,aAAa;GACb,gBAAgB;GAChB,YAAY,KAAK;GACjB,iBAAiB,CAAC;GAClB,iBAAiB,KAAK,OAAO;GAC7B,gBAAgB,gBAAgB,KAAK;EACtC,CAAA;EAGF,aAAa,WACZ,oBAAC,YAAD;GACE,aAAa;GACC;GACd,aAAa,cAAc,eAAe,KAAA;GAChC;GACA;GACF;GACR,eAAe,aAAa,KAAK;GACjC,YAAY,aAAa;IACvB,MAAM,kBAAkB,iBAAiB,SAAS,OAAO;IAEzD,SACE,gBAAgB,SAAS,IAAI,kBAAkB,iBAAiB,KAAK,MAAM,OAAO,CACpF;IACA,aAAa,KAAK;GACpB;GACA,aAAa;GACb,OAAO;EACR,CAAA;CAEH,EAAA,CAAA;AAEN"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/action/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice/lattice/core/registry\";\nimport ActionComponent from \"./components/action\";\nimport ActionGroupComponent from \"./components/action-group\";\n\nexport const actionComponents = createPlugin({\n components: {\n action: eagerComponent(ActionComponent),\n \"action.group\": eagerComponent(ActionGroupComponent),\n },\n name: \"lattice/action\",\n});\n"],"mappings":";;;;AAIA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,QAAQ,eAAe,eAAe;EACtC,gBAAgB,eAAe,oBAAoB;CACrD;CACA,MAAM;AACR,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/action/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport ActionComponent from \"./components/action\";\nimport ActionGroupComponent from \"./components/action-group\";\n\nexport const actionComponents = createPlugin({\n components: {\n action: eagerComponent(ActionComponent),\n \"action.group\": eagerComponent(ActionGroupComponent),\n },\n name: \"lattice/action\",\n});\n"],"mappings":";;;;AAIA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,QAAQ,eAAe,eAAe;EACtC,gBAAgB,eAAe,oBAAoB;CACrD;CACA,MAAM;AACR,CAAC"}
@@ -18,6 +18,7 @@ var getStoredAppearance = () => {
18
18
  var isDarkMode = (appearance) => {
19
19
  return appearance === "dark" || appearance === "system" && prefersDark();
20
20
  };
21
+ var getSystemAppearance = () => prefersDark() ? "dark" : "light";
21
22
  var applyTheme = (appearance) => {
22
23
  if (typeof document === "undefined") return;
23
24
  const isDark = isDarkMode(appearance);
@@ -33,7 +34,10 @@ var mediaQuery = () => {
33
34
  if (typeof window === "undefined") return null;
34
35
  return window.matchMedia("(prefers-color-scheme: dark)");
35
36
  };
36
- var handleSystemThemeChange = () => applyTheme(currentAppearance);
37
+ var handleSystemThemeChange = () => {
38
+ applyTheme(currentAppearance);
39
+ notify();
40
+ };
37
41
  function initializeTheme() {
38
42
  if (typeof window === "undefined") return;
39
43
  if (!localStorage.getItem("appearance")) {
@@ -46,7 +50,8 @@ function initializeTheme() {
46
50
  }
47
51
  function useAppearance() {
48
52
  const appearance = useSyncExternalStore(subscribe, () => currentAppearance, () => "system");
49
- const resolvedAppearance = isDarkMode(appearance) ? "dark" : "light";
53
+ const systemAppearance = useSyncExternalStore(subscribe, getSystemAppearance, () => "light");
54
+ const resolvedAppearance = appearance === "system" ? systemAppearance : appearance;
50
55
  const updateAppearance = (mode) => {
51
56
  currentAppearance = mode;
52
57
  localStorage.setItem("appearance", mode);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/appearance/index.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport type { Appearance } from \"../events/event-bridge\";\n\nexport type ResolvedAppearance = \"light\" | \"dark\";\n\nexport type UseAppearanceReturn = {\n readonly appearance: Appearance;\n readonly resolvedAppearance: ResolvedAppearance;\n readonly updateAppearance: (mode: Appearance) => void;\n};\n\nconst listeners = new Set<() => void>();\nlet currentAppearance: Appearance = \"system\";\n\nconst prefersDark = (): boolean => {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n};\n\nconst setCookie = (name: string, value: string, days = 365): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const maxAge = days * 24 * 60 * 60;\n document.cookie = `${name}=${value};path=/;max-age=${maxAge};SameSite=Lax`;\n};\n\nconst getStoredAppearance = (): Appearance => {\n if (typeof window === \"undefined\") {\n return \"system\";\n }\n\n return (localStorage.getItem(\"appearance\") as Appearance) || \"system\";\n};\n\nconst isDarkMode = (appearance: Appearance): boolean => {\n return appearance === \"dark\" || (appearance === \"system\" && prefersDark());\n};\n\nconst applyTheme = (appearance: Appearance): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const isDark = isDarkMode(appearance);\n\n document.documentElement.classList.toggle(\"dark\", isDark);\n document.documentElement.style.colorScheme = isDark ? \"dark\" : \"light\";\n};\n\nconst subscribe = (callback: () => void) => {\n listeners.add(callback);\n\n return () => listeners.delete(callback);\n};\n\nconst notify = (): void => listeners.forEach((listener) => listener());\n\nconst mediaQuery = (): MediaQueryList | null => {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n return window.matchMedia(\"(prefers-color-scheme: dark)\");\n};\n\nconst handleSystemThemeChange = (): void => applyTheme(currentAppearance);\n\nexport function initializeTheme(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n if (!localStorage.getItem(\"appearance\")) {\n localStorage.setItem(\"appearance\", \"system\");\n setCookie(\"appearance\", \"system\");\n }\n\n currentAppearance = getStoredAppearance();\n applyTheme(currentAppearance);\n\n mediaQuery()?.addEventListener(\"change\", handleSystemThemeChange);\n}\n\nexport function useAppearance(): UseAppearanceReturn {\n const appearance: Appearance = useSyncExternalStore(\n subscribe,\n () => currentAppearance,\n () => \"system\",\n );\n\n const resolvedAppearance: ResolvedAppearance = isDarkMode(appearance) ? \"dark\" : \"light\";\n\n const updateAppearance = (mode: Appearance): void => {\n currentAppearance = mode;\n\n localStorage.setItem(\"appearance\", mode);\n\n setCookie(\"appearance\", mode);\n\n applyTheme(mode);\n notify();\n };\n\n return { appearance, resolvedAppearance, updateAppearance } as const;\n}\n"],"mappings":";;AAWA,IAAM,4BAAY,IAAI,IAAgB;AACtC,IAAI,oBAAgC;AAEpC,IAAM,oBAA6B;CACjC,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO,OAAO,WAAW,8BAA8B,EAAE;AAC3D;AAEA,IAAM,aAAa,MAAc,OAAe,OAAO,QAAc;CACnE,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,SAAS,OAAO,KAAK,KAAK;CAChC,SAAS,SAAS,GAAG,KAAK,GAAG,MAAM,kBAAkB,OAAO;AAC9D;AAEA,IAAM,4BAAwC;CAC5C,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAQ,aAAa,QAAQ,YAAY,KAAoB;AAC/D;AAEA,IAAM,cAAc,eAAoC;CACtD,OAAO,eAAe,UAAW,eAAe,YAAY,YAAY;AAC1E;AAEA,IAAM,cAAc,eAAiC;CACnD,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,SAAS,WAAW,UAAU;CAEpC,SAAS,gBAAgB,UAAU,OAAO,QAAQ,MAAM;CACxD,SAAS,gBAAgB,MAAM,cAAc,SAAS,SAAS;AACjE;AAEA,IAAM,aAAa,aAAyB;CAC1C,UAAU,IAAI,QAAQ;CAEtB,aAAa,UAAU,OAAO,QAAQ;AACxC;AAEA,IAAM,eAAqB,UAAU,SAAS,aAAa,SAAS,CAAC;AAErE,IAAM,mBAA0C;CAC9C,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO,OAAO,WAAW,8BAA8B;AACzD;AAEA,IAAM,gCAAsC,WAAW,iBAAiB;AAExE,SAAgB,kBAAwB;CACtC,IAAI,OAAO,WAAW,aACpB;CAGF,IAAI,CAAC,aAAa,QAAQ,YAAY,GAAG;EACvC,aAAa,QAAQ,cAAc,QAAQ;EAC3C,UAAU,cAAc,QAAQ;CAClC;CAEA,oBAAoB,oBAAoB;CACxC,WAAW,iBAAiB;CAE5B,WAAW,GAAG,iBAAiB,UAAU,uBAAuB;AAClE;AAEA,SAAgB,gBAAqC;CACnD,MAAM,aAAyB,qBAC7B,iBACM,yBACA,QACR;CAEA,MAAM,qBAAyC,WAAW,UAAU,IAAI,SAAS;CAEjF,MAAM,oBAAoB,SAA2B;EACnD,oBAAoB;EAEpB,aAAa,QAAQ,cAAc,IAAI;EAEvC,UAAU,cAAc,IAAI;EAE5B,WAAW,IAAI;EACf,OAAO;CACT;CAEA,OAAO;EAAE;EAAY;EAAoB;CAAiB;AAC5D"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/appearance/index.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport type { Appearance } from \"../events/event-bridge\";\n\nexport type ResolvedAppearance = \"light\" | \"dark\";\n\nexport type UseAppearanceReturn = {\n readonly appearance: Appearance;\n readonly resolvedAppearance: ResolvedAppearance;\n readonly updateAppearance: (mode: Appearance) => void;\n};\n\nconst listeners = new Set<() => void>();\nlet currentAppearance: Appearance = \"system\";\n\nconst prefersDark = (): boolean => {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n};\n\nconst setCookie = (name: string, value: string, days = 365): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const maxAge = days * 24 * 60 * 60;\n document.cookie = `${name}=${value};path=/;max-age=${maxAge};SameSite=Lax`;\n};\n\nconst getStoredAppearance = (): Appearance => {\n if (typeof window === \"undefined\") {\n return \"system\";\n }\n\n return (localStorage.getItem(\"appearance\") as Appearance) || \"system\";\n};\n\nconst isDarkMode = (appearance: Appearance): boolean => {\n return appearance === \"dark\" || (appearance === \"system\" && prefersDark());\n};\n\nconst getSystemAppearance = (): ResolvedAppearance => (prefersDark() ? \"dark\" : \"light\");\n\nconst applyTheme = (appearance: Appearance): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const isDark = isDarkMode(appearance);\n\n document.documentElement.classList.toggle(\"dark\", isDark);\n document.documentElement.style.colorScheme = isDark ? \"dark\" : \"light\";\n};\n\nconst subscribe = (callback: () => void) => {\n listeners.add(callback);\n\n return () => listeners.delete(callback);\n};\n\nconst notify = (): void => listeners.forEach((listener) => listener());\n\nconst mediaQuery = (): MediaQueryList | null => {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n return window.matchMedia(\"(prefers-color-scheme: dark)\");\n};\n\nconst handleSystemThemeChange = (): void => {\n applyTheme(currentAppearance);\n notify();\n};\n\nexport function initializeTheme(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n if (!localStorage.getItem(\"appearance\")) {\n localStorage.setItem(\"appearance\", \"system\");\n setCookie(\"appearance\", \"system\");\n }\n\n currentAppearance = getStoredAppearance();\n applyTheme(currentAppearance);\n\n mediaQuery()?.addEventListener(\"change\", handleSystemThemeChange);\n}\n\nexport function useAppearance(): UseAppearanceReturn {\n const appearance: Appearance = useSyncExternalStore(\n subscribe,\n () => currentAppearance,\n () => \"system\",\n );\n const systemAppearance: ResolvedAppearance = useSyncExternalStore(\n subscribe,\n getSystemAppearance,\n () => \"light\",\n );\n\n const resolvedAppearance: ResolvedAppearance =\n appearance === \"system\" ? systemAppearance : appearance;\n\n const updateAppearance = (mode: Appearance): void => {\n currentAppearance = mode;\n\n localStorage.setItem(\"appearance\", mode);\n\n setCookie(\"appearance\", mode);\n\n applyTheme(mode);\n notify();\n };\n\n return { appearance, resolvedAppearance, updateAppearance } as const;\n}\n"],"mappings":";;AAWA,IAAM,4BAAY,IAAI,IAAgB;AACtC,IAAI,oBAAgC;AAEpC,IAAM,oBAA6B;CACjC,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO,OAAO,WAAW,8BAA8B,EAAE;AAC3D;AAEA,IAAM,aAAa,MAAc,OAAe,OAAO,QAAc;CACnE,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,SAAS,OAAO,KAAK,KAAK;CAChC,SAAS,SAAS,GAAG,KAAK,GAAG,MAAM,kBAAkB,OAAO;AAC9D;AAEA,IAAM,4BAAwC;CAC5C,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAQ,aAAa,QAAQ,YAAY,KAAoB;AAC/D;AAEA,IAAM,cAAc,eAAoC;CACtD,OAAO,eAAe,UAAW,eAAe,YAAY,YAAY;AAC1E;AAEA,IAAM,4BAAiD,YAAY,IAAI,SAAS;AAEhF,IAAM,cAAc,eAAiC;CACnD,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,SAAS,WAAW,UAAU;CAEpC,SAAS,gBAAgB,UAAU,OAAO,QAAQ,MAAM;CACxD,SAAS,gBAAgB,MAAM,cAAc,SAAS,SAAS;AACjE;AAEA,IAAM,aAAa,aAAyB;CAC1C,UAAU,IAAI,QAAQ;CAEtB,aAAa,UAAU,OAAO,QAAQ;AACxC;AAEA,IAAM,eAAqB,UAAU,SAAS,aAAa,SAAS,CAAC;AAErE,IAAM,mBAA0C;CAC9C,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO,OAAO,WAAW,8BAA8B;AACzD;AAEA,IAAM,gCAAsC;CAC1C,WAAW,iBAAiB;CAC5B,OAAO;AACT;AAEA,SAAgB,kBAAwB;CACtC,IAAI,OAAO,WAAW,aACpB;CAGF,IAAI,CAAC,aAAa,QAAQ,YAAY,GAAG;EACvC,aAAa,QAAQ,cAAc,QAAQ;EAC3C,UAAU,cAAc,QAAQ;CAClC;CAEA,oBAAoB,oBAAoB;CACxC,WAAW,iBAAiB;CAE5B,WAAW,GAAG,iBAAiB,UAAU,uBAAuB;AAClE;AAEA,SAAgB,gBAAqC;CACnD,MAAM,aAAyB,qBAC7B,iBACM,yBACA,QACR;CACA,MAAM,mBAAuC,qBAC3C,WACA,2BACM,OACR;CAEA,MAAM,qBACJ,eAAe,WAAW,mBAAmB;CAE/C,MAAM,oBAAoB,SAA2B;EACnD,oBAAoB;EAEpB,aAAa,QAAQ,cAAc,IAAI;EAEvC,UAAU,cAAc,IAAI;EAE5B,WAAW,IAAI;EACf,OAAO;CACT;CAEA,OAAO;EAAE;EAAY;EAAoB;CAAiB;AAC5D"}
@@ -0,0 +1,3 @@
1
+ import { RendererComponent } from '../../core/types';
2
+ export declare const ChatBox: RendererComponent<"chat.box">;
3
+ export default ChatBox;