@lattice-php/lattice 0.19.0 → 0.21.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 (343) hide show
  1. package/dist/action/components/action-form.d.ts +6 -1
  2. package/dist/action/components/action-form.js +34 -49
  3. package/dist/action/components/action-form.js.map +1 -1
  4. package/dist/action/components/action-trigger-provider.d.ts +1 -1
  5. package/dist/action/components/action-trigger-provider.js.map +1 -1
  6. package/dist/action/hooks/use-action.d.ts +1 -1
  7. package/dist/action/hooks/use-action.js +3 -1
  8. package/dist/action/hooks/use-action.js.map +1 -1
  9. package/dist/action/index.d.ts +0 -2
  10. package/dist/action/index.js +1 -2
  11. package/dist/chat/plugin.d.ts +0 -1
  12. package/dist/chat/plugin.js.map +1 -1
  13. package/dist/clipboard/index.d.ts +0 -4
  14. package/dist/clipboard/index.js +1 -15
  15. package/dist/{events → core}/event-names.js +1 -1
  16. package/dist/core/event-names.js.map +1 -0
  17. package/dist/core/hooks/use-window-event.d.ts +8 -0
  18. package/dist/core/hooks/use-window-event.js +22 -0
  19. package/dist/core/hooks/use-window-event.js.map +1 -0
  20. package/dist/core/index.js +1 -1
  21. package/dist/core/types.d.ts +8 -61
  22. package/dist/create-app.d.ts +31 -3
  23. package/dist/create-app.js +48 -10
  24. package/dist/create-app.js.map +1 -1
  25. package/dist/effects/dispatch.js +1 -1
  26. package/dist/effects/dispatch.js.map +1 -1
  27. package/dist/effects/registry.d.ts +2 -18
  28. package/dist/effects/registry.js +5 -9
  29. package/dist/effects/registry.js.map +1 -1
  30. package/dist/event-bridge.js +10 -23
  31. package/dist/event-bridge.js.map +1 -1
  32. package/dist/form/components/base/field.d.ts +2 -2
  33. package/dist/form/components/base/field.js +2 -2
  34. package/dist/form/components/base/field.js.map +1 -1
  35. package/dist/form/components/fields/color-picker-field.d.ts +2 -0
  36. package/dist/form/components/fields/color-picker-field.js +57 -0
  37. package/dist/form/components/fields/color-picker-field.js.map +1 -0
  38. package/dist/form/components/fields/date-input.js +1 -1
  39. package/dist/form/components/fields/date-time-input.js +1 -1
  40. package/dist/form/components/fields/file-upload.js +11 -18
  41. package/dist/form/components/fields/file-upload.js.map +1 -1
  42. package/dist/form/components/fields/number-input.js +1 -1
  43. package/dist/form/components/fields/rich-editor-field.js +35 -276
  44. package/dist/form/components/fields/rich-editor-field.js.map +1 -1
  45. package/dist/form/components/fields/row-action-menu.js +2 -2
  46. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  47. package/dist/form/components/fields/row-actions.js +3 -1
  48. package/dist/form/components/fields/row-actions.js.map +1 -1
  49. package/dist/form/components/fields/select.js +60 -17
  50. package/dist/form/components/fields/select.js.map +1 -1
  51. package/dist/form/components/fields/table-rows.js +5 -17
  52. package/dist/form/components/fields/table-rows.js.map +1 -1
  53. package/dist/form/components/fields/text-input.js +8 -1
  54. package/dist/form/components/fields/text-input.js.map +1 -1
  55. package/dist/form/components/fields/time-input.js +1 -1
  56. package/dist/form/components/form.js +8 -23
  57. package/dist/form/components/form.js.map +1 -1
  58. package/dist/form/components/index.d.ts +1 -0
  59. package/dist/form/components/index.js +2 -1
  60. package/dist/form/embed.d.ts +5 -0
  61. package/dist/form/embed.js +4 -1
  62. package/dist/form/hooks/use-form-resolver.js.map +1 -1
  63. package/dist/form/index.js +2 -1
  64. package/dist/form/lib/collect-fields.d.ts +7 -0
  65. package/dist/form/lib/collect-fields.js +19 -0
  66. package/dist/form/lib/collect-fields.js.map +1 -0
  67. package/dist/form/lib/conditions.d.ts +4 -10
  68. package/dist/form/lib/conditions.js.map +1 -1
  69. package/dist/form/lib/field-errors.d.ts +3 -0
  70. package/dist/form/lib/field-errors.js +11 -0
  71. package/dist/form/lib/field-errors.js.map +1 -0
  72. package/dist/form/lib/field-props.d.ts +4 -18
  73. package/dist/form/lib/field-props.js.map +1 -1
  74. package/dist/form/plugin.js +2 -0
  75. package/dist/form/plugin.js.map +1 -1
  76. package/dist/form/rich-editor/builtins.d.ts +6 -0
  77. package/dist/form/rich-editor/builtins.js +400 -0
  78. package/dist/form/rich-editor/builtins.js.map +1 -0
  79. package/dist/form/rich-editor/index.d.ts +7 -0
  80. package/dist/form/rich-editor/index.js +3 -0
  81. package/dist/form/rich-editor/registry.d.ts +67 -0
  82. package/dist/form/rich-editor/registry.js +79 -0
  83. package/dist/form/rich-editor/registry.js.map +1 -0
  84. package/dist/form/rich-editor/toolbar-button.d.ts +12 -0
  85. package/dist/form/rich-editor/toolbar-button.js +28 -0
  86. package/dist/form/rich-editor/toolbar-button.js.map +1 -0
  87. package/dist/form/types.d.ts +1 -6
  88. package/dist/format/date-time.d.ts +3 -2
  89. package/dist/format/date-time.js.map +1 -1
  90. package/dist/format/format-context.d.ts +6 -0
  91. package/dist/format/format-context.js +17 -0
  92. package/dist/format/format-context.js.map +1 -0
  93. package/dist/i18n/date-time.d.ts +3 -2
  94. package/dist/i18n/date-time.js.map +1 -1
  95. package/dist/i18n/index.js +3 -2
  96. package/dist/i18n/locale-reload.d.ts +1 -1
  97. package/dist/i18n/locale-reload.js +7 -6
  98. package/dist/i18n/locale-reload.js.map +1 -1
  99. package/dist/i18n/locale.js +1 -1
  100. package/dist/i18n/locale.js.map +1 -1
  101. package/dist/i18n/page-props.d.ts +3 -2
  102. package/dist/i18n/page-props.js +1 -15
  103. package/dist/i18n/page-props.js.map +1 -1
  104. package/dist/i18n/shared-props.d.ts +7 -0
  105. package/dist/i18n/shared-props.js +23 -0
  106. package/dist/i18n/shared-props.js.map +1 -0
  107. package/dist/i18n/timezone.js +1 -1
  108. package/dist/i18n/timezone.js.map +1 -1
  109. package/dist/index.d.ts +11 -10
  110. package/dist/index.js +5 -5
  111. package/dist/lattice.css +212 -47
  112. package/dist/layout/components/breadcrumbs.js +3 -1
  113. package/dist/layout/components/breadcrumbs.js.map +1 -1
  114. package/dist/layout/components/sidebar.js +15 -48
  115. package/dist/layout/components/sidebar.js.map +1 -1
  116. package/dist/layout/plugin.d.ts +0 -1
  117. package/dist/layout/plugin.js.map +1 -1
  118. package/dist/lib/color.d.ts +9 -0
  119. package/dist/lib/color.js +48 -0
  120. package/dist/lib/color.js.map +1 -0
  121. package/dist/lib/is-truthy.d.ts +2 -0
  122. package/dist/lib/is-truthy.js +9 -0
  123. package/dist/lib/is-truthy.js.map +1 -0
  124. package/dist/lib/use-debounced-callback.d.ts +10 -0
  125. package/dist/lib/use-debounced-callback.js +34 -0
  126. package/dist/lib/use-debounced-callback.js.map +1 -0
  127. package/dist/lib/use-media-query.d.ts +5 -0
  128. package/dist/lib/use-media-query.js +26 -0
  129. package/dist/lib/use-media-query.js.map +1 -0
  130. package/dist/lib/use-persistent-state.d.ts +13 -0
  131. package/dist/lib/use-persistent-state.js +62 -0
  132. package/dist/lib/use-persistent-state.js.map +1 -0
  133. package/dist/notifications/api.d.ts +6 -6
  134. package/dist/notifications/api.js.map +1 -1
  135. package/dist/notifications/components/notifications.js +3 -1
  136. package/dist/notifications/components/notifications.js.map +1 -1
  137. package/dist/notifications/plugin.d.ts +0 -1
  138. package/dist/notifications/plugin.js.map +1 -1
  139. package/dist/notifications/types.d.ts +2 -10
  140. package/dist/provider-base.js +1 -1
  141. package/dist/realtime/build-effects.js +5 -5
  142. package/dist/realtime/build-effects.js.map +1 -1
  143. package/dist/realtime/listeners.d.ts +2 -2
  144. package/dist/realtime/listeners.js +1 -1
  145. package/dist/realtime/listeners.js.map +1 -1
  146. package/dist/realtime/subscriptions.d.ts +2 -2
  147. package/dist/realtime/subscriptions.js.map +1 -1
  148. package/dist/registry.d.ts +5 -0
  149. package/dist/registry.js.map +1 -1
  150. package/dist/remote/components/data-list.js +1 -1
  151. package/dist/remote/plugin.d.ts +0 -1
  152. package/dist/remote/plugin.js.map +1 -1
  153. package/dist/table/components/bulk-bar.js +7 -5
  154. package/dist/table/components/bulk-bar.js.map +1 -1
  155. package/dist/table/components/cells/badge-cell.js +4 -1
  156. package/dist/table/components/cells/badge-cell.js.map +1 -1
  157. package/dist/table/components/cells/boolean-cell.js +4 -4
  158. package/dist/table/components/cells/boolean-cell.js.map +1 -1
  159. package/dist/table/components/cells/copyable-cell.d.ts +9 -0
  160. package/dist/table/components/cells/copyable-cell.js +17 -0
  161. package/dist/table/components/cells/copyable-cell.js.map +1 -0
  162. package/dist/table/components/cells/icon-cell.js +5 -2
  163. package/dist/table/components/cells/icon-cell.js.map +1 -1
  164. package/dist/table/components/cells/image-cell.js +8 -9
  165. package/dist/table/components/cells/image-cell.js.map +1 -1
  166. package/dist/table/components/cells/money-cell.js +7 -10
  167. package/dist/table/components/cells/money-cell.js.map +1 -1
  168. package/dist/table/components/cells/number-cell.js +14 -19
  169. package/dist/table/components/cells/number-cell.js.map +1 -1
  170. package/dist/table/components/cells/numeric-cell.d.ts +10 -0
  171. package/dist/table/components/cells/numeric-cell.js +25 -0
  172. package/dist/table/components/cells/numeric-cell.js.map +1 -0
  173. package/dist/table/components/cells/stack-cell.js +1 -1
  174. package/dist/table/components/cells/text-cell.js +8 -6
  175. package/dist/table/components/cells/text-cell.js.map +1 -1
  176. package/dist/table/components/column-filter-control.js +25 -32
  177. package/dist/table/components/column-filter-control.js.map +1 -1
  178. package/dist/table/components/column-header.d.ts +3 -3
  179. package/dist/table/components/column-header.js +5 -3
  180. package/dist/table/components/column-header.js.map +1 -1
  181. package/dist/table/components/column-visibility-menu.js +6 -11
  182. package/dist/table/components/column-visibility-menu.js.map +1 -1
  183. package/dist/table/components/filter-bar.d.ts +2 -2
  184. package/dist/table/components/filter-bar.js +13 -22
  185. package/dist/table/components/filter-bar.js.map +1 -1
  186. package/dist/table/components/filter-controls.d.ts +2 -1
  187. package/dist/table/components/filter-controls.js +37 -38
  188. package/dist/table/components/filter-controls.js.map +1 -1
  189. package/dist/table/components/filter-value-input.d.ts +0 -1
  190. package/dist/table/components/filter-value-input.js +21 -20
  191. package/dist/table/components/filter-value-input.js.map +1 -1
  192. package/dist/table/components/pagination.js +16 -20
  193. package/dist/table/components/pagination.js.map +1 -1
  194. package/dist/table/components/sort-bar.d.ts +3 -3
  195. package/dist/table/components/sort-bar.js +11 -12
  196. package/dist/table/components/sort-bar.js.map +1 -1
  197. package/dist/table/components/table-cell.js.map +1 -1
  198. package/dist/table/components/table-search.d.ts +9 -0
  199. package/dist/table/components/table-search.js +72 -0
  200. package/dist/table/components/table-search.js.map +1 -0
  201. package/dist/table/components/table.js +73 -21
  202. package/dist/table/components/table.js.map +1 -1
  203. package/dist/table/hooks/use-column-visibility.js +29 -58
  204. package/dist/table/hooks/use-column-visibility.js.map +1 -1
  205. package/dist/table/hooks/use-expanded-rows.d.ts +8 -0
  206. package/dist/table/hooks/use-expanded-rows.js +24 -0
  207. package/dist/table/hooks/use-expanded-rows.js.map +1 -0
  208. package/dist/table/hooks/use-table.d.ts +5 -3
  209. package/dist/table/hooks/use-table.js +59 -55
  210. package/dist/table/hooks/use-table.js.map +1 -1
  211. package/dist/table/lib/bulk.d.ts +2 -0
  212. package/dist/table/lib/bulk.js +3 -1
  213. package/dist/table/lib/bulk.js.map +1 -1
  214. package/dist/table/lib/payload.d.ts +3 -2
  215. package/dist/table/lib/payload.js +16 -10
  216. package/dist/table/lib/payload.js.map +1 -1
  217. package/dist/table/lib/query.d.ts +5 -5
  218. package/dist/table/lib/query.js +21 -19
  219. package/dist/table/lib/query.js.map +1 -1
  220. package/dist/table/plugin.d.ts +0 -1
  221. package/dist/table/plugin.js.map +1 -1
  222. package/dist/table/types.d.ts +5 -81
  223. package/dist/toast/callout.js +2 -4
  224. package/dist/toast/callout.js.map +1 -1
  225. package/dist/toast/index.d.ts +1 -1
  226. package/dist/toast/index.js +2 -2
  227. package/dist/toast/toast.d.ts +1 -7
  228. package/dist/toast/toast.js +3 -15
  229. package/dist/toast/toast.js.map +1 -1
  230. package/dist/toast/toaster.js.map +1 -1
  231. package/dist/types/generated.d.ts +444 -225
  232. package/dist/types/index.d.ts +1 -1
  233. package/dist/ui/affix-group.d.ts +2 -1
  234. package/dist/ui/affix-group.js +9 -7
  235. package/dist/ui/affix-group.js.map +1 -1
  236. package/dist/ui/avatar.d.ts +3 -0
  237. package/dist/ui/avatar.js +52 -0
  238. package/dist/ui/avatar.js.map +1 -0
  239. package/dist/ui/button.d.ts +5 -3
  240. package/dist/ui/button.js +10 -3
  241. package/dist/ui/button.js.map +1 -1
  242. package/dist/ui/chart-view.js +155 -28
  243. package/dist/ui/chart-view.js.map +1 -1
  244. package/dist/ui/click-behavior.d.ts +4 -4
  245. package/dist/ui/click-behavior.js.map +1 -1
  246. package/dist/ui/collapsible.js +3 -15
  247. package/dist/ui/collapsible.js.map +1 -1
  248. package/dist/ui/color-picker.d.ts +8 -0
  249. package/dist/ui/color-picker.js +59 -0
  250. package/dist/ui/color-picker.js.map +1 -0
  251. package/dist/ui/combobox.d.ts +11 -2
  252. package/dist/ui/combobox.js +57 -11
  253. package/dist/ui/combobox.js.map +1 -1
  254. package/dist/ui/confirm-dialog.js +1 -1
  255. package/dist/ui/confirm-dialog.js.map +1 -1
  256. package/dist/ui/control.d.ts +1 -1
  257. package/dist/ui/copyable-text.d.ts +7 -0
  258. package/dist/ui/copyable-text.js +21 -13
  259. package/dist/ui/copyable-text.js.map +1 -1
  260. package/dist/ui/dialog.d.ts +6 -2
  261. package/dist/ui/dialog.js +29 -5
  262. package/dist/ui/dialog.js.map +1 -1
  263. package/dist/ui/fragment.js +1 -1
  264. package/dist/ui/fragment.js.map +1 -1
  265. package/dist/ui/heading.js +39 -21
  266. package/dist/ui/heading.js.map +1 -1
  267. package/dist/ui/icon-button.d.ts +22 -0
  268. package/dist/ui/icon-button.js +51 -0
  269. package/dist/ui/icon-button.js.map +1 -0
  270. package/dist/ui/icon.js +10 -11
  271. package/dist/ui/icon.js.map +1 -1
  272. package/dist/ui/image-preview.d.ts +12 -0
  273. package/dist/ui/image-preview.js +65 -0
  274. package/dist/ui/image-preview.js.map +1 -0
  275. package/dist/ui/image.d.ts +3 -0
  276. package/dist/ui/image.js +21 -0
  277. package/dist/ui/image.js.map +1 -0
  278. package/dist/ui/index.d.ts +2 -1
  279. package/dist/ui/index.js +4 -3
  280. package/dist/ui/info-tooltip.js +1 -1
  281. package/dist/ui/info-tooltip.js.map +1 -1
  282. package/dist/ui/input.d.ts +3 -1
  283. package/dist/ui/input.js +2 -2
  284. package/dist/ui/input.js.map +1 -1
  285. package/dist/ui/modal.js +17 -4
  286. package/dist/ui/modal.js.map +1 -1
  287. package/dist/ui/native-select.d.ts +10 -0
  288. package/dist/ui/native-select.js +23 -0
  289. package/dist/ui/native-select.js.map +1 -0
  290. package/dist/ui/pill.d.ts +2 -0
  291. package/dist/ui/pill.js +10 -0
  292. package/dist/ui/pill.js.map +1 -0
  293. package/dist/ui/plugin.js +11 -1
  294. package/dist/ui/plugin.js.map +1 -1
  295. package/dist/ui/progress.d.ts +3 -0
  296. package/dist/ui/progress.js +114 -0
  297. package/dist/ui/progress.js.map +1 -0
  298. package/dist/ui/section.js +2 -15
  299. package/dist/ui/section.js.map +1 -1
  300. package/dist/ui/segmented-pills.js +2 -1
  301. package/dist/ui/segmented-pills.js.map +1 -1
  302. package/dist/ui/separator.d.ts +3 -0
  303. package/dist/ui/separator.js +15 -0
  304. package/dist/ui/separator.js.map +1 -0
  305. package/dist/ui/tabs.js +12 -10
  306. package/dist/ui/tabs.js.map +1 -1
  307. package/dist/ui/text.js +5 -10
  308. package/dist/ui/text.js.map +1 -1
  309. package/dist/ui/tree-context.d.ts +33 -0
  310. package/dist/ui/tree-context.js +135 -0
  311. package/dist/ui/tree-context.js.map +1 -0
  312. package/dist/ui/tree.d.ts +19 -0
  313. package/dist/ui/tree.js +187 -0
  314. package/dist/ui/tree.js.map +1 -0
  315. package/dist/ui/use-collapsible-state.d.ts +7 -0
  316. package/dist/ui/use-collapsible-state.js +21 -0
  317. package/dist/ui/use-collapsible-state.js.map +1 -0
  318. package/dist-standalone/chunks/chart-view-C6R5iPra.js +36 -0
  319. package/dist-standalone/chunks/date-picker-field-DhhEB-Mh.js +1 -0
  320. package/dist-standalone/chunks/jsx-runtime-Drll_-DD.js +1 -0
  321. package/dist-standalone/chunks/locale-CXqr7LPR.js +1 -0
  322. package/dist-standalone/chunks/page-props-DOfg30l5.js +1 -0
  323. package/dist-standalone/chunks/rich-editor-field-DORXTHPw.js +154 -0
  324. package/dist-standalone/chunks/{subscriptions-B3UuDBmx.js → subscriptions-B_ISgA7V.js} +1 -1
  325. package/dist-standalone/chunks/use-effect-dispatcher-D1wPPwHj.js +97 -0
  326. package/dist-standalone/lattice.css +1 -1
  327. package/dist-standalone/lattice.js +15 -15
  328. package/dist-standalone/manifest.json +11 -9
  329. package/dist-standalone/sprite.svg +1 -1
  330. package/package.json +6 -1
  331. package/resources/icons/code-xml.svg +17 -0
  332. package/resources/icons/heading.svg +17 -0
  333. package/dist/clipboard/index.js.map +0 -1
  334. package/dist/events/event-names.js.map +0 -1
  335. package/dist/table/components/table-action-node.d.ts +0 -4
  336. package/dist/table/components/table-action-node.js +0 -24
  337. package/dist/table/components/table-action-node.js.map +0 -1
  338. package/dist-standalone/chunks/chart-view-CK5fKIkR.js +0 -36
  339. package/dist-standalone/chunks/date-picker-field-BlCPFhZd.js +0 -1
  340. package/dist-standalone/chunks/jsx-runtime-CJ_btYLc.js +0 -1
  341. package/dist-standalone/chunks/rich-editor-field-DH5dS5c1.js +0 -154
  342. package/dist-standalone/chunks/use-effect-dispatcher-k98Nzf9M.js +0 -97
  343. /package/dist/{events → core}/event-names.d.ts +0 -0
@@ -1,2 +1,2 @@
1
- export type { ComponentProps, DateFormat, Node, NodeProps, NumberFormat, PageContainer, PageBreadcrumb, PagePayload, PropsOf, RendererComponent, } from '../index.js';
1
+ export type { ComponentProps, DateFormat, Node, NodeProps, NumberFormat, PageContainer, PageBreadcrumb, PagePayload, ComponentPropsOf, RendererComponent, } from '../index.js';
2
2
  export type { Method } from '@inertiajs/core';
@@ -10,8 +10,9 @@ import { Affix } from '../types/generated.js';
10
10
  * affix segments. The control itself stays the focus target; only its own ring
11
11
  * is suppressed.
12
12
  */
13
- export declare function AffixGroup({ prefix, suffix, children, }: {
13
+ export declare function AffixGroup({ prefix, suffix, end, children, }: {
14
14
  prefix?: Affix | null;
15
15
  suffix?: Affix | null;
16
+ end?: ReactNode;
16
17
  children: (controlClassName: string) => ReactNode;
17
18
  }): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
@@ -2,10 +2,10 @@ import { cn } from "../lib/utils.js";
2
2
  import { IconRenderer } from "../icons/icon-renderer.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region resources/js/ui/affix-group.tsx
5
- function AffixSegment({ affix, side }) {
5
+ function AffixSegment({ affix, side, squared = false }) {
6
6
  return /* @__PURE__ */ jsx("span", {
7
7
  "data-slot": `affix-${side}`,
8
- className: cn("inline-flex h-lt-control-md shrink-0 items-center border border-lt-input bg-lt-muted px-3 text-base whitespace-nowrap text-lt-muted-fg", "group-has-[:focus-visible]:border-lt-ring", side === "start" ? "rounded-l-lt-sm border-r-0" : "rounded-r-lt-sm border-l-0"),
8
+ className: cn("inline-flex h-lt-control-md shrink-0 items-center border border-lt-input bg-lt-muted px-3 text-base whitespace-nowrap text-lt-muted-fg", "group-has-[:focus-visible]:border-lt-ring", side === "start" ? "rounded-l-lt-sm border-r-0" : "rounded-r-lt-sm border-l-0", squared && "rounded-r-none border-r-0"),
9
9
  children: affix.icon ? /* @__PURE__ */ jsx(IconRenderer, {
10
10
  className: "size-lt-icon-md",
11
11
  icon: affix.icon
@@ -22,8 +22,8 @@ function AffixSegment({ affix, side }) {
22
22
  * affix segments. The control itself stays the focus target; only its own ring
23
23
  * is suppressed.
24
24
  */
25
- function AffixGroup({ prefix, suffix, children }) {
26
- if (!prefix && !suffix) return children("");
25
+ function AffixGroup({ prefix, suffix, end, children }) {
26
+ if (!prefix && !suffix && !end) return children("");
27
27
  return /* @__PURE__ */ jsxs("div", {
28
28
  className: "group flex w-full rounded-lt-sm transition-[color,box-shadow] has-[:focus-visible]:ring-[3px] has-[:focus-visible]:ring-lt-ring/50",
29
29
  "data-slot": "affix-group",
@@ -34,12 +34,14 @@ function AffixGroup({ prefix, suffix, children }) {
34
34
  }) : null,
35
35
  /* @__PURE__ */ jsx("div", {
36
36
  className: "min-w-0 flex-1",
37
- children: children(cn("focus-visible:ring-0", prefix && "rounded-l-none", suffix && "rounded-r-none"))
37
+ children: children(cn("focus-visible:ring-0", prefix && "rounded-l-none", (suffix || end) && "rounded-r-none"))
38
38
  }),
39
39
  suffix ? /* @__PURE__ */ jsx(AffixSegment, {
40
40
  affix: suffix,
41
- side: "end"
42
- }) : null
41
+ side: "end",
42
+ squared: Boolean(end)
43
+ }) : null,
44
+ end
43
45
  ]
44
46
  });
45
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"affix-group.js","names":[],"sources":["../../resources/js/ui/affix-group.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { Affix } from \"@lattice-php/lattice/types/generated\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nfunction AffixSegment({ affix, side }: { affix: Affix; side: \"start\" | \"end\" }) {\n return (\n <span\n data-slot={`affix-${side}`}\n className={cn(\n \"inline-flex h-lt-control-md shrink-0 items-center border border-lt-input bg-lt-muted px-3 text-base whitespace-nowrap text-lt-muted-fg\",\n \"group-has-[:focus-visible]:border-lt-ring\",\n side === \"start\" ? \"rounded-l-lt-sm border-r-0\" : \"rounded-r-lt-sm border-l-0\",\n )}\n >\n {affix.icon ? <IconRenderer className=\"size-lt-icon-md\" icon={affix.icon} /> : affix.text}\n </span>\n );\n}\n\n/**\n * Wraps a single-line control in a prefix/suffix input group. The control is a\n * render prop receiving the class names that square the corners adjacent to an\n * affix; with no affixes the control renders untouched.\n *\n * The focus ring lives on the group, not the bare input, so it surrounds the\n * whole control — affixes included — instead of being clipped by the opaque\n * affix segments. The control itself stays the focus target; only its own ring\n * is suppressed.\n */\nexport function AffixGroup({\n prefix,\n suffix,\n children,\n}: {\n prefix?: Affix | null;\n suffix?: Affix | null;\n children: (controlClassName: string) => ReactNode;\n}) {\n if (!prefix && !suffix) {\n return children(\"\");\n }\n\n return (\n <div\n className=\"group flex w-full rounded-lt-sm transition-[color,box-shadow] has-[:focus-visible]:ring-[3px] has-[:focus-visible]:ring-lt-ring/50\"\n data-slot=\"affix-group\"\n >\n {prefix ? <AffixSegment affix={prefix} side=\"start\" /> : null}\n <div className=\"min-w-0 flex-1\">\n {children(\n cn(\"focus-visible:ring-0\", prefix && \"rounded-l-none\", suffix && \"rounded-r-none\"),\n )}\n </div>\n {suffix ? <AffixSegment affix={suffix} side=\"end\" /> : null}\n </div>\n );\n}\n"],"mappings":";;;;AAKA,SAAS,aAAa,EAAE,OAAO,QAAiD;CAC9E,OACE,oBAAC,QAAD;EACE,aAAW,SAAS;EACpB,WAAW,GACT,0IACA,6CACA,SAAS,UAAU,+BAA+B,4BACpD;YAEC,MAAM,OAAO,oBAAC,cAAD;GAAc,WAAU;GAAkB,MAAM,MAAM;EAAO,CAAA,IAAI,MAAM;CACjF,CAAA;AAEV;;;;;;;;;;;AAYA,SAAgB,WAAW,EACzB,QACA,QACA,YAKC;CACD,IAAI,CAAC,UAAU,CAAC,QACd,OAAO,SAAS,EAAE;CAGpB,OACE,qBAAC,OAAD;EACE,WAAU;EACV,aAAU;YAFZ;GAIG,SAAS,oBAAC,cAAD;IAAc,OAAO;IAAQ,MAAK;GAAS,CAAA,IAAI;GACzD,oBAAC,OAAD;IAAK,WAAU;cACZ,SACC,GAAG,wBAAwB,UAAU,kBAAkB,UAAU,gBAAgB,CACnF;GACG,CAAA;GACJ,SAAS,oBAAC,cAAD;IAAc,OAAO;IAAQ,MAAK;GAAO,CAAA,IAAI;EACpD;;AAET"}
1
+ {"version":3,"file":"affix-group.js","names":[],"sources":["../../resources/js/ui/affix-group.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { Affix } from \"@lattice-php/lattice/types/generated\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nfunction AffixSegment({\n affix,\n side,\n squared = false,\n}: {\n affix: Affix;\n side: \"start\" | \"end\";\n squared?: boolean;\n}) {\n return (\n <span\n data-slot={`affix-${side}`}\n className={cn(\n \"inline-flex h-lt-control-md shrink-0 items-center border border-lt-input bg-lt-muted px-3 text-base whitespace-nowrap text-lt-muted-fg\",\n \"group-has-[:focus-visible]:border-lt-ring\",\n side === \"start\" ? \"rounded-l-lt-sm border-r-0\" : \"rounded-r-lt-sm border-l-0\",\n squared && \"rounded-r-none border-r-0\",\n )}\n >\n {affix.icon ? <IconRenderer className=\"size-lt-icon-md\" icon={affix.icon} /> : affix.text}\n </span>\n );\n}\n\n/**\n * Wraps a single-line control in a prefix/suffix input group. The control is a\n * render prop receiving the class names that square the corners adjacent to an\n * affix; with no affixes the control renders untouched.\n *\n * The focus ring lives on the group, not the bare input, so it surrounds the\n * whole control — affixes included — instead of being clipped by the opaque\n * affix segments. The control itself stays the focus target; only its own ring\n * is suppressed.\n */\nexport function AffixGroup({\n prefix,\n suffix,\n end,\n children,\n}: {\n prefix?: Affix | null;\n suffix?: Affix | null;\n end?: ReactNode;\n children: (controlClassName: string) => ReactNode;\n}) {\n if (!prefix && !suffix && !end) {\n return children(\"\");\n }\n\n return (\n <div\n className=\"group flex w-full rounded-lt-sm transition-[color,box-shadow] has-[:focus-visible]:ring-[3px] has-[:focus-visible]:ring-lt-ring/50\"\n data-slot=\"affix-group\"\n >\n {prefix ? <AffixSegment affix={prefix} side=\"start\" /> : null}\n <div className=\"min-w-0 flex-1\">\n {children(\n cn(\n \"focus-visible:ring-0\",\n prefix && \"rounded-l-none\",\n (suffix || end) && \"rounded-r-none\",\n ),\n )}\n </div>\n {suffix ? <AffixSegment affix={suffix} side=\"end\" squared={Boolean(end)} /> : null}\n {end}\n </div>\n );\n}\n"],"mappings":";;;;AAKA,SAAS,aAAa,EACpB,OACA,MACA,UAAU,SAKT;CACD,OACE,oBAAC,QAAD;EACE,aAAW,SAAS;EACpB,WAAW,GACT,0IACA,6CACA,SAAS,UAAU,+BAA+B,8BAClD,WAAW,2BACb;YAEC,MAAM,OAAO,oBAAC,cAAD;GAAc,WAAU;GAAkB,MAAM,MAAM;EAAO,CAAA,IAAI,MAAM;CACjF,CAAA;AAEV;;;;;;;;;;;AAYA,SAAgB,WAAW,EACzB,QACA,QACA,KACA,YAMC;CACD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KACzB,OAAO,SAAS,EAAE;CAGpB,OACE,qBAAC,OAAD;EACE,WAAU;EACV,aAAU;YAFZ;GAIG,SAAS,oBAAC,cAAD;IAAc,OAAO;IAAQ,MAAK;GAAS,CAAA,IAAI;GACzD,oBAAC,OAAD;IAAK,WAAU;cACZ,SACC,GACE,wBACA,UAAU,mBACT,UAAU,QAAQ,gBACrB,CACF;GACG,CAAA;GACJ,SAAS,oBAAC,cAAD;IAAc,OAAO;IAAQ,MAAK;IAAM,SAAS,QAAQ,GAAG;GAAI,CAAA,IAAI;GAC7E;EACE;;AAET"}
@@ -0,0 +1,3 @@
1
+ import { RendererComponent } from '../core/types.js';
2
+ declare const AvatarComponent: RendererComponent<"avatar">;
3
+ export default AvatarComponent;
@@ -0,0 +1,52 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region resources/js/ui/avatar.tsx
4
+ var sizeClass = {
5
+ xs: "size-6 text-[0.5rem]",
6
+ sm: "size-8 text-xs",
7
+ md: "size-10 text-sm",
8
+ lg: "size-12 text-base",
9
+ xl: "size-16 text-lg",
10
+ "2xl": "size-20 text-xl",
11
+ "3xl": "size-24 text-2xl",
12
+ "4xl": "size-32 text-3xl"
13
+ };
14
+ function initials(name) {
15
+ return name.trim().split(/\s+/).slice(0, 2).map((word) => word.charAt(0).toUpperCase()).join("");
16
+ }
17
+ function UserGlyph() {
18
+ return /* @__PURE__ */ jsxs("svg", {
19
+ viewBox: "0 0 24 24",
20
+ fill: "none",
21
+ stroke: "currentColor",
22
+ strokeWidth: 2,
23
+ strokeLinecap: "round",
24
+ strokeLinejoin: "round",
25
+ "aria-hidden": "true",
26
+ className: "size-[60%]",
27
+ children: [/* @__PURE__ */ jsx("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }), /* @__PURE__ */ jsx("circle", {
28
+ cx: "12",
29
+ cy: "7",
30
+ r: "4"
31
+ })]
32
+ });
33
+ }
34
+ var AvatarComponent = ({ node }) => {
35
+ const { src, name, size } = node.props;
36
+ const label = name ?? void 0;
37
+ return /* @__PURE__ */ jsx("span", {
38
+ "data-slot": "avatar",
39
+ role: src ? void 0 : "img",
40
+ "aria-label": src ? void 0 : label,
41
+ className: cn("inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-lt-muted font-medium text-lt-muted-fg select-none", sizeClass[size]),
42
+ children: src ? /* @__PURE__ */ jsx("img", {
43
+ src,
44
+ alt: label ?? "",
45
+ className: "size-full object-cover"
46
+ }) : name ? initials(name) : /* @__PURE__ */ jsx(UserGlyph, {})
47
+ });
48
+ };
49
+ //#endregion
50
+ export { AvatarComponent as default };
51
+
52
+ //# sourceMappingURL=avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatar.js","names":[],"sources":["../../resources/js/ui/avatar.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { Size } from \"@lattice-php/lattice/types/generated\";\n\nconst sizeClass: Record<Size, string> = {\n xs: \"size-6 text-[0.5rem]\",\n sm: \"size-8 text-xs\",\n md: \"size-10 text-sm\",\n lg: \"size-12 text-base\",\n xl: \"size-16 text-lg\",\n \"2xl\": \"size-20 text-xl\",\n \"3xl\": \"size-24 text-2xl\",\n \"4xl\": \"size-32 text-3xl\",\n};\n\nfunction initials(name: string): string {\n return name\n .trim()\n .split(/\\s+/)\n .slice(0, 2)\n .map((word) => word.charAt(0).toUpperCase())\n .join(\"\");\n}\n\nfunction UserGlyph() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"size-[60%]\"\n >\n <path d=\"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2\" />\n <circle cx=\"12\" cy=\"7\" r=\"4\" />\n </svg>\n );\n}\n\nconst AvatarComponent: RendererComponent<\"avatar\"> = ({ node }) => {\n const { src, name, size } = node.props;\n const label = name ?? undefined;\n\n return (\n <span\n data-slot=\"avatar\"\n role={src ? undefined : \"img\"}\n aria-label={src ? undefined : label}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-lt-muted font-medium text-lt-muted-fg select-none\",\n sizeClass[size],\n )}\n >\n {src ? (\n <img src={src} alt={label ?? \"\"} className=\"size-full object-cover\" />\n ) : name ? (\n initials(name)\n ) : (\n <UserGlyph />\n )}\n </span>\n );\n};\n\nexport default AvatarComponent;\n"],"mappings":";;;AAIA,IAAM,YAAkC;CACtC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,OAAO;AACT;AAEA,SAAS,SAAS,MAAsB;CACtC,OAAO,KACJ,KAAK,EACL,MAAM,KAAK,EACX,MAAM,GAAG,CAAC,EACV,KAAK,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,CAAC,EAC1C,KAAK,EAAE;AACZ;AAEA,SAAS,YAAY;CACnB,OACE,qBAAC,OAAD;EACE,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAa;EACb,eAAc;EACd,gBAAe;EACf,eAAY;EACZ,WAAU;YARZ,CAUE,oBAAC,QAAD,EAAM,GAAE,4CAA6C,CAAA,GACrD,oBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAI,GAAE;EAAK,CAAA,CAC3B;;AAET;AAEA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,EAAE,KAAK,MAAM,SAAS,KAAK;CACjC,MAAM,QAAQ,QAAQ,KAAA;CAEtB,OACE,oBAAC,QAAD;EACE,aAAU;EACV,MAAM,MAAM,KAAA,IAAY;EACxB,cAAY,MAAM,KAAA,IAAY;EAC9B,WAAW,GACT,sIACA,UAAU,KACZ;YAEC,MACC,oBAAC,OAAD;GAAU;GAAK,KAAK,SAAS;GAAI,WAAU;EAA0B,CAAA,IACnE,OACF,SAAS,IAAI,IAEb,oBAAC,WAAD,CAAY,CAAA;CAEV,CAAA;AAEV"}
@@ -4,11 +4,13 @@ import { ButtonVariant } from '../types/generated.js';
4
4
  import * as React from "react";
5
5
  export type { ButtonVariant };
6
6
  declare const buttonVariants: (props?: ({
7
- variant?: "default" | "destructive" | "ghost" | "info" | "link" | "outline" | "secondary" | "success" | null | undefined;
8
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
7
+ variant?: "link" | "default" | "destructive" | "ghost" | "info" | "outline" | "secondary" | "success" | null | undefined;
8
+ size?: "sm" | "lg" | "default" | "icon" | null | undefined;
9
9
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
10
- declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
10
+ declare function Button({ className, variant, size, asChild, icon, children, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
11
11
  asChild?: boolean;
12
+ /** Leading icon glyph. Ignored with `asChild` (Slot needs a single child). */
13
+ icon?: string;
12
14
  }): React.JSX.Element;
13
15
  declare const ButtonComponent: RendererComponent<"button">;
14
16
  export default ButtonComponent;
package/dist/ui/button.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { cn } from "../lib/utils.js";
2
+ import { Icon } from "../icons/sprite.js";
2
3
  import { IconRenderer } from "../icons/icon-renderer.js";
3
4
  import { nodeIdentity } from "../core/test-id.js";
4
5
  import { ActionTrigger, useClickBehavior } from "./click-behavior.js";
@@ -32,15 +33,21 @@ var buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespa
32
33
  size: "default"
33
34
  }
34
35
  });
35
- function Button({ className, variant, size, asChild = false, ...props }) {
36
- return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
36
+ function Button({ className, variant, size, asChild = false, icon, children, ...props }) {
37
+ const Comp = asChild ? Slot : "button";
38
+ const content = icon && !asChild ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, {
39
+ name: icon,
40
+ "aria-hidden": "true"
41
+ }), children] }) : children;
42
+ return /* @__PURE__ */ jsx(Comp, {
37
43
  "data-slot": "button",
38
44
  className: cn(buttonVariants({
39
45
  variant,
40
46
  size,
41
47
  className
42
48
  })),
43
- ...props
49
+ ...props,
50
+ children: content
44
51
  });
45
52
  }
46
53
  var ButtonComponent = ({ node }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../../resources/js/ui/button.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { ActionTrigger, type TriggerState, useClickBehavior } from \"./click-behavior\";\nimport type { ButtonVariant } from \"@lattice-php/lattice/types/generated\";\n\nexport type { ButtonVariant };\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lt-sm text-base font-medium transition-[color,box-shadow] disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-lt-icon-md [&_svg]:shrink-0 outline-none focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px] aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40 aria-invalid:border-lt-danger\",\n {\n variants: {\n variant: {\n default:\n \"bg-lt-primary text-lt-primary-fg shadow-lt-xs hover:bg-lt-primary-hover active:bg-lt-primary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n destructive:\n \"bg-lt-danger text-lt-danger-fg shadow-lt-xs hover:bg-lt-danger-hover active:bg-lt-danger-active focus-visible:ring-lt-danger/20 dark:focus-visible:ring-lt-danger/40 disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n success:\n \"bg-lt-success text-lt-success-fg shadow-lt-xs hover:bg-lt-success-hover active:bg-lt-success-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n info: \"bg-lt-info text-lt-info-fg shadow-lt-xs hover:bg-lt-info-hover active:bg-lt-info-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n outline:\n \"border border-lt-input bg-lt-bg shadow-lt-xs hover:bg-lt-accent hover:text-lt-accent-fg disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:border-transparent disabled:shadow-none\",\n secondary:\n \"bg-lt-secondary text-lt-secondary-fg shadow-lt-xs hover:bg-lt-secondary-hover active:bg-lt-secondary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n ghost: \"hover:bg-lt-accent hover:text-lt-accent-fg disabled:text-lt-disabled-fg\",\n link: \"text-lt-primary underline-offset-4 hover:underline disabled:text-lt-disabled-fg disabled:no-underline\",\n },\n size: {\n default: \"h-lt-control-md px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-lt-control-sm rounded-lt-sm px-3 has-[>svg]:px-2.5\",\n lg: \"h-lt-control-lg rounded-lt-sm px-6 has-[>svg]:px-4\",\n icon: \"size-lt-control-md\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nconst ButtonComponent: RendererComponent<\"button\"> = ({ node }) => {\n const { label, icon } = node.props;\n const variant = node.props.variant ?? \"default\";\n const testId = nodeIdentity(node);\n const behavior = useClickBehavior(node.props);\n const size = icon ? \"icon\" : \"default\";\n const content = icon ? (\n <>\n <IconRenderer className=\"size-lt-icon-md\" icon={icon} />\n {label ? <span className=\"sr-only\">{label}</span> : null}\n </>\n ) : (\n label\n );\n\n const triggerButton = ({ onClick, processing }: TriggerState) => (\n <Button\n data-test={testId}\n disabled={processing}\n onClick={onClick}\n size={size}\n variant={variant}\n >\n {content}\n </Button>\n );\n\n if (behavior.kind === \"navigate\") {\n return (\n <Button asChild data-test={testId} variant={variant} size={size}>\n <Link href={behavior.href} method={behavior.method}>\n {content}\n </Link>\n </Button>\n );\n }\n\n if (behavior.kind === \"action\") {\n return <ActionTrigger action={behavior.action}>{triggerButton}</ActionTrigger>;\n }\n\n if (behavior.kind === \"effects\") {\n return triggerButton({ onClick: behavior.onClick, processing: false });\n }\n\n return (\n <Button data-test={testId} size={size} type={node.props.buttonType} variant={variant}>\n {content}\n </Button>\n );\n};\n\nexport default ButtonComponent;\nexport { Button, buttonVariants };\n"],"mappings":";;;;;;;;;;AAaA,IAAM,iBAAiB,IACrB,+bACA;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,aACE;GACF,SACE;GACF,MAAM;GACN,SACE;GACF,WACE;GACF,OAAO;GACP,MAAM;EACR;EACA,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,MAAM;EACR;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAEA,SAAS,OAAO,EACd,WACA,SACA,MACA,UAAU,OACV,GAAG,SAIA;CAGH,OACE,oBAHW,UAAU,OAAO,UAG5B;EACE,aAAU;EACV,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAAC;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,EAAE,OAAO,SAAS,KAAK;CAC7B,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,WAAW,iBAAiB,KAAK,KAAK;CAC5C,MAAM,OAAO,OAAO,SAAS;CAC7B,MAAM,UAAU,OACd,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EAAc,WAAU;EAAwB;CAAO,CAAA,GACtD,QAAQ,oBAAC,QAAD;EAAM,WAAU;YAAW;CAAY,CAAA,IAAI,IACpD,EAAA,CAAA,IAEF;CAGF,MAAM,iBAAiB,EAAE,SAAS,iBAChC,oBAAC,QAAD;EACE,aAAW;EACX,UAAU;EACD;EACH;EACG;YAER;CACK,CAAA;CAGV,IAAI,SAAS,SAAS,YACpB,OACE,oBAAC,QAAD;EAAQ,SAAA;EAAQ,aAAW;EAAiB;EAAe;YACzD,oBAAC,MAAD;GAAM,MAAM,SAAS;GAAM,QAAQ,SAAS;aACzC;EACG,CAAA;CACA,CAAA;CAIZ,IAAI,SAAS,SAAS,UACpB,OAAO,oBAAC,eAAD;EAAe,QAAQ,SAAS;YAAS;CAA6B,CAAA;CAG/E,IAAI,SAAS,SAAS,WACpB,OAAO,cAAc;EAAE,SAAS,SAAS;EAAS,YAAY;CAAM,CAAC;CAGvE,OACE,oBAAC,QAAD;EAAQ,aAAW;EAAc;EAAM,MAAM,KAAK,MAAM;EAAqB;YAC1E;CACK,CAAA;AAEZ"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../resources/js/ui/button.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { Icon, IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { ActionTrigger, type TriggerState, useClickBehavior } from \"./click-behavior\";\nimport type { ButtonVariant } from \"@lattice-php/lattice/types/generated\";\n\nexport type { ButtonVariant };\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lt-sm text-base font-medium transition-[color,box-shadow] disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-lt-icon-md [&_svg]:shrink-0 outline-none focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px] aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40 aria-invalid:border-lt-danger\",\n {\n variants: {\n variant: {\n default:\n \"bg-lt-primary text-lt-primary-fg shadow-lt-xs hover:bg-lt-primary-hover active:bg-lt-primary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n destructive:\n \"bg-lt-danger text-lt-danger-fg shadow-lt-xs hover:bg-lt-danger-hover active:bg-lt-danger-active focus-visible:ring-lt-danger/20 dark:focus-visible:ring-lt-danger/40 disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n success:\n \"bg-lt-success text-lt-success-fg shadow-lt-xs hover:bg-lt-success-hover active:bg-lt-success-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n info: \"bg-lt-info text-lt-info-fg shadow-lt-xs hover:bg-lt-info-hover active:bg-lt-info-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n outline:\n \"border border-lt-input bg-lt-bg shadow-lt-xs hover:bg-lt-accent hover:text-lt-accent-fg disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:border-transparent disabled:shadow-none\",\n secondary:\n \"bg-lt-secondary text-lt-secondary-fg shadow-lt-xs hover:bg-lt-secondary-hover active:bg-lt-secondary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n ghost: \"hover:bg-lt-accent hover:text-lt-accent-fg disabled:text-lt-disabled-fg\",\n link: \"text-lt-primary underline-offset-4 hover:underline disabled:text-lt-disabled-fg disabled:no-underline\",\n },\n size: {\n default: \"h-lt-control-md px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-lt-control-sm rounded-lt-sm px-3 has-[>svg]:px-2.5\",\n lg: \"h-lt-control-lg rounded-lt-sm px-6 has-[>svg]:px-4\",\n icon: \"size-lt-control-md\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n icon,\n children,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n /** Leading icon glyph. Ignored with `asChild` (Slot needs a single child). */\n icon?: string;\n }) {\n const Comp = asChild ? Slot : \"button\";\n const content =\n icon && !asChild ? (\n <>\n <Icon name={icon} aria-hidden=\"true\" />\n {children}\n </>\n ) : (\n children\n );\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n >\n {content}\n </Comp>\n );\n}\n\nconst ButtonComponent: RendererComponent<\"button\"> = ({ node }) => {\n const { label, icon } = node.props;\n const variant = node.props.variant ?? \"default\";\n const testId = nodeIdentity(node);\n const behavior = useClickBehavior(node.props);\n const size = icon ? \"icon\" : \"default\";\n const content = icon ? (\n <>\n <IconRenderer className=\"size-lt-icon-md\" icon={icon} />\n {label ? <span className=\"sr-only\">{label}</span> : null}\n </>\n ) : (\n label\n );\n\n const triggerButton = ({ onClick, processing }: TriggerState) => (\n <Button\n data-test={testId}\n disabled={processing}\n onClick={onClick}\n size={size}\n variant={variant}\n >\n {content}\n </Button>\n );\n\n if (behavior.kind === \"navigate\") {\n return (\n <Button asChild data-test={testId} variant={variant} size={size}>\n <Link href={behavior.href} method={behavior.method}>\n {content}\n </Link>\n </Button>\n );\n }\n\n if (behavior.kind === \"action\") {\n return <ActionTrigger action={behavior.action}>{triggerButton}</ActionTrigger>;\n }\n\n if (behavior.kind === \"effects\") {\n return triggerButton({ onClick: behavior.onClick, processing: false });\n }\n\n return (\n <Button data-test={testId} size={size} type={node.props.buttonType} variant={variant}>\n {content}\n </Button>\n );\n};\n\nexport default ButtonComponent;\nexport { Button, buttonVariants };\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,iBAAiB,IACrB,+bACA;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,aACE;GACF,SACE;GACF,MAAM;GACN,SACE;GACF,WACE;GACF,OAAO;GACP,MAAM;EACR;EACA,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,MAAM;EACR;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAEA,SAAS,OAAO,EACd,WACA,SACA,MACA,UAAU,OACV,MACA,UACA,GAAG,SAMA;CACH,MAAM,OAAO,UAAU,OAAO;CAC9B,MAAM,UACJ,QAAQ,CAAC,UACP,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;EAAM,MAAM;EAAM,eAAY;CAAQ,CAAA,GACrC,QACD,EAAA,CAAA,IAEF;CAGJ,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAAC;EAC1D,GAAI;YAEH;CACG,CAAA;AAEV;AAEA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,EAAE,OAAO,SAAS,KAAK;CAC7B,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,WAAW,iBAAiB,KAAK,KAAK;CAC5C,MAAM,OAAO,OAAO,SAAS;CAC7B,MAAM,UAAU,OACd,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EAAc,WAAU;EAAwB;CAAO,CAAA,GACtD,QAAQ,oBAAC,QAAD;EAAM,WAAU;YAAW;CAAY,CAAA,IAAI,IACpD,EAAA,CAAA,IAEF;CAGF,MAAM,iBAAiB,EAAE,SAAS,iBAChC,oBAAC,QAAD;EACE,aAAW;EACX,UAAU;EACD;EACH;EACG;YAER;CACK,CAAA;CAGV,IAAI,SAAS,SAAS,YACpB,OACE,oBAAC,QAAD;EAAQ,SAAA;EAAQ,aAAW;EAAiB;EAAe;YACzD,oBAAC,MAAD;GAAM,MAAM,SAAS;GAAM,QAAQ,SAAS;aACzC;EACG,CAAA;CACA,CAAA;CAIZ,IAAI,SAAS,SAAS,UACpB,OAAO,oBAAC,eAAD;EAAe,QAAQ,SAAS;YAAS;CAA6B,CAAA;CAG/E,IAAI,SAAS,SAAS,WACpB,OAAO,cAAc;EAAE,SAAS,SAAS;EAAS,YAAY;CAAM,CAAC;CAGvE,OACE,oBAAC,QAAD;EAAQ,aAAW;EAAc;EAAM,MAAM,KAAK,MAAM;EAAqB;YAC1E;CACK,CAAA;AAEZ"}
@@ -1,9 +1,11 @@
1
- import { useLocale } from "../i18n/locale.js";
2
- import { useTimezone } from "../i18n/timezone.js";
1
+ import { isRecord } from "../core/materialize.js";
3
2
  import { nodeIdentity } from "../core/test-id.js";
3
+ import { coerceColor, colorValue } from "../lib/color.js";
4
+ import { numericValue } from "../format/numeric.js";
5
+ import { useFormatContext } from "../format/format-context.js";
4
6
  import { formatValue } from "../format/value.js";
5
7
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, ComposedChart, Legend, Line, LineChart, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
8
+ import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, ComposedChart, Legend, Line, LineChart, Pie, PieChart, PolarAngleAxis, RadialBar, RadialBarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
7
9
  //#region resources/js/ui/chart-view.tsx
8
10
  var chartMargin = {
9
11
  bottom: 0,
@@ -46,16 +48,27 @@ var palette = [
46
48
  function colorAt(index) {
47
49
  return palette[index % palette.length] ?? "var(--lt-primary)";
48
50
  }
49
- function isRecord(value) {
50
- return typeof value === "object" && value !== null && !Array.isArray(value);
51
- }
52
51
  function datumColor(datum, series, index) {
53
- if (isRecord(datum) && typeof datum.color === "string") return datum.color;
54
- return series.color ?? colorAt(index);
52
+ if (isRecord(datum)) {
53
+ const color = coerceColor(datum.color);
54
+ if (color) return colorValue(color);
55
+ }
56
+ return series.color ? colorValue(series.color) : colorAt(index);
55
57
  }
56
58
  function isCartesianSeries(series) {
57
59
  return series.type === "area" || series.type === "bar" || series.type === "line";
58
60
  }
61
+ function isSpecialSeries(series) {
62
+ return !isCartesianSeries(series);
63
+ }
64
+ function datumValue(datum, key) {
65
+ return isRecord(datum) ? numericValue(datum[key]) ?? 0 : 0;
66
+ }
67
+ function datumName(datum, series) {
68
+ if (series.nameKey === null || !isRecord(datum)) return series.name;
69
+ const name = datum[series.nameKey];
70
+ return typeof name === "string" ? name : series.name;
71
+ }
59
72
  function cartesianChartFor(series) {
60
73
  const types = new Set(series.map((item) => item.type));
61
74
  const firstSeries = series[0];
@@ -85,12 +98,7 @@ function ChartFrame({ children, description, id, title }) {
85
98
  function CartesianChart({ props }) {
86
99
  const series = props.series.filter(isCartesianSeries);
87
100
  const RechartsChart = cartesianChartFor(series);
88
- const { locale } = useLocale();
89
- const { timezone } = useTimezone();
90
- const ctx = {
91
- locale,
92
- timezone
93
- };
101
+ const ctx = useFormatContext();
94
102
  const formatCategory = (value) => formatValue(value, props.categoryFormat, ctx);
95
103
  const formatValueTick = (value) => formatValue(value, props.valueFormat, ctx);
96
104
  const tooltipCursor = series.some((item) => item.type === "bar") ? {
@@ -134,13 +142,13 @@ function CartesianChart({ props }) {
134
142
  }),
135
143
  props.legend && /* @__PURE__ */ jsx(Legend, { ...compactLegendProps }),
136
144
  series.map((item, index) => {
137
- const color = item.color ?? colorAt(index);
145
+ const color = item.color ? colorValue(item.color) : colorAt(index);
138
146
  const key = `${item.type}:${item.dataKey}`;
139
147
  if (item.type === "area") return /* @__PURE__ */ jsx(Area, {
140
148
  dataKey: item.dataKey,
141
149
  fill: color,
142
150
  fillOpacity: .16,
143
- name: item.name ?? void 0,
151
+ name: item.name,
144
152
  stackId: item.stackId ?? void 0,
145
153
  stroke: color,
146
154
  type: "monotone"
@@ -148,7 +156,7 @@ function CartesianChart({ props }) {
148
156
  if (item.type === "bar") return /* @__PURE__ */ jsx(Bar, {
149
157
  dataKey: item.dataKey,
150
158
  fill: color,
151
- name: item.name ?? void 0,
159
+ name: item.name,
152
160
  radius: [
153
161
  4,
154
162
  4,
@@ -160,7 +168,7 @@ function CartesianChart({ props }) {
160
168
  return /* @__PURE__ */ jsx(Line, {
161
169
  dataKey: item.dataKey,
162
170
  dot: false,
163
- name: item.name ?? void 0,
171
+ name: item.name,
164
172
  stroke: color,
165
173
  strokeWidth: 2,
166
174
  type: "monotone"
@@ -171,12 +179,7 @@ function CartesianChart({ props }) {
171
179
  });
172
180
  }
173
181
  function PieChartView({ props, series }) {
174
- const { locale } = useLocale();
175
- const { timezone } = useTimezone();
176
- const ctx = {
177
- locale,
178
- timezone
179
- };
182
+ const ctx = useFormatContext();
180
183
  return /* @__PURE__ */ jsx(ResponsiveContainer, {
181
184
  width: "100%",
182
185
  height: props.height,
@@ -193,8 +196,9 @@ function PieChartView({ props, series }) {
193
196
  /* @__PURE__ */ jsx(Pie, {
194
197
  data: props.data,
195
198
  dataKey: series.dataKey,
196
- name: series.name ?? void 0,
199
+ name: series.name,
197
200
  nameKey: series.nameKey ?? void 0,
201
+ innerRadius: series.innerRadius,
198
202
  outerRadius: "68%",
199
203
  children: props.data.map((datum, index) => /* @__PURE__ */ jsx(Cell, { fill: datumColor(datum, series, index) }, index))
200
204
  })
@@ -202,9 +206,132 @@ function PieChartView({ props, series }) {
202
206
  })
203
207
  });
204
208
  }
209
+ function ChartLegend({ entries }) {
210
+ return /* @__PURE__ */ jsx("div", {
211
+ className: "flex flex-wrap items-center justify-center gap-x-3 gap-y-1",
212
+ children: entries.map((entry, index) => /* @__PURE__ */ jsxs("span", {
213
+ className: "flex items-center gap-1 text-[11px] leading-[14px] text-lt-muted-fg",
214
+ children: [
215
+ /* @__PURE__ */ jsx("span", {
216
+ "aria-hidden": true,
217
+ className: "size-[7px] rounded-full",
218
+ style: { background: entry.color }
219
+ }),
220
+ entry.label,
221
+ entry.value !== void 0 && /* @__PURE__ */ jsx("span", {
222
+ className: "font-medium text-lt-surface-fg",
223
+ children: entry.value
224
+ })
225
+ ]
226
+ }, index))
227
+ });
228
+ }
229
+ function GaugeChartView({ props, series }) {
230
+ const ctx = useFormatContext();
231
+ const values = props.data.map((datum) => datumValue(datum, series.dataKey));
232
+ const max = series.maxValue ?? Math.max(0, ...values);
233
+ const legendEntries = props.data.map((datum, index) => ({
234
+ color: datumColor(datum, series, index),
235
+ label: datumName(datum, series)
236
+ }));
237
+ return /* @__PURE__ */ jsxs("div", {
238
+ className: "flex flex-col gap-1.5",
239
+ children: [props.legend && /* @__PURE__ */ jsx(ChartLegend, { entries: legendEntries }), /* @__PURE__ */ jsxs("div", {
240
+ className: "relative",
241
+ children: [/* @__PURE__ */ jsx(ResponsiveContainer, {
242
+ width: "100%",
243
+ height: props.height,
244
+ debounce: 100,
245
+ children: /* @__PURE__ */ jsxs(RadialBarChart, {
246
+ data: props.data,
247
+ endAngle: -30,
248
+ innerRadius: series.innerRadius,
249
+ margin: chartMargin,
250
+ outerRadius: "100%",
251
+ startAngle: 210,
252
+ children: [
253
+ /* @__PURE__ */ jsx(PolarAngleAxis, {
254
+ type: "number",
255
+ domain: [0, max],
256
+ tick: false
257
+ }),
258
+ props.tooltip && /* @__PURE__ */ jsx(Tooltip, {
259
+ ...tooltipProps,
260
+ formatter: (value) => formatValue(value, props.valueFormat, ctx)
261
+ }),
262
+ /* @__PURE__ */ jsx(RadialBar, {
263
+ background: { fill: "var(--lt-muted)" },
264
+ cornerRadius: 6,
265
+ dataKey: series.dataKey,
266
+ name: series.name,
267
+ children: props.data.map((datum, index) => /* @__PURE__ */ jsx(Cell, { fill: datumColor(datum, series, index) }, index))
268
+ })
269
+ ]
270
+ })
271
+ }), values.length === 1 && /* @__PURE__ */ jsx("div", {
272
+ className: "pointer-events-none absolute inset-0 flex items-center justify-center",
273
+ children: /* @__PURE__ */ jsx("span", {
274
+ className: "text-2xl font-semibold text-lt-surface-fg",
275
+ children: formatValue(values[0], props.valueFormat, ctx)
276
+ })
277
+ })]
278
+ })]
279
+ });
280
+ }
281
+ function DistributionChartView({ props, series }) {
282
+ const ctx = useFormatContext();
283
+ const segments = props.data.map((datum, index) => ({
284
+ color: datumColor(datum, series, index),
285
+ label: datumName(datum, series),
286
+ value: datumValue(datum, series.dataKey)
287
+ })).filter((segment) => segment.value > 0);
288
+ const total = segments.reduce((sum, segment) => sum + segment.value, 0);
289
+ if (total <= 0) return /* @__PURE__ */ jsx("div", {
290
+ className: "h-2.5 w-full rounded-full bg-lt-muted",
291
+ "data-lattice-distribution": ""
292
+ });
293
+ const formatPercent = new Intl.NumberFormat(ctx.locale, {
294
+ maximumFractionDigits: 1,
295
+ style: "percent"
296
+ });
297
+ return /* @__PURE__ */ jsxs("div", {
298
+ className: "flex flex-col gap-1.5",
299
+ children: [/* @__PURE__ */ jsx("div", {
300
+ className: "flex h-2.5 w-full gap-0.5 overflow-hidden rounded-full",
301
+ "data-lattice-distribution": "",
302
+ children: segments.map((segment, index) => /* @__PURE__ */ jsx("div", {
303
+ style: {
304
+ background: segment.color,
305
+ width: `${segment.value / total * 100}%`
306
+ },
307
+ title: props.tooltip ? `${segment.label}: ${formatValue(segment.value, props.valueFormat, ctx)}` : void 0
308
+ }, index))
309
+ }), props.legend && /* @__PURE__ */ jsx(ChartLegend, { entries: segments.map((segment) => ({
310
+ color: segment.color,
311
+ label: segment.label,
312
+ value: formatPercent.format(segment.value / total)
313
+ })) })]
314
+ });
315
+ }
316
+ function SpecialChart({ props, series }) {
317
+ switch (series.type) {
318
+ case "distribution": return /* @__PURE__ */ jsx(DistributionChartView, {
319
+ props,
320
+ series
321
+ });
322
+ case "gauge": return /* @__PURE__ */ jsx(GaugeChartView, {
323
+ props,
324
+ series
325
+ });
326
+ case "pie": return /* @__PURE__ */ jsx(PieChartView, {
327
+ props,
328
+ series
329
+ });
330
+ }
331
+ }
205
332
  var ChartView = ({ node }) => {
206
333
  const props = node.props;
207
- const pieSeries = props.series.find((series) => series.type === "pie");
334
+ const specialSeries = props.series.find(isSpecialSeries);
208
335
  const hasCartesianSeries = props.series.some(isCartesianSeries);
209
336
  return /* @__PURE__ */ jsx(ChartFrame, {
210
337
  description: props.description,
@@ -212,9 +339,9 @@ var ChartView = ({ node }) => {
212
339
  title: props.title,
213
340
  children: /* @__PURE__ */ jsx("div", {
214
341
  className: "min-h-0 w-full",
215
- children: pieSeries && !hasCartesianSeries ? /* @__PURE__ */ jsx(PieChartView, {
342
+ children: specialSeries !== void 0 && !hasCartesianSeries ? /* @__PURE__ */ jsx(SpecialChart, {
216
343
  props,
217
- series: pieSeries
344
+ series: specialSeries
218
345
  }) : /* @__PURE__ */ jsx(CartesianChart, { props })
219
346
  })
220
347
  });
@@ -1 +1 @@
1
- {"version":3,"file":"chart-view.js","names":[],"sources":["../../resources/js/ui/chart-view.tsx"],"sourcesContent":["import {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n ComposedChart,\n Legend,\n Line,\n LineChart,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { PropsOf, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useLocale, useTimezone } from \"@lattice-php/lattice/i18n\";\nimport { formatValue } from \"@lattice-php/lattice/format/value\";\n\ntype ChartProps = PropsOf<\"chart\">;\ntype ChartSeries = ChartProps[\"series\"][number];\ntype ChartDatum = ChartProps[\"data\"][number];\ntype CartesianSeries = ChartSeries & { type: \"area\" | \"bar\" | \"line\" };\ntype ChartMargin = { bottom: number; left: number; right: number; top: number };\ntype CartesianChartComponent = ComponentType<{\n children: ReactNode;\n data: ChartProps[\"data\"];\n margin?: ChartMargin;\n}>;\n\nconst chartMargin: ChartMargin = { bottom: 0, left: 0, right: 16, top: 8 };\nconst compactLegendProps = {\n align: \"center\" as const,\n height: 24,\n iconSize: 7,\n verticalAlign: \"top\" as const,\n wrapperStyle: { fontSize: 11, lineHeight: \"14px\", paddingBottom: 6 },\n};\nconst axisTick = { fontSize: 10 };\nconst tooltipProps = {\n contentStyle: {\n background: \"var(--lt-surface)\",\n border: \"1px solid var(--lt-border)\",\n borderRadius: \"var(--lt-radius-sm)\",\n boxShadow: \"var(--lt-shadow-sm)\",\n color: \"var(--lt-surface-fg)\",\n fontSize: 12,\n },\n itemStyle: { color: \"var(--lt-surface-fg)\" },\n labelStyle: { color: \"var(--lt-muted-fg)\" },\n} as const;\n\nconst palette = [\n \"var(--lt-primary)\",\n \"var(--lt-success)\",\n \"var(--lt-info)\",\n \"var(--lt-warning)\",\n \"var(--lt-danger)\",\n \"var(--lt-muted-fg)\",\n];\n\nfunction colorAt(index: number): string {\n return palette[index % palette.length] ?? \"var(--lt-primary)\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction datumColor(datum: ChartDatum, series: ChartSeries, index: number): string {\n if (isRecord(datum) && typeof datum.color === \"string\") {\n return datum.color;\n }\n\n return series.color ?? colorAt(index);\n}\n\nfunction isCartesianSeries(series: ChartSeries): series is CartesianSeries {\n return series.type === \"area\" || series.type === \"bar\" || series.type === \"line\";\n}\n\nfunction cartesianChartFor(series: CartesianSeries[]): CartesianChartComponent {\n const types = new Set(series.map((item) => item.type));\n const firstSeries = series[0];\n\n if (firstSeries === undefined || types.size !== 1) {\n return ComposedChart;\n }\n\n switch (firstSeries.type) {\n case \"area\":\n return AreaChart;\n case \"bar\":\n return BarChart;\n case \"line\":\n return LineChart;\n }\n}\n\nfunction ChartFrame({\n children,\n description,\n id,\n title,\n}: {\n children: ReactNode;\n description: string | null;\n id?: string;\n title: string | null;\n}) {\n const hasHeader = title !== null || description !== null;\n\n return (\n <div\n className=\"flex flex-col gap-3 rounded-lt border border-lt-border bg-lt-surface p-4 text-lt-surface-fg shadow-lt-sm\"\n data-lattice-component={id}\n >\n {hasHeader && (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n {title !== null && <div className=\"text-sm font-semibold leading-tight\">{title}</div>}\n {description !== null && (\n <div className=\"text-xs leading-5 text-lt-muted-fg\">{description}</div>\n )}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nfunction CartesianChart({ props }: { props: ChartProps }) {\n const series = props.series.filter(isCartesianSeries);\n const RechartsChart = cartesianChartFor(series);\n const { locale } = useLocale();\n const { timezone } = useTimezone();\n const ctx = { locale, timezone };\n const formatCategory = (value: unknown) => formatValue(value, props.categoryFormat, ctx);\n const formatValueTick = (value: unknown) => formatValue(value, props.valueFormat, ctx);\n const hasBarSeries = series.some((item) => item.type === \"bar\");\n const tooltipCursor = hasBarSeries\n ? { fill: \"var(--lt-muted-fg)\", fillOpacity: 0.15 }\n : { stroke: \"var(--lt-muted-fg)\", strokeOpacity: 0.4 };\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <RechartsChart data={props.data} margin={chartMargin}>\n {props.grid && <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--lt-border)\" />}\n {props.xAxis && props.categoryKey !== null && (\n <XAxis\n dataKey={props.categoryKey}\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickFormatter={formatCategory}\n tickLine={false}\n />\n )}\n {props.yAxis && (\n <YAxis\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickFormatter={formatValueTick}\n tickLine={false}\n width={42}\n />\n )}\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n cursor={tooltipCursor}\n formatter={formatValueTick}\n labelFormatter={formatCategory}\n />\n )}\n {props.legend && <Legend {...compactLegendProps} />}\n {series.map((item, index) => {\n const color = item.color ?? colorAt(index);\n const key = `${item.type}:${item.dataKey}`;\n\n if (item.type === \"area\") {\n return (\n <Area\n key={key}\n dataKey={item.dataKey}\n fill={color}\n fillOpacity={0.16}\n name={item.name ?? undefined}\n stackId={item.stackId ?? undefined}\n stroke={color}\n type=\"monotone\"\n />\n );\n }\n\n if (item.type === \"bar\") {\n return (\n <Bar\n key={key}\n dataKey={item.dataKey}\n fill={color}\n name={item.name ?? undefined}\n radius={[4, 4, 0, 0]}\n stackId={item.stackId ?? undefined}\n />\n );\n }\n\n return (\n <Line\n key={key}\n dataKey={item.dataKey}\n dot={false}\n name={item.name ?? undefined}\n stroke={color}\n strokeWidth={2}\n type=\"monotone\"\n />\n );\n })}\n </RechartsChart>\n </ResponsiveContainer>\n );\n}\n\nfunction PieChartView({ props, series }: { props: ChartProps; series: ChartSeries }) {\n const { locale } = useLocale();\n const { timezone } = useTimezone();\n const ctx = { locale, timezone };\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <PieChart margin={chartMargin}>\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n formatter={(value) => formatValue(value, props.valueFormat, ctx)}\n labelFormatter={(value) => formatValue(value, props.categoryFormat, ctx)}\n />\n )}\n {props.legend && <Legend {...compactLegendProps} />}\n <Pie\n data={props.data}\n dataKey={series.dataKey}\n name={series.name ?? undefined}\n nameKey={series.nameKey ?? undefined}\n outerRadius=\"68%\"\n >\n {props.data.map((datum, index) => (\n <Cell key={index} fill={datumColor(datum, series, index)} />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n );\n}\n\nconst ChartView: RendererComponent<\"chart\"> = ({ node }) => {\n const props = node.props;\n const pieSeries = props.series.find((series) => series.type === \"pie\");\n const hasCartesianSeries = props.series.some(isCartesianSeries);\n\n return (\n <ChartFrame description={props.description} id={nodeIdentity(node)} title={props.title}>\n <div className=\"min-h-0 w-full\">\n {pieSeries && !hasCartesianSeries ? (\n <PieChartView props={props} series={pieSeries} />\n ) : (\n <CartesianChart props={props} />\n )}\n </div>\n </ChartFrame>\n );\n};\n\nexport default ChartView;\n"],"mappings":"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"}
1
+ {"version":3,"file":"chart-view.js","names":[],"sources":["../../resources/js/ui/chart-view.tsx"],"sourcesContent":["import {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n ComposedChart,\n Legend,\n Line,\n LineChart,\n Pie,\n PieChart,\n PolarAngleAxis,\n RadialBar,\n RadialBarChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { isRecord } from \"@lattice-php/lattice/core/materialize\";\nimport type { ComponentPropsOf, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { coerceColor, colorValue } from \"@lattice-php/lattice/lib/color\";\nimport { useFormatContext } from \"@lattice-php/lattice/format/format-context\";\nimport { numericValue } from \"@lattice-php/lattice/format/numeric\";\nimport { formatValue } from \"@lattice-php/lattice/format/value\";\n\ntype ChartProps = ComponentPropsOf<\"chart\">;\ntype ChartSeries = ChartProps[\"series\"][number];\ntype ChartDatum = ChartProps[\"data\"][number];\ntype CartesianSeries = ChartSeries & { type: \"area\" | \"bar\" | \"line\" };\ntype SpecialSeries = ChartSeries & { type: \"distribution\" | \"gauge\" | \"pie\" };\ntype ChartMargin = { bottom: number; left: number; right: number; top: number };\ntype CartesianChartComponent = ComponentType<{\n children: ReactNode;\n data: ChartProps[\"data\"];\n margin?: ChartMargin;\n}>;\n\nconst chartMargin: ChartMargin = { bottom: 0, left: 0, right: 16, top: 8 };\nconst compactLegendProps = {\n align: \"center\" as const,\n height: 24,\n iconSize: 7,\n verticalAlign: \"top\" as const,\n wrapperStyle: { fontSize: 11, lineHeight: \"14px\", paddingBottom: 6 },\n};\nconst axisTick = { fontSize: 10 };\nconst tooltipProps = {\n contentStyle: {\n background: \"var(--lt-surface)\",\n border: \"1px solid var(--lt-border)\",\n borderRadius: \"var(--lt-radius-sm)\",\n boxShadow: \"var(--lt-shadow-sm)\",\n color: \"var(--lt-surface-fg)\",\n fontSize: 12,\n },\n itemStyle: { color: \"var(--lt-surface-fg)\" },\n labelStyle: { color: \"var(--lt-muted-fg)\" },\n} as const;\n\nconst palette = [\n \"var(--lt-primary)\",\n \"var(--lt-success)\",\n \"var(--lt-info)\",\n \"var(--lt-warning)\",\n \"var(--lt-danger)\",\n \"var(--lt-muted-fg)\",\n];\n\nfunction colorAt(index: number): string {\n return palette[index % palette.length] ?? \"var(--lt-primary)\";\n}\n\nfunction datumColor(datum: ChartDatum, series: ChartSeries, index: number): string {\n if (isRecord(datum)) {\n const color = coerceColor(datum.color);\n\n if (color) {\n return colorValue(color);\n }\n }\n\n return series.color ? colorValue(series.color) : colorAt(index);\n}\n\nfunction isCartesianSeries(series: ChartSeries): series is CartesianSeries {\n return series.type === \"area\" || series.type === \"bar\" || series.type === \"line\";\n}\n\nfunction isSpecialSeries(series: ChartSeries): series is SpecialSeries {\n return !isCartesianSeries(series);\n}\n\nfunction datumValue(datum: ChartDatum, key: string): number {\n return isRecord(datum) ? (numericValue(datum[key]) ?? 0) : 0;\n}\n\nfunction datumName(datum: ChartDatum, series: ChartSeries): string {\n if (series.nameKey === null || !isRecord(datum)) {\n return series.name;\n }\n\n const name = datum[series.nameKey];\n\n return typeof name === \"string\" ? name : series.name;\n}\n\nfunction cartesianChartFor(series: CartesianSeries[]): CartesianChartComponent {\n const types = new Set(series.map((item) => item.type));\n const firstSeries = series[0];\n\n if (firstSeries === undefined || types.size !== 1) {\n return ComposedChart;\n }\n\n switch (firstSeries.type) {\n case \"area\":\n return AreaChart;\n case \"bar\":\n return BarChart;\n case \"line\":\n return LineChart;\n }\n}\n\nfunction ChartFrame({\n children,\n description,\n id,\n title,\n}: {\n children: ReactNode;\n description: string | null;\n id?: string;\n title: string | null;\n}) {\n const hasHeader = title !== null || description !== null;\n\n return (\n <div\n className=\"flex flex-col gap-3 rounded-lt border border-lt-border bg-lt-surface p-4 text-lt-surface-fg shadow-lt-sm\"\n data-lattice-component={id}\n >\n {hasHeader && (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n {title !== null && <div className=\"text-sm font-semibold leading-tight\">{title}</div>}\n {description !== null && (\n <div className=\"text-xs leading-5 text-lt-muted-fg\">{description}</div>\n )}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nfunction CartesianChart({ props }: { props: ChartProps }) {\n const series = props.series.filter(isCartesianSeries);\n const RechartsChart = cartesianChartFor(series);\n const ctx = useFormatContext();\n const formatCategory = (value: unknown) => formatValue(value, props.categoryFormat, ctx);\n const formatValueTick = (value: unknown) => formatValue(value, props.valueFormat, ctx);\n const hasBarSeries = series.some((item) => item.type === \"bar\");\n const tooltipCursor = hasBarSeries\n ? { fill: \"var(--lt-muted-fg)\", fillOpacity: 0.15 }\n : { stroke: \"var(--lt-muted-fg)\", strokeOpacity: 0.4 };\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <RechartsChart data={props.data} margin={chartMargin}>\n {props.grid && <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--lt-border)\" />}\n {props.xAxis && props.categoryKey !== null && (\n <XAxis\n dataKey={props.categoryKey}\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickFormatter={formatCategory}\n tickLine={false}\n />\n )}\n {props.yAxis && (\n <YAxis\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickFormatter={formatValueTick}\n tickLine={false}\n width={42}\n />\n )}\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n cursor={tooltipCursor}\n formatter={formatValueTick}\n labelFormatter={formatCategory}\n />\n )}\n {props.legend && <Legend {...compactLegendProps} />}\n {series.map((item, index) => {\n const color = item.color ? colorValue(item.color) : colorAt(index);\n const key = `${item.type}:${item.dataKey}`;\n\n if (item.type === \"area\") {\n return (\n <Area\n key={key}\n dataKey={item.dataKey}\n fill={color}\n fillOpacity={0.16}\n name={item.name}\n stackId={item.stackId ?? undefined}\n stroke={color}\n type=\"monotone\"\n />\n );\n }\n\n if (item.type === \"bar\") {\n return (\n <Bar\n key={key}\n dataKey={item.dataKey}\n fill={color}\n name={item.name}\n radius={[4, 4, 0, 0]}\n stackId={item.stackId ?? undefined}\n />\n );\n }\n\n return (\n <Line\n key={key}\n dataKey={item.dataKey}\n dot={false}\n name={item.name}\n stroke={color}\n strokeWidth={2}\n type=\"monotone\"\n />\n );\n })}\n </RechartsChart>\n </ResponsiveContainer>\n );\n}\n\nfunction PieChartView({ props, series }: { props: ChartProps; series: ChartSeries }) {\n const ctx = useFormatContext();\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <PieChart margin={chartMargin}>\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n formatter={(value) => formatValue(value, props.valueFormat, ctx)}\n labelFormatter={(value) => formatValue(value, props.categoryFormat, ctx)}\n />\n )}\n {props.legend && <Legend {...compactLegendProps} />}\n <Pie\n data={props.data}\n dataKey={series.dataKey}\n name={series.name}\n nameKey={series.nameKey ?? undefined}\n innerRadius={series.innerRadius}\n outerRadius=\"68%\"\n >\n {props.data.map((datum, index) => (\n <Cell key={index} fill={datumColor(datum, series, index)} />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n );\n}\n\nfunction ChartLegend({\n entries,\n}: {\n entries: Array<{ color: string; label: string; value?: string }>;\n}) {\n return (\n <div className=\"flex flex-wrap items-center justify-center gap-x-3 gap-y-1\">\n {entries.map((entry, index) => (\n <span\n key={index}\n className=\"flex items-center gap-1 text-[11px] leading-[14px] text-lt-muted-fg\"\n >\n <span\n aria-hidden\n className=\"size-[7px] rounded-full\"\n style={{ background: entry.color }}\n />\n {entry.label}\n {entry.value !== undefined && (\n <span className=\"font-medium text-lt-surface-fg\">{entry.value}</span>\n )}\n </span>\n ))}\n </div>\n );\n}\n\nfunction GaugeChartView({ props, series }: { props: ChartProps; series: ChartSeries }) {\n const ctx = useFormatContext();\n const values = props.data.map((datum) => datumValue(datum, series.dataKey));\n const max = series.maxValue ?? Math.max(0, ...values);\n const legendEntries = props.data.map((datum, index) => ({\n color: datumColor(datum, series, index),\n label: datumName(datum, series),\n }));\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n {props.legend && <ChartLegend entries={legendEntries} />}\n <div className=\"relative\">\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <RadialBarChart\n data={props.data}\n endAngle={-30}\n innerRadius={series.innerRadius}\n margin={chartMargin}\n outerRadius=\"100%\"\n startAngle={210}\n >\n <PolarAngleAxis type=\"number\" domain={[0, max]} tick={false} />\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n formatter={(value) => formatValue(value, props.valueFormat, ctx)}\n />\n )}\n <RadialBar\n background={{ fill: \"var(--lt-muted)\" }}\n cornerRadius={6}\n dataKey={series.dataKey}\n name={series.name}\n >\n {props.data.map((datum, index) => (\n <Cell key={index} fill={datumColor(datum, series, index)} />\n ))}\n </RadialBar>\n </RadialBarChart>\n </ResponsiveContainer>\n {values.length === 1 && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n <span className=\"text-2xl font-semibold text-lt-surface-fg\">\n {formatValue(values[0], props.valueFormat, ctx)}\n </span>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction DistributionChartView({ props, series }: { props: ChartProps; series: ChartSeries }) {\n const ctx = useFormatContext();\n const segments = props.data\n .map((datum, index) => ({\n color: datumColor(datum, series, index),\n label: datumName(datum, series),\n value: datumValue(datum, series.dataKey),\n }))\n .filter((segment) => segment.value > 0);\n const total = segments.reduce((sum, segment) => sum + segment.value, 0);\n\n if (total <= 0) {\n return <div className=\"h-2.5 w-full rounded-full bg-lt-muted\" data-lattice-distribution=\"\" />;\n }\n\n const formatPercent = new Intl.NumberFormat(ctx.locale, {\n maximumFractionDigits: 1,\n style: \"percent\",\n });\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n <div\n className=\"flex h-2.5 w-full gap-0.5 overflow-hidden rounded-full\"\n data-lattice-distribution=\"\"\n >\n {segments.map((segment, index) => (\n <div\n key={index}\n style={{ background: segment.color, width: `${(segment.value / total) * 100}%` }}\n title={\n props.tooltip\n ? `${segment.label}: ${formatValue(segment.value, props.valueFormat, ctx)}`\n : undefined\n }\n />\n ))}\n </div>\n {props.legend && (\n <ChartLegend\n entries={segments.map((segment) => ({\n color: segment.color,\n label: segment.label,\n value: formatPercent.format(segment.value / total),\n }))}\n />\n )}\n </div>\n );\n}\n\nfunction SpecialChart({ props, series }: { props: ChartProps; series: SpecialSeries }) {\n switch (series.type) {\n case \"distribution\":\n return <DistributionChartView props={props} series={series} />;\n case \"gauge\":\n return <GaugeChartView props={props} series={series} />;\n case \"pie\":\n return <PieChartView props={props} series={series} />;\n }\n}\n\nconst ChartView: RendererComponent<\"chart\"> = ({ node }) => {\n const props = node.props;\n const specialSeries = props.series.find(isSpecialSeries);\n const hasCartesianSeries = props.series.some(isCartesianSeries);\n\n return (\n <ChartFrame description={props.description} id={nodeIdentity(node)} title={props.title}>\n <div className=\"min-h-0 w-full\">\n {specialSeries !== undefined && !hasCartesianSeries ? (\n <SpecialChart props={props} series={specialSeries} />\n ) : (\n <CartesianChart props={props} />\n )}\n </div>\n </ChartFrame>\n );\n};\n\nexport default ChartView;\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ export type ClickBehavior = {
8
8
  method: Method;
9
9
  } | {
10
10
  kind: "action";
11
- action: Node<"action">;
11
+ action: Node<"action" | "action.bulk">;
12
12
  } | {
13
13
  kind: "effects";
14
14
  onClick: () => void;
@@ -20,7 +20,7 @@ export type TriggerState = {
20
20
  processing: boolean;
21
21
  };
22
22
  export type ActionTriggerRenderer = (props: {
23
- action: Node<"action">;
23
+ action: Node<"action" | "action.bulk">;
24
24
  children: (trigger: TriggerState) => ReactNode;
25
25
  }) => ReactNode;
26
26
  export declare function ActionTriggerProvider({ children, render, }: {
@@ -29,12 +29,12 @@ export declare function ActionTriggerProvider({ children, render, }: {
29
29
  }): import("react").JSX.Element;
30
30
  export declare function useActionTrigger(): ActionTriggerRenderer | null;
31
31
  export declare function ActionTrigger({ action, children, }: {
32
- action: Node<"action">;
32
+ action: Node<"action" | "action.bulk">;
33
33
  children: (trigger: TriggerState) => ReactNode;
34
34
  }): import("react").JSX.Element;
35
35
  export declare function useClickBehavior(props: {
36
36
  href?: string | null;
37
37
  method?: Method | null;
38
- action?: Node | null;
38
+ action?: Node<"action" | "action.bulk"> | null;
39
39
  effects?: Effect[] | null;
40
40
  }): ClickBehavior;
@@ -1 +1 @@
1
- {"version":3,"file":"click-behavior.js","names":[],"sources":["../../resources/js/ui/click-behavior.tsx"],"sourcesContent":["import type { Method } from \"@inertiajs/core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport type { Effect } from \"@lattice-php/lattice/types/generated\";\n\nexport type ClickBehavior =\n | { kind: \"navigate\"; href: string; method: Method }\n | { kind: \"action\"; action: Node<\"action\"> }\n | { kind: \"effects\"; onClick: () => void }\n | { kind: \"none\" };\n\nexport type TriggerState = { onClick: () => void; processing: boolean };\n\nexport type ActionTriggerRenderer = (props: {\n action: Node<\"action\">;\n children: (trigger: TriggerState) => ReactNode;\n}) => ReactNode;\n\nconst ActionTriggerContext = createContext<ActionTriggerRenderer | null>(null);\n\nexport function ActionTriggerProvider({\n children,\n render,\n}: {\n children: ReactNode;\n render: ActionTriggerRenderer;\n}) {\n return <ActionTriggerContext.Provider value={render}>{children}</ActionTriggerContext.Provider>;\n}\n\nexport function useActionTrigger(): ActionTriggerRenderer | null {\n return useContext(ActionTriggerContext);\n}\n\nexport function ActionTrigger({\n action,\n children,\n}: {\n action: Node<\"action\">;\n children: (trigger: TriggerState) => ReactNode;\n}) {\n const render = useActionTrigger();\n\n if (!render) {\n throw new Error(\"Action triggers require an ActionTriggerProvider.\");\n }\n\n return <>{render({ action, children })}</>;\n}\n\nexport function useClickBehavior(props: {\n href?: string | null;\n method?: Method | null;\n action?: Node | null;\n effects?: Effect[] | null;\n}): ClickBehavior {\n const dispatch = useEffectDispatcher();\n const action = (props.action ?? null) as Node<\"action\"> | null;\n const effects = props.effects ?? [];\n\n if (action) {\n return { kind: \"action\", action };\n }\n\n if (effects.length > 0) {\n return { kind: \"effects\", onClick: () => dispatch(getActionEffects(effects)) };\n }\n\n if (props.href != null && props.href !== \"\") {\n return { kind: \"navigate\", href: props.href, method: props.method ?? \"get\" };\n }\n\n return { kind: \"none\" };\n}\n"],"mappings":";;;;;AAoBA,IAAM,uBAAuB,cAA4C,IAAI;AAE7E,SAAgB,sBAAsB,EACpC,UACA,UAIC;CACD,OAAO,oBAAC,qBAAqB,UAAtB;EAA+B,OAAO;EAAS;CAAwC,CAAA;AAChG;AAEA,SAAgB,mBAAiD;CAC/D,OAAO,WAAW,oBAAoB;AACxC;AAEA,SAAgB,cAAc,EAC5B,QACA,YAIC;CACD,MAAM,SAAS,iBAAiB;CAEhC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,mDAAmD;CAGrE,OAAO,oBAAA,YAAA,EAAA,UAAG,OAAO;EAAE;EAAQ;CAAS,CAAC,EAAI,CAAA;AAC3C;AAEA,SAAgB,iBAAiB,OAKf;CAChB,MAAM,WAAW,oBAAoB;CACrC,MAAM,SAAU,MAAM,UAAU;CAChC,MAAM,UAAU,MAAM,WAAW,CAAC;CAElC,IAAI,QACF,OAAO;EAAE,MAAM;EAAU;CAAO;CAGlC,IAAI,QAAQ,SAAS,GACnB,OAAO;EAAE,MAAM;EAAW,eAAe,SAAS,iBAAiB,OAAO,CAAC;CAAE;CAG/E,IAAI,MAAM,QAAQ,QAAQ,MAAM,SAAS,IACvC,OAAO;EAAE,MAAM;EAAY,MAAM,MAAM;EAAM,QAAQ,MAAM,UAAU;CAAM;CAG7E,OAAO,EAAE,MAAM,OAAO;AACxB"}
1
+ {"version":3,"file":"click-behavior.js","names":[],"sources":["../../resources/js/ui/click-behavior.tsx"],"sourcesContent":["import type { Method } from \"@inertiajs/core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport type { Effect } from \"@lattice-php/lattice/types/generated\";\n\nexport type ClickBehavior =\n | { kind: \"navigate\"; href: string; method: Method }\n | { kind: \"action\"; action: Node<\"action\" | \"action.bulk\"> }\n | { kind: \"effects\"; onClick: () => void }\n | { kind: \"none\" };\n\nexport type TriggerState = { onClick: () => void; processing: boolean };\n\nexport type ActionTriggerRenderer = (props: {\n action: Node<\"action\" | \"action.bulk\">;\n children: (trigger: TriggerState) => ReactNode;\n}) => ReactNode;\n\nconst ActionTriggerContext = createContext<ActionTriggerRenderer | null>(null);\n\nexport function ActionTriggerProvider({\n children,\n render,\n}: {\n children: ReactNode;\n render: ActionTriggerRenderer;\n}) {\n return <ActionTriggerContext.Provider value={render}>{children}</ActionTriggerContext.Provider>;\n}\n\nexport function useActionTrigger(): ActionTriggerRenderer | null {\n return useContext(ActionTriggerContext);\n}\n\nexport function ActionTrigger({\n action,\n children,\n}: {\n action: Node<\"action\" | \"action.bulk\">;\n children: (trigger: TriggerState) => ReactNode;\n}) {\n const render = useActionTrigger();\n\n if (!render) {\n throw new Error(\"Action triggers require an ActionTriggerProvider.\");\n }\n\n return <>{render({ action, children })}</>;\n}\n\nexport function useClickBehavior(props: {\n href?: string | null;\n method?: Method | null;\n action?: Node<\"action\" | \"action.bulk\"> | null;\n effects?: Effect[] | null;\n}): ClickBehavior {\n const dispatch = useEffectDispatcher();\n const action = props.action ?? null;\n const effects = props.effects ?? [];\n\n if (action) {\n return { kind: \"action\", action };\n }\n\n if (effects.length > 0) {\n return { kind: \"effects\", onClick: () => dispatch(getActionEffects(effects)) };\n }\n\n if (props.href != null && props.href !== \"\") {\n return { kind: \"navigate\", href: props.href, method: props.method ?? \"get\" };\n }\n\n return { kind: \"none\" };\n}\n"],"mappings":";;;;;AAoBA,IAAM,uBAAuB,cAA4C,IAAI;AAE7E,SAAgB,sBAAsB,EACpC,UACA,UAIC;CACD,OAAO,oBAAC,qBAAqB,UAAtB;EAA+B,OAAO;EAAS;CAAwC,CAAA;AAChG;AAEA,SAAgB,mBAAiD;CAC/D,OAAO,WAAW,oBAAoB;AACxC;AAEA,SAAgB,cAAc,EAC5B,QACA,YAIC;CACD,MAAM,SAAS,iBAAiB;CAEhC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,mDAAmD;CAGrE,OAAO,oBAAA,YAAA,EAAA,UAAG,OAAO;EAAE;EAAQ;CAAS,CAAC,EAAI,CAAA;AAC3C;AAEA,SAAgB,iBAAiB,OAKf;CAChB,MAAM,WAAW,oBAAoB;CACrC,MAAM,SAAS,MAAM,UAAU;CAC/B,MAAM,UAAU,MAAM,WAAW,CAAC;CAElC,IAAI,QACF,OAAO;EAAE,MAAM;EAAU;CAAO;CAGlC,IAAI,QAAQ,SAAS,GACnB,OAAO;EAAE,MAAM;EAAW,eAAe,SAAS,iBAAiB,OAAO,CAAC;CAAE;CAG/E,IAAI,MAAM,QAAQ,QAAQ,MAAM,SAAS,IACvC,OAAO;EAAE,MAAM;EAAY,MAAM,MAAM;EAAM,QAAQ,MAAM,UAAU;CAAM;CAG7E,OAAO,EAAE,MAAM,OAAO;AACxB"}