@lattice-php/lattice 0.1.0 → 0.2.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 (367) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +8 -0
  2. package/dist/action/components/action-form.d.ts +24 -0
  3. package/dist/action/components/action-form.js +270 -0
  4. package/dist/action/components/action-form.js.map +1 -0
  5. package/dist/action/components/action-group.d.ts +1 -8
  6. package/dist/action/components/action-group.js +24 -66
  7. package/dist/action/components/action-group.js.map +1 -1
  8. package/dist/action/components/action.d.ts +1 -24
  9. package/dist/action/components/action.js +61 -46
  10. package/dist/action/components/action.js.map +1 -1
  11. package/dist/action/effects.d.ts +6 -25
  12. package/dist/action/effects.js +2 -2
  13. package/dist/action/effects.js.map +1 -1
  14. package/dist/action/index.d.ts +1 -1
  15. package/dist/core/components/badge.d.ts +1 -8
  16. package/dist/core/components/badge.js +2 -3
  17. package/dist/core/components/badge.js.map +1 -1
  18. package/dist/core/components/button.d.ts +4 -12
  19. package/dist/core/components/button.js +6 -9
  20. package/dist/core/components/button.js.map +1 -1
  21. package/dist/core/components/card.d.ts +1 -9
  22. package/dist/core/components/card.js +1 -3
  23. package/dist/core/components/card.js.map +1 -1
  24. package/dist/core/components/confirm-dialog.d.ts +2 -3
  25. package/dist/core/components/confirm-dialog.js +19 -13
  26. package/dist/core/components/confirm-dialog.js.map +1 -1
  27. package/dist/core/components/fragment.d.ts +1 -10
  28. package/dist/core/components/fragment.js +5 -6
  29. package/dist/core/components/fragment.js.map +1 -1
  30. package/dist/core/components/grid.d.ts +1 -8
  31. package/dist/core/components/grid.js +1 -2
  32. package/dist/core/components/grid.js.map +1 -1
  33. package/dist/core/components/heading.d.ts +1 -9
  34. package/dist/core/components/heading.js +2 -3
  35. package/dist/core/components/heading.js.map +1 -1
  36. package/dist/core/components/icon.d.ts +3 -0
  37. package/dist/core/components/icon.js +30 -0
  38. package/dist/core/components/icon.js.map +1 -0
  39. package/dist/core/components/index.d.ts +1 -1
  40. package/dist/core/components/index.js +4 -0
  41. package/dist/core/components/index.js.map +1 -1
  42. package/dist/core/components/link.d.ts +1 -12
  43. package/dist/core/components/link.js +4 -9
  44. package/dist/core/components/link.js.map +1 -1
  45. package/dist/core/components/modal.d.ts +1 -11
  46. package/dist/core/components/modal.js +27 -31
  47. package/dist/core/components/modal.js.map +1 -1
  48. package/dist/core/components/section.d.ts +3 -0
  49. package/dist/core/components/section.js +79 -0
  50. package/dist/core/components/section.js.map +1 -0
  51. package/dist/core/components/segmented-control.d.ts +1 -14
  52. package/dist/core/components/segmented-control.js +4 -7
  53. package/dist/core/components/segmented-control.js.map +1 -1
  54. package/dist/core/components/segmented-pills.d.ts +4 -2
  55. package/dist/core/components/segmented-pills.js +10 -1
  56. package/dist/core/components/segmented-pills.js.map +1 -1
  57. package/dist/core/components/spinner.js +8 -4
  58. package/dist/core/components/spinner.js.map +1 -1
  59. package/dist/core/components/stack.d.ts +1 -11
  60. package/dist/core/components/stack.js +5 -5
  61. package/dist/core/components/stack.js.map +1 -1
  62. package/dist/core/components/tabs.d.ts +1 -19
  63. package/dist/core/components/tabs.js +45 -21
  64. package/dist/core/components/tabs.js.map +1 -1
  65. package/dist/core/components/text.d.ts +1 -9
  66. package/dist/core/components/text.js +2 -3
  67. package/dist/core/components/text.js.map +1 -1
  68. package/dist/core/registry.d.ts +9 -3
  69. package/dist/core/registry.js +21 -5
  70. package/dist/core/registry.js.map +1 -1
  71. package/dist/core/renderer.js +7 -13
  72. package/dist/core/renderer.js.map +1 -1
  73. package/dist/core/types.d.ts +54 -26
  74. package/dist/form/components/base/checkbox.js +5 -2
  75. package/dist/form/components/base/checkbox.js.map +1 -1
  76. package/dist/form/components/base/field.d.ts +2 -1
  77. package/dist/form/components/base/field.js +5 -1
  78. package/dist/form/components/base/field.js.map +1 -1
  79. package/dist/form/components/base/password-input.js +9 -2
  80. package/dist/form/components/base/password-input.js.map +1 -1
  81. package/dist/form/components/base/submit-button.d.ts +4 -4
  82. package/dist/form/components/base/submit-button.js +2 -2
  83. package/dist/form/components/base/submit-button.js.map +1 -1
  84. package/dist/form/components/conditions.d.ts +6 -9
  85. package/dist/form/components/conditions.js +10 -2
  86. package/dist/form/components/conditions.js.map +1 -1
  87. package/dist/form/components/context.d.ts +0 -4
  88. package/dist/form/components/context.js +1 -5
  89. package/dist/form/components/context.js.map +1 -1
  90. package/dist/form/components/field-props.d.ts +24 -0
  91. package/dist/form/components/field-props.js +15 -0
  92. package/dist/form/components/field-props.js.map +1 -0
  93. package/dist/form/components/fields/checkbox.d.ts +1 -15
  94. package/dist/form/components/fields/checkbox.js +16 -21
  95. package/dist/form/components/fields/checkbox.js.map +1 -1
  96. package/dist/form/components/fields/choice.d.ts +1 -13
  97. package/dist/form/components/fields/choice.js +13 -20
  98. package/dist/form/components/fields/choice.js.map +1 -1
  99. package/dist/form/components/fields/date-input.d.ts +1 -19
  100. package/dist/form/components/fields/date-input.js +11 -16
  101. package/dist/form/components/fields/date-input.js.map +1 -1
  102. package/dist/form/components/fields/hidden-input.d.ts +1 -9
  103. package/dist/form/components/fields/hidden-input.js +2 -3
  104. package/dist/form/components/fields/hidden-input.js.map +1 -1
  105. package/dist/form/components/fields/number-input.d.ts +1 -22
  106. package/dist/form/components/fields/number-input.js +38 -41
  107. package/dist/form/components/fields/number-input.js.map +1 -1
  108. package/dist/form/components/fields/password-input.d.ts +1 -28
  109. package/dist/form/components/fields/password-input.js +15 -24
  110. package/dist/form/components/fields/password-input.js.map +1 -1
  111. package/dist/form/components/fields/rich-editor.d.ts +1 -16
  112. package/dist/form/components/fields/rich-editor.js +57 -47
  113. package/dist/form/components/fields/rich-editor.js.map +1 -1
  114. package/dist/form/components/fields/select.d.ts +1 -22
  115. package/dist/form/components/fields/select.js +85 -74
  116. package/dist/form/components/fields/select.js.map +1 -1
  117. package/dist/form/components/fields/simple-field.d.ts +9 -0
  118. package/dist/form/components/fields/simple-field.js +22 -0
  119. package/dist/form/components/fields/simple-field.js.map +1 -0
  120. package/dist/form/components/fields/text-input.d.ts +1 -20
  121. package/dist/form/components/fields/text-input.js +12 -17
  122. package/dist/form/components/fields/text-input.js.map +1 -1
  123. package/dist/form/components/fields/textarea.d.ts +1 -19
  124. package/dist/form/components/fields/textarea.js +11 -16
  125. package/dist/form/components/fields/textarea.js.map +1 -1
  126. package/dist/form/components/form.d.ts +1 -20
  127. package/dist/form/components/form.js +29 -36
  128. package/dist/form/components/form.js.map +1 -1
  129. package/dist/form/components/index.d.ts +0 -1
  130. package/dist/form/components/index.js +1 -2
  131. package/dist/form/components/resolved-nodes.d.ts +1 -1
  132. package/dist/form/components/resolved-nodes.js +2 -2
  133. package/dist/form/components/resolved-nodes.js.map +1 -1
  134. package/dist/form/components/types.d.ts +1 -0
  135. package/dist/form/components/use-controlled-field.d.ts +3 -9
  136. package/dist/form/components/use-controlled-field.js +5 -9
  137. package/dist/form/components/use-controlled-field.js.map +1 -1
  138. package/dist/form/components/use-dependent-field.d.ts +1 -1
  139. package/dist/form/components/use-dependent-field.js +8 -8
  140. package/dist/form/components/use-dependent-field.js.map +1 -1
  141. package/dist/form/components/use-form-resolver.d.ts +1 -1
  142. package/dist/form/components/use-form-resolver.js +8 -13
  143. package/dist/form/components/use-form-resolver.js.map +1 -1
  144. package/dist/form/components/use-seed-default.d.ts +5 -0
  145. package/dist/form/components/use-seed-default.js +23 -0
  146. package/dist/form/components/use-seed-default.js.map +1 -0
  147. package/dist/form/index.d.ts +1 -1
  148. package/dist/form/index.js +0 -1
  149. package/dist/form/index.js.map +1 -1
  150. package/dist/form/skeleton.d.ts +1 -1
  151. package/dist/form/skeleton.js +1 -1
  152. package/dist/form/skeleton.js.map +1 -1
  153. package/dist/i18n/backend.d.ts +24 -0
  154. package/dist/i18n/backend.js +39 -0
  155. package/dist/i18n/backend.js.map +1 -0
  156. package/dist/i18n/index.d.ts +3 -0
  157. package/dist/i18n/index.js +3 -0
  158. package/dist/i18n/instance.js +48 -0
  159. package/dist/i18n/instance.js.map +1 -0
  160. package/dist/icons/icon-renderer.js +30 -5
  161. package/dist/icons/icon-renderer.js.map +1 -1
  162. package/dist/icons/index.d.ts +2 -0
  163. package/dist/icons/index.js +2 -1
  164. package/dist/icons/sprite.d.ts +30 -0
  165. package/dist/icons/sprite.js +40 -0
  166. package/dist/icons/sprite.js.map +1 -0
  167. package/dist/index.d.ts +9 -5
  168. package/dist/index.js +7 -3
  169. package/dist/inertia.d.ts +1 -6
  170. package/dist/inertia.js +4 -8
  171. package/dist/inertia.js.map +1 -1
  172. package/dist/lattice.css +129 -5
  173. package/dist/layout/components.d.ts +1 -0
  174. package/dist/layout/components.js +19 -0
  175. package/dist/layout/components.js.map +1 -0
  176. package/dist/layout/context.d.ts +12 -0
  177. package/dist/layout/context.js +19 -0
  178. package/dist/layout/context.js.map +1 -0
  179. package/dist/layout/index.d.ts +3 -0
  180. package/dist/layout/index.js +4 -0
  181. package/dist/layout/menu-item.d.ts +3 -0
  182. package/dist/layout/menu-item.js +130 -0
  183. package/dist/layout/menu-item.js.map +1 -0
  184. package/dist/layout/menu.d.ts +3 -0
  185. package/dist/layout/menu.js +13 -0
  186. package/dist/layout/menu.js.map +1 -0
  187. package/dist/layout/outlet.d.ts +6 -0
  188. package/dist/layout/outlet.js +14 -0
  189. package/dist/layout/outlet.js.map +1 -0
  190. package/dist/layout/schema-layout.d.ts +10 -0
  191. package/dist/layout/schema-layout.js +30 -0
  192. package/dist/layout/schema-layout.js.map +1 -0
  193. package/dist/layout/sidebar.d.ts +3 -0
  194. package/dist/layout/sidebar.js +48 -0
  195. package/dist/layout/sidebar.js.map +1 -0
  196. package/dist/lib/utils.d.ts +0 -2
  197. package/dist/lib/utils.js +1 -4
  198. package/dist/lib/utils.js.map +1 -1
  199. package/dist/node_modules/i18next/dist/esm/i18next.js +1982 -0
  200. package/dist/node_modules/i18next/dist/esm/i18next.js.map +1 -0
  201. package/dist/node_modules/i18next-http-backend/esm/index.js +352 -0
  202. package/dist/node_modules/i18next-http-backend/esm/index.js.map +1 -0
  203. package/dist/node_modules/react-i18next/dist/es/context.js +23 -0
  204. package/dist/node_modules/react-i18next/dist/es/context.js.map +1 -0
  205. package/dist/node_modules/react-i18next/dist/es/defaults.js +29 -0
  206. package/dist/node_modules/react-i18next/dist/es/defaults.js.map +1 -0
  207. package/dist/node_modules/react-i18next/dist/es/i18nInstance.js +10 -0
  208. package/dist/node_modules/react-i18next/dist/es/i18nInstance.js.map +1 -0
  209. package/dist/node_modules/react-i18next/dist/es/initReactI18next.js +14 -0
  210. package/dist/node_modules/react-i18next/dist/es/initReactI18next.js.map +1 -0
  211. package/dist/node_modules/react-i18next/dist/es/unescape.js +30 -0
  212. package/dist/node_modules/react-i18next/dist/es/unescape.js.map +1 -0
  213. package/dist/node_modules/react-i18next/dist/es/useTranslation.js +157 -0
  214. package/dist/node_modules/react-i18next/dist/es/useTranslation.js.map +1 -0
  215. package/dist/node_modules/react-i18next/dist/es/utils.js +58 -0
  216. package/dist/node_modules/react-i18next/dist/es/utils.js.map +1 -0
  217. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js +70 -0
  218. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js.map +1 -0
  219. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js +61 -0
  220. package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js.map +1 -0
  221. package/dist/node_modules/use-sync-external-store/shim/index.js +13 -0
  222. package/dist/node_modules/use-sync-external-store/shim/index.js.map +1 -0
  223. package/dist/page.d.ts +1 -1
  224. package/dist/page.js +2 -2
  225. package/dist/page.js.map +1 -1
  226. package/dist/provider.d.ts +8 -3
  227. package/dist/provider.js +17 -9
  228. package/dist/provider.js.map +1 -1
  229. package/dist/registry.d.ts +1 -1
  230. package/dist/registry.js +2 -1
  231. package/dist/registry.js.map +1 -1
  232. package/dist/table/bulk.d.ts +6 -10
  233. package/dist/table/bulk.js +13 -35
  234. package/dist/table/bulk.js.map +1 -1
  235. package/dist/table/column-registry.d.ts +9 -0
  236. package/dist/table/components/bulk-bar.js +34 -3
  237. package/dist/table/components/bulk-bar.js.map +1 -1
  238. package/dist/table/components/cells/badge-cell.d.ts +5 -0
  239. package/dist/table/components/cells/badge-cell.js +16 -0
  240. package/dist/table/components/cells/badge-cell.js.map +1 -0
  241. package/dist/table/components/cells/icon-cell.d.ts +5 -0
  242. package/dist/table/components/cells/icon-cell.js +22 -0
  243. package/dist/table/components/cells/icon-cell.js.map +1 -0
  244. package/dist/table/components/cells/image-cell.d.ts +5 -0
  245. package/dist/table/components/cells/image-cell.js +24 -0
  246. package/dist/table/components/cells/image-cell.js.map +1 -0
  247. package/dist/table/components/cells/text-cell.d.ts +6 -0
  248. package/dist/table/components/cells/text-cell.js +50 -0
  249. package/dist/table/components/cells/text-cell.js.map +1 -0
  250. package/dist/table/components/column-filter-control.js +59 -96
  251. package/dist/table/components/column-filter-control.js.map +1 -1
  252. package/dist/table/components/column-header.js +22 -11
  253. package/dist/table/components/column-header.js.map +1 -1
  254. package/dist/table/components/filter-stack-bar.d.ts +2 -2
  255. package/dist/table/components/filter-stack-bar.js +10 -8
  256. package/dist/table/components/filter-stack-bar.js.map +1 -1
  257. package/dist/table/components/filter-value-input.d.ts +5 -3
  258. package/dist/table/components/filter-value-input.js +25 -16
  259. package/dist/table/components/filter-value-input.js.map +1 -1
  260. package/dist/table/components/pagination.d.ts +1 -1
  261. package/dist/table/components/pagination.js +20 -8
  262. package/dist/table/components/pagination.js.map +1 -1
  263. package/dist/table/components/sort-bar.d.ts +2 -2
  264. package/dist/table/components/sort-bar.js +12 -10
  265. package/dist/table/components/sort-bar.js.map +1 -1
  266. package/dist/table/components/table-action-node.d.ts +1 -1
  267. package/dist/table/components/table-action-node.js +1 -1
  268. package/dist/table/components/table-action-node.js.map +1 -1
  269. package/dist/table/components/table-cell.d.ts +1 -1
  270. package/dist/table/components/table-cell.js +24 -43
  271. package/dist/table/components/table-cell.js.map +1 -1
  272. package/dist/table/components/table.d.ts +6 -2
  273. package/dist/table/components/table.js +40 -17
  274. package/dist/table/components/table.js.map +1 -1
  275. package/dist/table/format.js +5 -3
  276. package/dist/table/format.js.map +1 -1
  277. package/dist/table/index.d.ts +1 -1
  278. package/dist/table/index.js.map +1 -1
  279. package/dist/table/payload.d.ts +1 -1
  280. package/dist/table/query.d.ts +0 -1
  281. package/dist/table/query.js +8 -9
  282. package/dist/table/query.js.map +1 -1
  283. package/dist/table/types.d.ts +38 -42
  284. package/dist/table/use-table.d.ts +3 -4
  285. package/dist/table/use-table.js +12 -23
  286. package/dist/table/use-table.js.map +1 -1
  287. package/dist/test-support.d.ts +14 -0
  288. package/dist/test-support.js +14 -0
  289. package/dist/test-support.js.map +1 -0
  290. package/dist/toast/index.d.ts +1 -0
  291. package/dist/toast/index.js +2 -0
  292. package/dist/toast/toaster.d.ts +3 -0
  293. package/dist/toast/toaster.js +126 -0
  294. package/dist/toast/toaster.js.map +1 -0
  295. package/dist/types/generated.d.ts +677 -0
  296. package/dist/types/generated.js +0 -0
  297. package/dist/types/index.d.ts +1 -1
  298. package/package.json +18 -3
  299. package/resources/icons/align-center.svg +17 -0
  300. package/resources/icons/align-justify.svg +17 -0
  301. package/resources/icons/align-left.svg +17 -0
  302. package/resources/icons/align-right.svg +17 -0
  303. package/resources/icons/arrow-down.svg +16 -0
  304. package/resources/icons/arrow-up.svg +16 -0
  305. package/resources/icons/bold.svg +15 -0
  306. package/resources/icons/check.svg +15 -0
  307. package/resources/icons/chevron-down.svg +15 -0
  308. package/resources/icons/chevron-right.svg +15 -0
  309. package/resources/icons/chevrons-up-down.svg +16 -0
  310. package/resources/icons/circle-alert.svg +17 -0
  311. package/resources/icons/circle-check.svg +16 -0
  312. package/resources/icons/circle-help.svg +17 -0
  313. package/resources/icons/circle-x.svg +17 -0
  314. package/resources/icons/code.svg +16 -0
  315. package/resources/icons/columns-3.svg +17 -0
  316. package/resources/icons/copy.svg +16 -0
  317. package/resources/icons/external-link.svg +17 -0
  318. package/resources/icons/eye-off.svg +18 -0
  319. package/resources/icons/eye.svg +16 -0
  320. package/resources/icons/filter.svg +15 -0
  321. package/resources/icons/heading-1.svg +18 -0
  322. package/resources/icons/heading-2.svg +18 -0
  323. package/resources/icons/heading-3.svg +19 -0
  324. package/resources/icons/highlighter.svg +16 -0
  325. package/resources/icons/info.svg +17 -0
  326. package/resources/icons/italic.svg +17 -0
  327. package/resources/icons/layout-dashboard.svg +18 -0
  328. package/resources/icons/link.svg +16 -0
  329. package/resources/icons/list-ordered.svg +20 -0
  330. package/resources/icons/list.svg +20 -0
  331. package/resources/icons/loader-2.svg +15 -0
  332. package/resources/icons/minus.svg +15 -0
  333. package/resources/icons/more-horizontal.svg +17 -0
  334. package/resources/icons/panel-left.svg +16 -0
  335. package/resources/icons/pencil-line.svg +17 -0
  336. package/resources/icons/pencil.svg +16 -0
  337. package/resources/icons/plus.svg +16 -0
  338. package/resources/icons/quote.svg +16 -0
  339. package/resources/icons/rows-3.svg +17 -0
  340. package/resources/icons/search.svg +16 -0
  341. package/resources/icons/send.svg +16 -0
  342. package/resources/icons/settings.svg +16 -0
  343. package/resources/icons/smile.svg +18 -0
  344. package/resources/icons/strikethrough.svg +17 -0
  345. package/resources/icons/table.svg +18 -0
  346. package/resources/icons/trash-2.svg +19 -0
  347. package/resources/icons/underline.svg +16 -0
  348. package/resources/icons/x.svg +16 -0
  349. package/dist/core/props.d.ts +0 -14
  350. package/dist/core/props.js +0 -30
  351. package/dist/core/props.js.map +0 -1
  352. package/dist/form/components/fields/submit-button.d.ts +0 -10
  353. package/dist/form/components/fields/submit-button.js +0 -14
  354. package/dist/form/components/fields/submit-button.js.map +0 -1
  355. package/dist/generated/types.d.ts +0 -17
  356. package/dist/icons/default-icons.d.ts +0 -3
  357. package/dist/icons/default-icons.js +0 -44
  358. package/dist/icons/default-icons.js.map +0 -1
  359. package/dist/icons/dynamic-lucide-renderer.d.ts +0 -2
  360. package/dist/icons/dynamic-lucide-renderer.js +0 -18
  361. package/dist/icons/dynamic-lucide-renderer.js.map +0 -1
  362. package/dist/menu/index.d.ts +0 -1
  363. package/dist/menu/index.js +0 -2
  364. package/dist/menu/use-menu.d.ts +0 -2
  365. package/dist/menu/use-menu.js +0 -9
  366. package/dist/menu/use-menu.js.map +0 -1
  367. /package/dist/{generated/types.js → table/column-registry.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"table-cell.js","names":[],"sources":["../../../resources/js/table/components/table-cell.tsx"],"sourcesContent":["import { copyToClipboard } from \"@lattice/lattice/clipboard\";\nimport { Check, Copy } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { formatCell, resolveLink } from \"../format\";\nimport type { TableColumn, TableRow } from \"../types\";\n\nexport function ColumnCell({ column, row }: { column: TableColumn; row: TableRow }) {\n if (column.type === \"stack\") {\n return (\n <div className=\"grid gap-1\">\n {(column.columns ?? []).map((stackedColumn) => (\n <span key={stackedColumn.key}>\n <TextCell column={stackedColumn} row={row} value={row[stackedColumn.key]} />\n </span>\n ))}\n </div>\n );\n }\n\n return <TextCell column={column} row={row} value={row[column.key]} />;\n}\n\nfunction TextCell({ column, row, value }: { column: TableColumn; row: TableRow; value: unknown }) {\n const text = formatCell(value, column);\n const [copied, setCopied] = useState(false);\n const href = resolveLink(column, row, value);\n const content = href ? (\n <a\n className=\"underline underline-offset-2\"\n href={href}\n rel={column.link?.external ? \"noreferrer\" : undefined}\n target={column.link?.external ? \"_blank\" : undefined}\n >\n {text}\n </a>\n ) : (\n text\n );\n\n useEffect(() => {\n if (!copied) {\n return;\n }\n\n const timeout = window.setTimeout(() => setCopied(false), 1500);\n\n return () => window.clearTimeout(timeout);\n }, [copied]);\n\n function handleCopy(): void {\n void copyToClipboard(text);\n setCopied(true);\n }\n\n if (!column.copyable) {\n return content;\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\">\n <span>{content}</span>\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 rounded border border-lt-border px-2 py-1 text-xs\"\n aria-label={`${copied ? \"Copied\" : \"Copy\"} ${column.label}`}\n onClick={handleCopy}\n >\n {copied ? (\n <Check aria-hidden=\"true\" className=\"size-3\" />\n ) : (\n <Copy aria-hidden=\"true\" className=\"size-3\" />\n )}\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </span>\n );\n}\n"],"mappings":";;;;;;AAMA,SAAgB,WAAW,EAAE,QAAQ,OAA+C;CAClF,IAAI,OAAO,SAAS,SAClB,OACE,oBAAC,OAAD;EAAK,WAAU;aACX,OAAO,WAAW,CAAC,GAAG,KAAK,kBAC3B,oBAAC,QAAD,EAAA,UACE,oBAAC,UAAD;GAAU,QAAQ;GAAoB;GAAK,OAAO,IAAI,cAAc;EAAO,CAAA,EACvE,GAFK,cAAc,GAEnB,CACP;CACE,CAAA;CAIT,OAAO,oBAAC,UAAD;EAAkB;EAAa;EAAK,OAAO,IAAI,OAAO;CAAO,CAAA;AACtE;AAEA,SAAS,SAAS,EAAE,QAAQ,KAAK,SAAiE;CAChG,MAAM,OAAO,WAAW,OAAO,MAAM;CACrC,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,OAAO,YAAY,QAAQ,KAAK,KAAK;CAC3C,MAAM,UAAU,OACd,oBAAC,KAAD;EACE,WAAU;EACJ;EACN,KAAK,OAAO,MAAM,WAAW,eAAe,KAAA;EAC5C,QAAQ,OAAO,MAAM,WAAW,WAAW,KAAA;YAE1C;CACA,CAAA,IAEH;CAGF,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,UAAU,OAAO,iBAAiB,UAAU,KAAK,GAAG,IAAI;EAE9D,aAAa,OAAO,aAAa,OAAO;CAC1C,GAAG,CAAC,MAAM,CAAC;CAEX,SAAS,aAAmB;EAC1B,gBAAqB,IAAI;EACzB,UAAU,IAAI;CAChB;CAEA,IAAI,CAAC,OAAO,UACV,OAAO;CAGT,OACE,qBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,oBAAC,QAAD,EAAA,UAAO,QAAc,CAAA,GACrB,qBAAC,UAAD;GACE,MAAK;GACL,WAAU;GACV,cAAY,GAAG,SAAS,WAAW,OAAO,GAAG,OAAO;GACpD,SAAS;aAJX,CAMG,SACC,oBAAC,OAAD;IAAO,eAAY;IAAO,WAAU;GAAU,CAAA,IAE9C,oBAAC,MAAD;IAAM,eAAY;IAAO,WAAU;GAAU,CAAA,GAE9C,SAAS,WAAW,MACf;IACJ;;AAEV"}
1
+ {"version":3,"file":"table-cell.js","names":[],"sources":["../../../resources/js/table/components/table-cell.tsx"],"sourcesContent":["import { useColumnRegistry } from \"../../provider\";\nimport type { TableColumn, TableRow } from \"../types\";\nimport { BadgeCell } from \"./cells/badge-cell\";\nimport { IconCell } from \"./cells/icon-cell\";\nimport { ImageCell } from \"./cells/image-cell\";\nimport { TextCell } from \"./cells/text-cell\";\n\nexport function ColumnCell({ column, row }: { column: TableColumn; row: TableRow }) {\n const columnRegistry = useColumnRegistry();\n const customRenderer = columnRegistry[column.type];\n\n if (customRenderer) {\n return customRenderer({ column, row, value: row[column.key] });\n }\n\n if (column.type === \"stack\") {\n return (\n <div className=\"grid gap-1\">\n {(column.columns ?? []).map((stackedColumn) => (\n <span key={stackedColumn.key}>\n <TextCell column={stackedColumn} row={row} value={row[stackedColumn.key]} />\n </span>\n ))}\n </div>\n );\n }\n\n if (column.type === \"badge\") {\n return <BadgeCell column={column} value={row[column.key]} />;\n }\n\n if (column.type === \"icon\") {\n return <IconCell column={column} value={row[column.key]} />;\n }\n\n if (column.type === \"image\") {\n return <ImageCell column={column} value={row[column.key]} />;\n }\n\n return <TextCell column={column} row={row} value={row[column.key]} />;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,WAAW,EAAE,QAAQ,OAA+C;CAElF,MAAM,iBADiB,kBACA,EAAe,OAAO;CAE7C,IAAI,gBACF,OAAO,eAAe;EAAE;EAAQ;EAAK,OAAO,IAAI,OAAO;CAAK,CAAC;CAG/D,IAAI,OAAO,SAAS,SAClB,OACE,oBAAC,OAAD;EAAK,WAAU;aACX,OAAO,WAAW,CAAC,GAAG,KAAK,kBAC3B,oBAAC,QAAD,EAAA,UACE,oBAAC,UAAD;GAAU,QAAQ;GAAoB;GAAK,OAAO,IAAI,cAAc;EAAO,CAAA,EACvE,GAFK,cAAc,GAEnB,CACP;CACE,CAAA;CAIT,IAAI,OAAO,SAAS,SAClB,OAAO,oBAAC,WAAD;EAAmB;EAAQ,OAAO,IAAI,OAAO;CAAO,CAAA;CAG7D,IAAI,OAAO,SAAS,QAClB,OAAO,oBAAC,UAAD;EAAkB;EAAQ,OAAO,IAAI,OAAO;CAAO,CAAA;CAG5D,IAAI,OAAO,SAAS,SAClB,OAAO,oBAAC,WAAD;EAAmB;EAAQ,OAAO,IAAI,OAAO;CAAO,CAAA;CAG7D,OAAO,oBAAC,UAAD;EAAkB;EAAa;EAAK,OAAO,IAAI,OAAO;CAAO,CAAA;AACtE"}
@@ -1,3 +1,7 @@
1
- import { RendererComponent } from '../../../../core/types';
2
- declare const TableComponent: RendererComponent<"table">;
1
+ import { ReactNode } from 'react';
2
+ import { TableNode } from '../types';
3
+ declare const TableComponent: ({ node }: {
4
+ children?: ReactNode;
5
+ node: TableNode;
6
+ }) => import("react").JSX.Element;
3
7
  export default TableComponent;
@@ -1,5 +1,6 @@
1
+ import { useT } from "../../i18n/instance.js";
1
2
  import { getBulkActions } from "../bulk.js";
2
- import { getRowActions, getRowKey } from "../payload.js";
3
+ import { flattenColumns, getRowActions, getRowKey } from "../payload.js";
3
4
  import { getColumnGridTemplate, getQueryParams, getVisiblePages } from "../query.js";
4
5
  import { useTableSelection } from "../use-table-selection.js";
5
6
  import { useTable } from "../use-table.js";
@@ -11,18 +12,21 @@ import { TablePagination } from "./pagination.js";
11
12
  import { SortBar } from "./sort-bar.js";
12
13
  import { TableActionNode } from "./table-action-node.js";
13
14
  import { ColumnCell } from "./table-cell.js";
15
+ import { useMemo } from "react";
14
16
  import { jsx, jsxs } from "react/jsx-runtime";
15
17
  //#region resources/js/table/components/table.tsx
16
18
  var TableComponent = ({ node }) => {
19
+ const { t } = useT("lattice");
17
20
  const { columns, rows, pagination, state, filters, addFilter, updateFilter, removeFilter, processing, hasLoaded, infiniteLoaderRef, sort, clearSort, goToPage, loadMore } = useTable(node);
18
- const bulkActions = getBulkActions(node.props?.bulkActions);
21
+ const bulkActions = useMemo(() => getBulkActions(node.props?.bulkActions), [node.props?.bulkActions]);
19
22
  const hasBulkActions = bulkActions.length > 0;
20
- const rowEntries = rows.map((row, index) => ({
23
+ const rowEntries = useMemo(() => rows.map((row, index) => ({
21
24
  row,
22
25
  actions: getRowActions(row),
23
26
  key: getRowKey(row, index)
24
- }));
27
+ })), [rows]);
25
28
  const selection = useTableSelection(rowEntries.map((entry) => entry.key));
29
+ const columnsByKey = useMemo(() => new Map(flattenColumns(columns).map((column) => [column.key, column])), [columns]);
26
30
  const currentPage = pagination.currentPage ?? state.page;
27
31
  const lastPage = pagination.lastPage ?? currentPage;
28
32
  const mode = pagination.mode ?? "table";
@@ -35,7 +39,11 @@ var TableComponent = ({ node }) => {
35
39
  clause,
36
40
  index
37
41
  }));
38
- const gridTemplateColumns = getColumnGridTemplate(columns, hasActions, hasBulkActions);
42
+ const gridTemplateColumns = useMemo(() => getColumnGridTemplate(columns, hasActions, hasBulkActions), [
43
+ columns,
44
+ hasActions,
45
+ hasBulkActions
46
+ ]);
39
47
  return /* @__PURE__ */ jsxs("div", {
40
48
  "data-lattice-component": node.id,
41
49
  className: "overflow-x-auto rounded-lt-sm border border-lt-border",
@@ -52,18 +60,18 @@ var TableComponent = ({ node }) => {
52
60
  }),
53
61
  filters.length > 0 && /* @__PURE__ */ jsx(FilterStackBar, {
54
62
  filters,
55
- columns,
63
+ columnsByKey,
56
64
  processing,
57
65
  onRemove: removeFilter
58
66
  }),
59
67
  state.sorts.length > 0 && /* @__PURE__ */ jsx(SortBar, {
60
- columns,
68
+ columnsByKey,
61
69
  state,
62
70
  processing,
63
71
  onClear: clearSort
64
72
  }),
65
73
  /* @__PURE__ */ jsxs("div", {
66
- className: "w-max min-w-full text-sm",
74
+ className: "min-w-full text-sm",
67
75
  role: "table",
68
76
  children: [/* @__PURE__ */ jsxs("div", {
69
77
  className: "border-b border-lt-border bg-lt-muted/50",
@@ -78,7 +86,8 @@ var TableComponent = ({ node }) => {
78
86
  role: "columnheader",
79
87
  children: /* @__PURE__ */ jsx("input", {
80
88
  type: "checkbox",
81
- "aria-label": "Select all rows",
89
+ "aria-label": t("a11y.selectAllRows", "Select all rows"),
90
+ "data-test": "select-all",
82
91
  checked: selection.allSelected,
83
92
  onChange: selection.toggleAll
84
93
  })
@@ -92,7 +101,10 @@ var TableComponent = ({ node }) => {
92
101
  hasActions && /* @__PURE__ */ jsx("div", {
93
102
  className: "px-4 py-3 text-right align-middle font-medium text-lt-muted-fg",
94
103
  role: "columnheader",
95
- children: "Actions"
104
+ children: /* @__PURE__ */ jsx("span", {
105
+ className: "sr-only",
106
+ children: node.props?.actionsLabel
107
+ })
96
108
  })
97
109
  ]
98
110
  }), hasFilters && /* @__PURE__ */ jsxs("div", {
@@ -105,7 +117,7 @@ var TableComponent = ({ node }) => {
105
117
  role: "cell"
106
118
  }),
107
119
  columns.map((column) => /* @__PURE__ */ jsx("div", {
108
- className: "px-4 py-2",
120
+ className: "min-w-0 px-2 py-2",
109
121
  role: "cell",
110
122
  children: column.filter?.enabled && /* @__PURE__ */ jsx(ColumnFilterControl, {
111
123
  column,
@@ -129,7 +141,14 @@ var TableComponent = ({ node }) => {
129
141
  role: "row",
130
142
  children: /* @__PURE__ */ jsx("div", {
131
143
  role: "cell",
132
- children: "Loading rows..."
144
+ children: t("table.loading", "Loading rows...")
145
+ })
146
+ }) : rowEntries.length === 0 ? /* @__PURE__ */ jsx("div", {
147
+ className: "p-8 text-center text-lt-muted-fg",
148
+ role: "row",
149
+ children: /* @__PURE__ */ jsx("div", {
150
+ role: "cell",
151
+ children: node.props?.emptyLabel
133
152
  })
134
153
  }) : rowEntries.map(({ row, actions, key }) => {
135
154
  return /* @__PURE__ */ jsxs("div", {
@@ -142,21 +161,25 @@ var TableComponent = ({ node }) => {
142
161
  role: "cell",
143
162
  children: /* @__PURE__ */ jsx("input", {
144
163
  type: "checkbox",
145
- "aria-label": `Select row ${key}`,
164
+ "aria-label": t("a11y.selectRow", "Select row {{key}}", { key }),
165
+ "data-test": `select-row-${key}`,
146
166
  checked: selection.isSelected(key),
147
167
  onChange: () => selection.toggle(key)
148
168
  })
149
169
  }),
150
170
  columns.map((column) => /* @__PURE__ */ jsxs("div", {
151
- className: "grid gap-1 p-4 align-middle",
171
+ className: "grid min-w-0 gap-1 p-4 align-middle",
152
172
  role: "cell",
153
173
  children: [/* @__PURE__ */ jsx("span", {
154
174
  "aria-hidden": "true",
155
175
  className: "text-xs font-medium text-lt-muted-fg md:hidden",
156
176
  children: column.label
157
- }), /* @__PURE__ */ jsx(ColumnCell, {
158
- column,
159
- row
177
+ }), /* @__PURE__ */ jsx("div", {
178
+ className: "min-w-0 truncate",
179
+ children: /* @__PURE__ */ jsx(ColumnCell, {
180
+ column,
181
+ row
182
+ })
160
183
  })]
161
184
  }, column.key)),
162
185
  actions.length > 0 && /* @__PURE__ */ jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","names":[],"sources":["../../../resources/js/table/components/table.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice/lattice/core/types\";\nimport { getBulkActions } from \"../bulk\";\nimport { getRowActions, getRowKey } from \"../payload\";\nimport { getColumnGridTemplate, getQueryParams, getVisiblePages } from \"../query\";\nimport { useTable } from \"../use-table\";\nimport { useTableSelection } from \"../use-table-selection\";\nimport { BulkBar } from \"./bulk-bar\";\nimport { ColumnFilterControl } from \"./column-filter-control\";\nimport { ColumnHeader } from \"./column-header\";\nimport { FilterStackBar } from \"./filter-stack-bar\";\nimport { TablePagination } from \"./pagination\";\nimport { SortBar } from \"./sort-bar\";\nimport { TableActionNode } from \"./table-action-node\";\nimport { ColumnCell } from \"./table-cell\";\n\nconst TableComponent: RendererComponent<\"table\"> = ({ node }) => {\n const {\n columns,\n rows,\n pagination,\n state,\n filters,\n addFilter,\n updateFilter,\n removeFilter,\n processing,\n hasLoaded,\n infiniteLoaderRef,\n sort,\n clearSort,\n goToPage,\n loadMore,\n } = useTable(node);\n\n const bulkActions = getBulkActions(node.props?.bulkActions);\n const hasBulkActions = bulkActions.length > 0;\n const rowEntries = rows.map((row, index) => ({\n row,\n actions: getRowActions(row),\n key: getRowKey(row, index),\n }));\n const selection = useTableSelection(rowEntries.map((entry) => entry.key));\n\n const currentPage = pagination.currentPage ?? state.page;\n const lastPage = pagination.lastPage ?? currentPage;\n const mode = pagination.mode ?? \"table\";\n const visiblePages = getVisiblePages(currentPage, lastPage);\n const hasNextPage = pagination.hasMore ?? currentPage < lastPage;\n const hasActions = rowEntries.some((entry) => entry.actions.length > 0);\n const striped = node.props?.striped === true;\n const hasFilters = columns.some((column) => column.filter?.enabled);\n const filterEntries = filters.map((clause, index) => ({ clause, index }));\n const gridTemplateColumns = getColumnGridTemplate(columns, hasActions, hasBulkActions);\n\n return (\n <div\n data-lattice-component={node.id}\n className=\"overflow-x-auto rounded-lt-sm border border-lt-border\"\n >\n {hasBulkActions && selection.active && (\n <BulkBar\n actions={bulkActions}\n selectedKeys={selection.selectedKeys}\n allMatching={selection.allMatching}\n total={pagination.total}\n query={getQueryParams(state)}\n canSelectAllMatching={\n selection.allVisibleSelected &&\n !selection.allMatching &&\n pagination.total !== undefined &&\n pagination.total > selection.selectedKeys.length\n }\n onSelectAllMatching={selection.selectAllMatching}\n onCompleted={selection.clear}\n />\n )}\n {filters.length > 0 && (\n <FilterStackBar\n filters={filters}\n columns={columns}\n processing={processing}\n onRemove={removeFilter}\n />\n )}\n {state.sorts.length > 0 && (\n <SortBar columns={columns} state={state} processing={processing} onClear={clearSort} />\n )}\n <div className=\"w-max min-w-full text-sm\" role=\"table\">\n <div className=\"border-b border-lt-border bg-lt-muted/50\" role=\"rowgroup\">\n <div\n className=\"hidden min-w-full md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center px-4 py-3\" role=\"columnheader\">\n <input\n type=\"checkbox\"\n aria-label=\"Select all rows\"\n checked={selection.allSelected}\n onChange={selection.toggleAll}\n />\n </div>\n )}\n {columns.map((column) => (\n <ColumnHeader\n column={column}\n key={column.key}\n processing={processing}\n sort={sort}\n state={state}\n />\n ))}\n {hasActions && (\n <div\n className=\"px-4 py-3 text-right align-middle font-medium text-lt-muted-fg\"\n role=\"columnheader\"\n >\n Actions\n </div>\n )}\n </div>\n {hasFilters && (\n <div\n className=\"hidden min-w-full border-t border-lt-border md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && <div className=\"px-4 py-2\" role=\"cell\" />}\n {columns.map((column) => (\n <div key={column.key} className=\"px-4 py-2\" role=\"cell\">\n {column.filter?.enabled && (\n <ColumnFilterControl\n column={column}\n clauses={filterEntries.filter((entry) => entry.clause.field === column.key)}\n processing={processing}\n onAdd={addFilter}\n onUpdate={updateFilter}\n onRemove={removeFilter}\n />\n )}\n </div>\n ))}\n {hasActions && <div className=\"px-4 py-2\" role=\"cell\" />}\n </div>\n )}\n </div>\n <div role=\"rowgroup\">\n {!hasLoaded ? (\n <div className=\"p-4 text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">Loading rows...</div>\n </div>\n ) : (\n rowEntries.map(({ row, actions, key }) => {\n return (\n <div\n key={key}\n className={`grid grid-cols-1 border-b border-lt-border last:border-b-0 md:grid-cols-[var(--lattice-table-columns)] ${\n striped ? \"odd:bg-lt-muted/30\" : \"\"\n }`}\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center p-4\" role=\"cell\">\n <input\n type=\"checkbox\"\n aria-label={`Select row ${key}`}\n checked={selection.isSelected(key)}\n onChange={() => selection.toggle(key)}\n />\n </div>\n )}\n {columns.map((column) => (\n <div key={column.key} className=\"grid gap-1 p-4 align-middle\" role=\"cell\">\n <span\n aria-hidden=\"true\"\n className=\"text-xs font-medium text-lt-muted-fg md:hidden\"\n >\n {column.label}\n </span>\n <ColumnCell column={column} row={row} />\n </div>\n ))}\n {actions.length > 0 && (\n <div\n className=\"flex items-center justify-start gap-2 p-4 md:justify-end\"\n role=\"cell\"\n >\n {actions.map((action, actionIndex) => (\n <TableActionNode\n key={action.key ?? action.id ?? actionIndex}\n node={action}\n />\n ))}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n </div>\n {hasLoaded && (\n <TablePagination\n pagination={pagination}\n currentPage={currentPage}\n processing={processing}\n mode={mode}\n hasNextPage={hasNextPage}\n visiblePages={visiblePages}\n infiniteLoaderRef={infiniteLoaderRef}\n onPage={goToPage}\n onLoadMore={loadMore}\n />\n )}\n </div>\n );\n};\n\nexport default TableComponent;\n"],"mappings":"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"}
1
+ {"version":3,"file":"table.js","names":[],"sources":["../../../resources/js/table/components/table.tsx"],"sourcesContent":["import { type ReactNode, useMemo } from \"react\";\nimport { useT } from \"@lattice/lattice/i18n\";\nimport type { TableNode } from \"../types\";\nimport { getBulkActions } from \"../bulk\";\nimport { flattenColumns, getRowActions, getRowKey } from \"../payload\";\nimport { getColumnGridTemplate, getQueryParams, getVisiblePages } from \"../query\";\nimport { useTable } from \"../use-table\";\nimport { useTableSelection } from \"../use-table-selection\";\nimport { BulkBar } from \"./bulk-bar\";\nimport { ColumnFilterControl } from \"./column-filter-control\";\nimport { ColumnHeader } from \"./column-header\";\nimport { FilterStackBar } from \"./filter-stack-bar\";\nimport { TablePagination } from \"./pagination\";\nimport { SortBar } from \"./sort-bar\";\nimport { TableActionNode } from \"./table-action-node\";\nimport { ColumnCell } from \"./table-cell\";\n\nconst TableComponent = ({ node }: { children?: ReactNode; node: TableNode }) => {\n const { t } = useT(\"lattice\");\n const {\n columns,\n rows,\n pagination,\n state,\n filters,\n addFilter,\n updateFilter,\n removeFilter,\n processing,\n hasLoaded,\n infiniteLoaderRef,\n sort,\n clearSort,\n goToPage,\n loadMore,\n } = useTable(node);\n\n const bulkActions = useMemo(\n () => getBulkActions(node.props?.bulkActions),\n [node.props?.bulkActions],\n );\n const hasBulkActions = bulkActions.length > 0;\n const rowEntries = useMemo(\n () =>\n rows.map((row, index) => ({ row, actions: getRowActions(row), key: getRowKey(row, index) })),\n [rows],\n );\n const selection = useTableSelection(rowEntries.map((entry) => entry.key));\n\n const columnsByKey = useMemo(\n () => new Map(flattenColumns(columns).map((column) => [column.key, column])),\n [columns],\n );\n const currentPage = pagination.currentPage ?? state.page;\n const lastPage = pagination.lastPage ?? currentPage;\n const mode = pagination.mode ?? \"table\";\n const visiblePages = getVisiblePages(currentPage, lastPage);\n const hasNextPage = pagination.hasMore ?? currentPage < lastPage;\n const hasActions = rowEntries.some((entry) => entry.actions.length > 0);\n const striped = node.props?.striped === true;\n const hasFilters = columns.some((column) => column.filter?.enabled);\n const filterEntries = filters.map((clause, index) => ({ clause, index }));\n const gridTemplateColumns = useMemo(\n () => getColumnGridTemplate(columns, hasActions, hasBulkActions),\n [columns, hasActions, hasBulkActions],\n );\n\n return (\n <div\n data-lattice-component={node.id}\n className=\"overflow-x-auto rounded-lt-sm border border-lt-border\"\n >\n {hasBulkActions && selection.active && (\n <BulkBar\n actions={bulkActions}\n selectedKeys={selection.selectedKeys}\n allMatching={selection.allMatching}\n total={pagination.total}\n query={getQueryParams(state)}\n canSelectAllMatching={\n selection.allVisibleSelected &&\n !selection.allMatching &&\n pagination.total !== undefined &&\n pagination.total > selection.selectedKeys.length\n }\n onSelectAllMatching={selection.selectAllMatching}\n onCompleted={selection.clear}\n />\n )}\n {filters.length > 0 && (\n <FilterStackBar\n filters={filters}\n columnsByKey={columnsByKey}\n processing={processing}\n onRemove={removeFilter}\n />\n )}\n {state.sorts.length > 0 && (\n <SortBar\n columnsByKey={columnsByKey}\n state={state}\n processing={processing}\n onClear={clearSort}\n />\n )}\n <div className=\"min-w-full text-sm\" role=\"table\">\n <div className=\"border-b border-lt-border bg-lt-muted/50\" role=\"rowgroup\">\n <div\n className=\"hidden min-w-full md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center px-4 py-3\" role=\"columnheader\">\n <input\n type=\"checkbox\"\n aria-label={t(\"a11y.selectAllRows\", \"Select all rows\")}\n data-test=\"select-all\"\n checked={selection.allSelected}\n onChange={selection.toggleAll}\n />\n </div>\n )}\n {columns.map((column) => (\n <ColumnHeader\n column={column}\n key={column.key}\n processing={processing}\n sort={sort}\n state={state}\n />\n ))}\n {hasActions && (\n <div\n className=\"px-4 py-3 text-right align-middle font-medium text-lt-muted-fg\"\n role=\"columnheader\"\n >\n <span className=\"sr-only\">{node.props?.actionsLabel}</span>\n </div>\n )}\n </div>\n {hasFilters && (\n <div\n className=\"hidden min-w-full border-t border-lt-border md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && <div className=\"px-4 py-2\" role=\"cell\" />}\n {columns.map((column) => (\n <div key={column.key} className=\"min-w-0 px-2 py-2\" role=\"cell\">\n {column.filter?.enabled && (\n <ColumnFilterControl\n column={column}\n clauses={filterEntries.filter((entry) => entry.clause.field === column.key)}\n processing={processing}\n onAdd={addFilter}\n onUpdate={updateFilter}\n onRemove={removeFilter}\n />\n )}\n </div>\n ))}\n {hasActions && <div className=\"px-4 py-2\" role=\"cell\" />}\n </div>\n )}\n </div>\n <div role=\"rowgroup\">\n {!hasLoaded ? (\n <div className=\"p-4 text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">{t(\"table.loading\", \"Loading rows...\")}</div>\n </div>\n ) : rowEntries.length === 0 ? (\n <div className=\"p-8 text-center text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">{node.props?.emptyLabel}</div>\n </div>\n ) : (\n rowEntries.map(({ row, actions, key }) => {\n return (\n <div\n key={key}\n className={`grid grid-cols-1 border-b border-lt-border last:border-b-0 md:grid-cols-[var(--lattice-table-columns)] ${\n striped ? \"odd:bg-lt-muted/30\" : \"\"\n }`}\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center p-4\" role=\"cell\">\n <input\n type=\"checkbox\"\n aria-label={t(\"a11y.selectRow\", \"Select row {{key}}\", { key })}\n data-test={`select-row-${key}`}\n checked={selection.isSelected(key)}\n onChange={() => selection.toggle(key)}\n />\n </div>\n )}\n {columns.map((column) => (\n <div\n key={column.key}\n className=\"grid min-w-0 gap-1 p-4 align-middle\"\n role=\"cell\"\n >\n <span\n aria-hidden=\"true\"\n className=\"text-xs font-medium text-lt-muted-fg md:hidden\"\n >\n {column.label}\n </span>\n <div className=\"min-w-0 truncate\">\n <ColumnCell column={column} row={row} />\n </div>\n </div>\n ))}\n {actions.length > 0 && (\n <div\n className=\"flex items-center justify-start gap-2 p-4 md:justify-end\"\n role=\"cell\"\n >\n {actions.map((action, actionIndex) => (\n <TableActionNode\n key={action.key ?? action.id ?? actionIndex}\n node={action}\n />\n ))}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n </div>\n {hasLoaded && (\n <TablePagination\n pagination={pagination}\n currentPage={currentPage}\n processing={processing}\n mode={mode}\n hasNextPage={hasNextPage}\n visiblePages={visiblePages}\n infiniteLoaderRef={infiniteLoaderRef}\n onPage={goToPage}\n onLoadMore={loadMore}\n />\n )}\n </div>\n );\n};\n\nexport default TableComponent;\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  //#region resources/js/table/format.ts
2
2
  function formatCell(value, column) {
3
3
  if (value === null || value === void 0) return "";
4
- if (column?.date) return formatDate(value, column.date.format ?? null);
4
+ const date = (column?.props)?.date;
5
+ if (date) return formatDate(value, date.format ?? null);
5
6
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
6
7
  return JSON.stringify(value);
7
8
  }
@@ -27,8 +28,9 @@ function formatDate(value, format) {
27
28
  return format.replace(/[YymndjHGis]/g, (token) => replacements[token] ?? token);
28
29
  }
29
30
  function resolveLink(column, row, value) {
30
- if (!column.link) return null;
31
- const href = column.link.href ?? String(value ?? "");
31
+ const link = column.props?.link;
32
+ if (!link) return null;
33
+ const href = link.href ?? String(value ?? "");
32
34
  if (href === "") return null;
33
35
  return href.replace(/\{([^}]+)\}/g, (_, key) => {
34
36
  if (key === "value") return encodeURIComponent(String(value ?? ""));
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","names":[],"sources":["../../resources/js/table/format.ts"],"sourcesContent":["import type { TableColumn, TableRow } from \"./types\";\n\nexport function formatCell(value: unknown, column?: TableColumn): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n if (column?.date) {\n return formatDate(value, column.date.format ?? null);\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n return JSON.stringify(value);\n}\n\nfunction formatDate(value: unknown, format: string | null): string {\n const date = new Date(String(value));\n\n if (Number.isNaN(date.getTime())) {\n return formatCell(value);\n }\n\n if (!format) {\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n }).format(date);\n }\n\n const replacements: Record<string, string> = {\n Y: String(date.getFullYear()),\n y: String(date.getFullYear()).slice(-2),\n m: String(date.getMonth() + 1).padStart(2, \"0\"),\n n: String(date.getMonth() + 1),\n d: String(date.getDate()).padStart(2, \"0\"),\n j: String(date.getDate()),\n H: String(date.getHours()).padStart(2, \"0\"),\n G: String(date.getHours()),\n i: String(date.getMinutes()).padStart(2, \"0\"),\n s: String(date.getSeconds()).padStart(2, \"0\"),\n };\n\n return format.replace(/[YymndjHGis]/g, (token) => replacements[token] ?? token);\n}\n\nexport function resolveLink(column: TableColumn, row: TableRow, value: unknown): string | null {\n if (!column.link) {\n return null;\n }\n\n const href = column.link.href ?? String(value ?? \"\");\n\n if (href === \"\") {\n return null;\n }\n\n return href.replace(/\\{([^}]+)\\}/g, (_, key: string) => {\n if (key === \"value\") {\n return encodeURIComponent(String(value ?? \"\"));\n }\n\n return encodeURIComponent(String(row[key] ?? \"\"));\n });\n}\n"],"mappings":";AAEA,SAAgB,WAAW,OAAgB,QAA8B;CACvE,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,IAAI,QAAQ,MACV,OAAO,WAAW,OAAO,OAAO,KAAK,UAAU,IAAI;CAGrD,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAC7E,OAAO,OAAO,KAAK;CAGrB,OAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,WAAW,OAAgB,QAA+B;CACjE,MAAM,OAAO,IAAI,KAAK,OAAO,KAAK,CAAC;CAEnC,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC7B,OAAO,WAAW,KAAK;CAGzB,IAAI,CAAC,QACH,OAAO,IAAI,KAAK,eAAe,KAAA,GAAW;EACxC,WAAW;EACX,WAAW;CACb,CAAC,EAAE,OAAO,IAAI;CAGhB,MAAM,eAAuC;EAC3C,GAAG,OAAO,KAAK,YAAY,CAAC;EAC5B,GAAG,OAAO,KAAK,YAAY,CAAC,EAAE,MAAM,EAAE;EACtC,GAAG,OAAO,KAAK,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;EAC9C,GAAG,OAAO,KAAK,SAAS,IAAI,CAAC;EAC7B,GAAG,OAAO,KAAK,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;EACzC,GAAG,OAAO,KAAK,QAAQ,CAAC;EACxB,GAAG,OAAO,KAAK,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;EAC1C,GAAG,OAAO,KAAK,SAAS,CAAC;EACzB,GAAG,OAAO,KAAK,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;EAC5C,GAAG,OAAO,KAAK,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;CAC9C;CAEA,OAAO,OAAO,QAAQ,kBAAkB,UAAU,aAAa,UAAU,KAAK;AAChF;AAEA,SAAgB,YAAY,QAAqB,KAAe,OAA+B;CAC7F,IAAI,CAAC,OAAO,MACV,OAAO;CAGT,MAAM,OAAO,OAAO,KAAK,QAAQ,OAAO,SAAS,EAAE;CAEnD,IAAI,SAAS,IACX,OAAO;CAGT,OAAO,KAAK,QAAQ,iBAAiB,GAAG,QAAgB;EACtD,IAAI,QAAQ,SACV,OAAO,mBAAmB,OAAO,SAAS,EAAE,CAAC;EAG/C,OAAO,mBAAmB,OAAO,IAAI,QAAQ,EAAE,CAAC;CAClD,CAAC;AACH"}
1
+ {"version":3,"file":"format.js","names":[],"sources":["../../resources/js/table/format.ts"],"sourcesContent":["import type { TextColumnProps } from \"@lattice/lattice/types/generated\";\nimport type { TableColumn, TableRow } from \"./types\";\n\nexport function formatCell(value: unknown, column?: TableColumn): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n const date = (column?.props as TextColumnProps | null)?.date;\n\n if (date) {\n return formatDate(value, date.format ?? null);\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n return JSON.stringify(value);\n}\n\nfunction formatDate(value: unknown, format: string | null): string {\n const date = new Date(String(value));\n\n if (Number.isNaN(date.getTime())) {\n return formatCell(value);\n }\n\n if (!format) {\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n }).format(date);\n }\n\n const replacements: Record<string, string> = {\n Y: String(date.getFullYear()),\n y: String(date.getFullYear()).slice(-2),\n m: String(date.getMonth() + 1).padStart(2, \"0\"),\n n: String(date.getMonth() + 1),\n d: String(date.getDate()).padStart(2, \"0\"),\n j: String(date.getDate()),\n H: String(date.getHours()).padStart(2, \"0\"),\n G: String(date.getHours()),\n i: String(date.getMinutes()).padStart(2, \"0\"),\n s: String(date.getSeconds()).padStart(2, \"0\"),\n };\n\n return format.replace(/[YymndjHGis]/g, (token) => replacements[token] ?? token);\n}\n\nexport function resolveLink(column: TableColumn, row: TableRow, value: unknown): string | null {\n const link = (column.props as TextColumnProps | null)?.link;\n\n if (!link) {\n return null;\n }\n\n const href = link.href ?? String(value ?? \"\");\n\n if (href === \"\") {\n return null;\n }\n\n return href.replace(/\\{([^}]+)\\}/g, (_, key: string) => {\n if (key === \"value\") {\n return encodeURIComponent(String(value ?? \"\"));\n }\n\n return encodeURIComponent(String(row[key] ?? \"\"));\n });\n}\n"],"mappings":";AAGA,SAAgB,WAAW,OAAgB,QAA8B;CACvE,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,MAAM,QAAQ,QAAQ,QAAkC;CAExD,IAAI,MACF,OAAO,WAAW,OAAO,KAAK,UAAU,IAAI;CAG9C,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAC7E,OAAO,OAAO,KAAK;CAGrB,OAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,WAAW,OAAgB,QAA+B;CACjE,MAAM,OAAO,IAAI,KAAK,OAAO,KAAK,CAAC;CAEnC,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC7B,OAAO,WAAW,KAAK;CAGzB,IAAI,CAAC,QACH,OAAO,IAAI,KAAK,eAAe,KAAA,GAAW;EACxC,WAAW;EACX,WAAW;CACb,CAAC,EAAE,OAAO,IAAI;CAGhB,MAAM,eAAuC;EAC3C,GAAG,OAAO,KAAK,YAAY,CAAC;EAC5B,GAAG,OAAO,KAAK,YAAY,CAAC,EAAE,MAAM,EAAE;EACtC,GAAG,OAAO,KAAK,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;EAC9C,GAAG,OAAO,KAAK,SAAS,IAAI,CAAC;EAC7B,GAAG,OAAO,KAAK,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;EACzC,GAAG,OAAO,KAAK,QAAQ,CAAC;EACxB,GAAG,OAAO,KAAK,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;EAC1C,GAAG,OAAO,KAAK,SAAS,CAAC;EACzB,GAAG,OAAO,KAAK,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;EAC5C,GAAG,OAAO,KAAK,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;CAC9C;CAEA,OAAO,OAAO,QAAQ,kBAAkB,UAAU,aAAa,UAAU,KAAK;AAChF;AAEA,SAAgB,YAAY,QAAqB,KAAe,OAA+B;CAC7F,MAAM,OAAQ,OAAO,OAAkC;CAEvD,IAAI,CAAC,MACH,OAAO;CAGT,MAAM,OAAO,KAAK,QAAQ,OAAO,SAAS,EAAE;CAE5C,IAAI,SAAS,IACX,OAAO;CAGT,OAAO,KAAK,QAAQ,iBAAiB,GAAG,QAAgB;EACtD,IAAI,QAAQ,SACV,OAAO,mBAAmB,OAAO,SAAS,EAAE,CAAC;EAG/C,OAAO,mBAAmB,OAAO,IAAI,QAAQ,EAAE,CAAC;CAClD,CAAC;AACH"}
@@ -1 +1 @@
1
- export declare const tableComponents: import('../../../core/registry').Plugin;
1
+ export declare const tableComponents: import('../core/registry').Plugin;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/table/index.ts"],"sourcesContent":["import { createPlugin, lazyComponent } from \"@lattice/lattice/core/registry\";\n\nexport const tableComponents = createPlugin({\n components: {\n table: lazyComponent(() => import(\"./components/table\")),\n },\n name: \"lattice/table\",\n});\n"],"mappings":";;AAEA,IAAa,kBAAkB,aAAa;CAC1C,YAAY,EACV,OAAO,oBAAoB,OAAO,wBAAqB,EACzD;CACA,MAAM;AACR,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../resources/js/table/index.ts"],"sourcesContent":["import { createPlugin, lazyComponent } from \"@lattice/lattice/core/registry\";\nimport type { RendererComponentModule } from \"@lattice/lattice/core/types\";\n\nexport const tableComponents = createPlugin({\n components: {\n // The table renders an enriched TableNode (rows/pagination/state the server\n // hydrates onto it); the registry erases per-component node types here.\n table: lazyComponent(\n () => import(\"./components/table\") as unknown as Promise<RendererComponentModule<\"table\">>,\n ),\n },\n name: \"lattice/table\",\n});\n"],"mappings":";;AAGA,IAAa,kBAAkB,aAAa;CAC1C,YAAY,EAGV,OAAO,oBACC,OAAO,wBACf,EACF;CACA,MAAM;AACR,CAAC"}
@@ -1,4 +1,4 @@
1
- import { Node } from '../../../core/types';
1
+ import { Node } from '../core/types';
2
2
  import { TableColumn, TablePagination, TableRow, TableState } from './types';
3
3
  export declare function getColumns(value: unknown): TableColumn[];
4
4
  export declare function getRows(value: unknown): TableRow[];
@@ -1,6 +1,5 @@
1
1
  import { TableColumn, TableSort, TableState } from './types';
2
2
  export declare function getColumnSort(state: TableState, column: TableColumn): TableSort | undefined;
3
- export declare function getSortColumn(columns: TableColumn[], sort: TableSort): TableColumn | undefined;
4
3
  export declare function getColumnAriaSort(sort: TableSort | undefined): "ascending" | "descending" | undefined;
5
4
  export declare function buildEndpoint(endpoint: string, state: TableState): string;
6
5
  export declare function getQueryParams(state: TableState): Record<string, unknown>;
@@ -1,11 +1,8 @@
1
- import { flattenColumns } from "./payload.js";
1
+ import { translate } from "../i18n/instance.js";
2
2
  //#region resources/js/table/query.ts
3
3
  function getColumnSort(state, column) {
4
4
  return state.sorts.find((currentSort) => currentSort.key === column.key);
5
5
  }
6
- function getSortColumn(columns, sort) {
7
- return flattenColumns(columns).find((column) => column.key === sort.key);
8
- }
9
6
  function getColumnAriaSort(sort) {
10
7
  if (sort?.direction === "asc") return "ascending";
11
8
  if (sort?.direction === "desc") return "descending";
@@ -40,6 +37,8 @@ var operatorLabels = {
40
37
  gte: "≥",
41
38
  lt: "<",
42
39
  lte: "≤",
40
+ in: "in",
41
+ not_in: "not in",
43
42
  before: "before",
44
43
  after: "after",
45
44
  empty: "is empty",
@@ -47,7 +46,7 @@ var operatorLabels = {
47
46
  };
48
47
  var VALUELESS_FILTER_OPERATORS = new Set(["empty", "filled"]);
49
48
  function operatorLabel(operator) {
50
- return operatorLabels[operator] ?? operator;
49
+ return translate("lattice", `operators.${operator}`, operatorLabels[operator] ?? operator);
51
50
  }
52
51
  function getSortDirectionLabel(direction) {
53
52
  return direction === "desc" ? "descending" : "ascending";
@@ -72,12 +71,12 @@ function getVisiblePages(currentPage, lastPage) {
72
71
  return Array.from({ length: 5 }, (_, index) => start + index);
73
72
  }
74
73
  function getColumnGridTemplate(columns, hasActions, hasSelection) {
75
- const tracks = columns.map((column) => column.type === "stack" ? "minmax(16rem, 2fr)" : "minmax(9rem, 1fr)");
76
- if (hasActions) tracks.push("max-content");
77
- if (hasSelection) tracks.unshift("max-content");
74
+ const tracks = columns.map((column) => column.type === "stack" ? "minmax(13rem, 2fr)" : "minmax(7rem, 1fr)");
75
+ if (hasActions) tracks.push("10rem");
76
+ if (hasSelection) tracks.unshift("3rem");
78
77
  return tracks.join(" ");
79
78
  }
80
79
  //#endregion
81
- export { VALUELESS_FILTER_OPERATORS, buildEndpoint, getColumnAriaSort, getColumnGridTemplate, getColumnSort, getQueryParams, getSortColumn, getSortDirectionLabel, getVisiblePages, nextSort, operatorLabel };
80
+ export { VALUELESS_FILTER_OPERATORS, buildEndpoint, getColumnAriaSort, getColumnGridTemplate, getColumnSort, getQueryParams, getSortDirectionLabel, getVisiblePages, nextSort, operatorLabel };
82
81
 
83
82
  //# sourceMappingURL=query.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","names":[],"sources":["../../resources/js/table/query.ts"],"sourcesContent":["import { flattenColumns } from \"./payload\";\nimport type { TableColumn, TableSort, TableState } from \"./types\";\n\nexport function getColumnSort(state: TableState, column: TableColumn): TableSort | undefined {\n return state.sorts.find((currentSort) => currentSort.key === column.key);\n}\n\nexport function getSortColumn(columns: TableColumn[], sort: TableSort): TableColumn | undefined {\n return flattenColumns(columns).find((column) => column.key === sort.key);\n}\n\nexport function getColumnAriaSort(\n sort: TableSort | undefined,\n): \"ascending\" | \"descending\" | undefined {\n if (sort?.direction === \"asc\") {\n return \"ascending\";\n }\n\n if (sort?.direction === \"desc\") {\n return \"descending\";\n }\n\n return undefined;\n}\n\nexport function buildEndpoint(endpoint: string, state: TableState): string {\n const url = new URL(endpoint, window.location.origin);\n\n if (state.filters.length > 0) {\n url.searchParams.set(\"filter\", serializeFilters(state));\n }\n\n if (state.sorts.length > 0) {\n url.searchParams.set(\"sort\", serializeSorts(state));\n }\n\n url.searchParams.set(\"page\", String(state.page));\n url.searchParams.set(\"per_page\", String(state.perPage));\n\n return `${url.pathname}${url.search}`;\n}\n\nexport function getQueryParams(state: TableState): Record<string, unknown> {\n const params: Record<string, unknown> = {};\n\n if (state.filters.length > 0) {\n params.filter = serializeFilters(state);\n }\n\n if (state.sorts.length > 0) {\n params.sort = serializeSorts(state);\n }\n\n return params;\n}\n\nfunction serializeFilters(state: TableState): string {\n return state.filters\n .map((clause) => `${clause.field}:${clause.operator}:${encodeURIComponent(clause.value)}`)\n .join(\",\");\n}\n\nfunction serializeSorts(state: TableState): string {\n return state.sorts\n .map((sort) => (sort.direction === \"desc\" ? `-${sort.key}` : sort.key))\n .join(\",\");\n}\n\nconst operatorLabels: Record<string, string> = {\n contains: \"contains\",\n starts_with: \"starts with\",\n ends_with: \"ends with\",\n eq: \"equals\",\n neq: \"not equals\",\n gt: \">\",\n gte: \"≥\",\n lt: \"<\",\n lte: \"≤\",\n before: \"before\",\n after: \"after\",\n empty: \"is empty\",\n filled: \"is not empty\",\n};\n\n// Operators that filter on presence alone and carry no value input.\nexport const VALUELESS_FILTER_OPERATORS = new Set<string>([\"empty\", \"filled\"]);\n\nexport function operatorLabel(operator: string): string {\n return operatorLabels[operator] ?? operator;\n}\n\nexport function getSortDirectionLabel(direction: string): string {\n return direction === \"desc\" ? \"descending\" : \"ascending\";\n}\n\nexport function nextSort(sorts: TableSort[], column: TableColumn): TableSort[] {\n if (!column.sortable) {\n return sorts;\n }\n\n const currentSort = sorts.find((sort) => sort.key === column.key);\n const remainingSorts = sorts.filter((sort) => sort.key !== column.key);\n\n if (!currentSort) {\n return [...sorts, { key: column.key, direction: \"asc\" }];\n }\n\n if (currentSort.direction === \"asc\") {\n return [...remainingSorts, { key: column.key, direction: \"desc\" }];\n }\n\n return remainingSorts;\n}\n\nexport function getVisiblePages(currentPage: number, lastPage: number): number[] {\n if (lastPage <= 5) {\n return Array.from({ length: lastPage }, (_, index) => index + 1);\n }\n\n const start = Math.max(1, Math.min(currentPage - 2, lastPage - 4));\n\n return Array.from({ length: 5 }, (_, index) => start + index);\n}\n\nexport function getColumnGridTemplate(\n columns: TableColumn[],\n hasActions: boolean,\n hasSelection: boolean,\n): string {\n const tracks: string[] = columns.map((column) =>\n column.type === \"stack\" ? \"minmax(16rem, 2fr)\" : \"minmax(9rem, 1fr)\",\n );\n\n if (hasActions) {\n tracks.push(\"max-content\");\n }\n\n if (hasSelection) {\n tracks.unshift(\"max-content\");\n }\n\n return tracks.join(\" \");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"query.js","names":[],"sources":["../../resources/js/table/query.ts"],"sourcesContent":["import { translate } from \"@lattice/lattice/i18n\";\nimport type { TableColumn, TableSort, TableState } from \"./types\";\n\nexport function getColumnSort(state: TableState, column: TableColumn): TableSort | undefined {\n return state.sorts.find((currentSort) => currentSort.key === column.key);\n}\n\nexport function getColumnAriaSort(\n sort: TableSort | undefined,\n): \"ascending\" | \"descending\" | undefined {\n if (sort?.direction === \"asc\") {\n return \"ascending\";\n }\n\n if (sort?.direction === \"desc\") {\n return \"descending\";\n }\n\n return undefined;\n}\n\nexport function buildEndpoint(endpoint: string, state: TableState): string {\n const url = new URL(endpoint, window.location.origin);\n\n if (state.filters.length > 0) {\n url.searchParams.set(\"filter\", serializeFilters(state));\n }\n\n if (state.sorts.length > 0) {\n url.searchParams.set(\"sort\", serializeSorts(state));\n }\n\n url.searchParams.set(\"page\", String(state.page));\n url.searchParams.set(\"per_page\", String(state.perPage));\n\n return `${url.pathname}${url.search}`;\n}\n\nexport function getQueryParams(state: TableState): Record<string, unknown> {\n const params: Record<string, unknown> = {};\n\n if (state.filters.length > 0) {\n params.filter = serializeFilters(state);\n }\n\n if (state.sorts.length > 0) {\n params.sort = serializeSorts(state);\n }\n\n return params;\n}\n\nfunction serializeFilters(state: TableState): string {\n return state.filters\n .map((clause) => `${clause.field}:${clause.operator}:${encodeURIComponent(clause.value)}`)\n .join(\",\");\n}\n\nfunction serializeSorts(state: TableState): string {\n return state.sorts\n .map((sort) => (sort.direction === \"desc\" ? `-${sort.key}` : sort.key))\n .join(\",\");\n}\n\nconst operatorLabels: Record<string, string> = {\n contains: \"contains\",\n starts_with: \"starts with\",\n ends_with: \"ends with\",\n eq: \"equals\",\n neq: \"not equals\",\n gt: \">\",\n gte: \"≥\",\n lt: \"<\",\n lte: \"≤\",\n in: \"in\",\n not_in: \"not in\",\n before: \"before\",\n after: \"after\",\n empty: \"is empty\",\n filled: \"is not empty\",\n};\n\nexport const VALUELESS_FILTER_OPERATORS = new Set<string>([\"empty\", \"filled\"]);\n\nexport function operatorLabel(operator: string): string {\n return translate(\"lattice\", `operators.${operator}`, operatorLabels[operator] ?? operator);\n}\n\nexport function getSortDirectionLabel(direction: string): string {\n return direction === \"desc\" ? \"descending\" : \"ascending\";\n}\n\nexport function nextSort(sorts: TableSort[], column: TableColumn): TableSort[] {\n if (!column.sortable) {\n return sorts;\n }\n\n const currentSort = sorts.find((sort) => sort.key === column.key);\n const remainingSorts = sorts.filter((sort) => sort.key !== column.key);\n\n if (!currentSort) {\n return [...sorts, { key: column.key, direction: \"asc\" }];\n }\n\n if (currentSort.direction === \"asc\") {\n return [...remainingSorts, { key: column.key, direction: \"desc\" }];\n }\n\n return remainingSorts;\n}\n\nexport function getVisiblePages(currentPage: number, lastPage: number): number[] {\n if (lastPage <= 5) {\n return Array.from({ length: lastPage }, (_, index) => index + 1);\n }\n\n const start = Math.max(1, Math.min(currentPage - 2, lastPage - 4));\n\n return Array.from({ length: 5 }, (_, index) => start + index);\n}\n\nexport function getColumnGridTemplate(\n columns: TableColumn[],\n hasActions: boolean,\n hasSelection: boolean,\n): string {\n const tracks: string[] = columns.map((column) =>\n column.type === \"stack\" ? \"minmax(13rem, 2fr)\" : \"minmax(7rem, 1fr)\",\n );\n\n // Selection and action tracks use fixed widths, not max-content: the header,\n // filter, and body rows are independent grids, so a content-sized track would\n // resolve to a different width in each one, changing the free space left for\n // the 1fr columns and drifting them out of alignment across rows.\n if (hasActions) {\n tracks.push(\"10rem\");\n }\n\n if (hasSelection) {\n tracks.unshift(\"3rem\");\n }\n\n return tracks.join(\" \");\n}\n"],"mappings":"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"}
@@ -1,31 +1,14 @@
1
- import { ControlType, FilterOperator, PaginationType, TableSort } from '../../../generated/types';
2
- export type { TableSort };
3
- export type TableColumn = {
4
- columns?: TableColumn[];
5
- key: string;
6
- label: string;
7
- type?: "stack" | "text";
8
- sortable?: boolean;
9
- filter?: {
10
- enabled?: boolean;
11
- type?: ControlType;
12
- operators?: FilterOperator[];
13
- defaultOperator?: FilterOperator;
14
- };
15
- date?: {
16
- format?: string | null;
17
- };
18
- copyable?: boolean;
19
- link?: {
20
- href?: string | null;
21
- external?: boolean;
22
- };
23
- };
1
+ import { ActionNode, ColumnData, ColumnFilter, ColumnPropsMap, ColumnType, FilterClause as WireFilterClause, Op, PaginationType, Table, TableSort } from '../types/generated';
2
+ export type { ColumnData, ColumnFilter, ColumnType, TableSort };
3
+ export type TableColumn = ColumnData;
24
4
  export type TableRow = Record<string, unknown>;
25
- export type FilterClause = {
26
- field: string;
27
- operator: FilterOperator;
28
- value: string;
5
+ /**
6
+ * The wire types `operator` as a free string (validated server-side); on the
7
+ * client a clause always carries a known Op, built from a column's
8
+ * allowed operators.
9
+ */
10
+ export type FilterClause = Omit<WireFilterClause, "operator"> & {
11
+ operator: Op;
29
12
  };
30
13
  export type TableState = {
31
14
  filters: FilterClause[];
@@ -49,19 +32,32 @@ export type TableResponse = {
49
32
  pagination?: TablePagination;
50
33
  state?: Partial<TableState>;
51
34
  };
52
- declare module '../../../core/types' {
53
- interface ComponentProps {
54
- table: {
55
- bulkActions?: Array<Record<string, unknown>>;
56
- columns?: TableColumn[];
57
- data?: TableRow[];
58
- endpoint?: string;
59
- ref?: string;
60
- lazy?: boolean;
61
- layout?: string;
62
- striped?: boolean;
63
- pagination?: Record<string, unknown>;
64
- state?: Record<string, unknown>;
65
- };
66
- }
35
+ /**
36
+ * The table node as it reaches the client: the generated wire props plus the
37
+ * rows, pagination, and state the server hydrates onto it for the initial render.
38
+ */
39
+ export type TableNodeProps = Partial<Omit<Table, "bulkActions">> & {
40
+ bulkActions?: ActionNode[];
41
+ data?: TableRow[];
42
+ pagination?: TablePagination;
43
+ state?: Partial<TableState>;
44
+ };
45
+ export type TableNode = {
46
+ type: "table";
47
+ id?: string;
48
+ key?: string;
49
+ props?: TableNodeProps;
50
+ };
51
+ /**
52
+ * Augmentable map of column `type` string → props. Consumer apps extend it via
53
+ * `declare module "@lattice-php/lattice"` so their custom columns gain strong
54
+ * prop types; the entries are generated by `php artisan lattice:typescript`.
55
+ */
56
+ export interface ColumnProps {
67
57
  }
58
+ type BuiltInColumnPropsOf<TType extends string> = TType extends keyof ColumnPropsMap ? ColumnPropsMap[TType] : never;
59
+ /**
60
+ * Resolves a column `type` to its props: consumer augmentations (`ColumnProps`)
61
+ * first, then the generated built-ins, then a loose bag.
62
+ */
63
+ export type ColumnPropsOf<TType extends string> = TType extends keyof ColumnProps ? ColumnProps[TType] : [BuiltInColumnPropsOf<TType>] extends [never] ? Record<string, unknown> | undefined : BuiltInColumnPropsOf<TType>;
@@ -1,7 +1,6 @@
1
- import { Node } from '../../../core/types';
2
- import { FilterClause, TableColumn, TableSort, TableState } from './types';
3
- export declare function useTable(node: Node<"table">): {
4
- columns: TableColumn[];
1
+ import { FilterClause, TableColumn, TableNode, TableSort, TableState } from './types';
2
+ export declare function useTable(node: TableNode): {
3
+ columns: import('./types').ColumnData[];
5
4
  rows: import('./types').TableRow[];
6
5
  pagination: import('./types').TablePagination;
7
6
  state: TableState;
@@ -5,7 +5,7 @@ import { buildEndpoint, nextSort } from "./query.js";
5
5
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
6
  //#region resources/js/table/use-table.ts
7
7
  function useTable(node) {
8
- const columns = getColumns(node.props?.columns);
8
+ const columns = useMemo(() => getColumns(node.props?.columns), [node.props?.columns]);
9
9
  const endpoint = typeof node.props?.endpoint === "string" ? node.props.endpoint : null;
10
10
  const componentRef = typeof node.props?.ref === "string" ? node.props.ref : "";
11
11
  const isLazy = node.props?.lazy === true;
@@ -13,7 +13,6 @@ function useTable(node) {
13
13
  const [rows, setRows] = useState(() => getRows(node.props?.data));
14
14
  const [pagination, setPagination] = useState(() => getPagination(node.props?.pagination));
15
15
  const [state, setState] = useState(initialState);
16
- const [filters, setFilters] = useState(initialState.filters);
17
16
  const [processing, setProcessing] = useState(isLazy);
18
17
  const [hasLoaded, setHasLoaded] = useState(!isLazy);
19
18
  const infiniteLoaderRef = useRef(null);
@@ -32,7 +31,6 @@ function useTable(node) {
32
31
  setRows((currentRows) => append ? [...currentRows, ...resultRows] : resultRows);
33
32
  setPagination(getPagination(result.pagination));
34
33
  setState(resultState);
35
- setFilters(resultState.filters);
36
34
  setHasLoaded(true);
37
35
  } finally {
38
36
  setProcessing(false);
@@ -52,32 +50,23 @@ function useTable(node) {
52
50
  sorts: state.sorts.filter((currentSort) => currentSort.key !== sort.key)
53
51
  });
54
52
  }
55
- function addFilter(clause) {
56
- const next = [...filters, clause];
57
- setFilters(next);
58
- load({
53
+ function applyFilters(next) {
54
+ const nextState = {
59
55
  ...state,
60
56
  filters: next,
61
57
  page: 1
62
- });
58
+ };
59
+ setState(nextState);
60
+ load(nextState);
61
+ }
62
+ function addFilter(clause) {
63
+ applyFilters([...state.filters, clause]);
63
64
  }
64
65
  function updateFilter(index, clause) {
65
- const next = filters.map((current, position) => position === index ? clause : current);
66
- setFilters(next);
67
- load({
68
- ...state,
69
- filters: next,
70
- page: 1
71
- });
66
+ applyFilters(state.filters.map((current, position) => position === index ? clause : current));
72
67
  }
73
68
  function removeFilter(index) {
74
- const next = filters.filter((_, current) => current !== index);
75
- setFilters(next);
76
- load({
77
- ...state,
78
- filters: next,
79
- page: 1
80
- });
69
+ applyFilters(state.filters.filter((_, current) => current !== index));
81
70
  }
82
71
  function goToPage(page) {
83
72
  load({
@@ -138,7 +127,7 @@ function useTable(node) {
138
127
  rows,
139
128
  pagination,
140
129
  state,
141
- filters,
130
+ filters: state.filters,
142
131
  addFilter,
143
132
  updateFilter,
144
133
  removeFilter,
@@ -1 +1 @@
1
- {"version":3,"file":"use-table.js","names":[],"sources":["../../resources/js/table/use-table.ts"],"sourcesContent":["import { withRefHeader } from \"@lattice/lattice/core/component-ref\";\nimport type { Node } from \"@lattice/lattice/core/types\";\nimport { LATTICE_EVENT, type ReloadComponentEvent } from \"@lattice/lattice/events/event-names\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { getColumns, getPagination, getRows, getState } from \"./payload\";\nimport { buildEndpoint, nextSort } from \"./query\";\nimport type { FilterClause, TableColumn, TableResponse, TableSort, TableState } from \"./types\";\n\nexport function useTable(node: Node<\"table\">) {\n const columns = getColumns(node.props?.columns);\n const endpoint = typeof node.props?.endpoint === \"string\" ? node.props.endpoint : null;\n const componentRef = typeof node.props?.ref === \"string\" ? node.props.ref : \"\";\n const isLazy = node.props?.lazy === true;\n const initialState = useMemo(() => getState(node.props?.state), [node.props?.state]);\n const [rows, setRows] = useState(() => getRows(node.props?.data));\n const [pagination, setPagination] = useState(() => getPagination(node.props?.pagination));\n const [state, setState] = useState(initialState);\n const [filters, setFilters] = useState(initialState.filters);\n const [processing, setProcessing] = useState(isLazy);\n const [hasLoaded, setHasLoaded] = useState(!isLazy);\n const infiniteLoaderRef = useRef<HTMLDivElement | null>(null);\n const currentPage = pagination.currentPage ?? state.page;\n const isInfinite = (pagination.mode ?? \"table\") === \"infinite\";\n\n const load = useCallback(\n async (nextState: TableState, append = false): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n setProcessing(true);\n\n try {\n const response = await fetch(buildEndpoint(endpoint, nextState), {\n headers: {\n Accept: \"application/json\",\n ...withRefHeader(componentRef),\n },\n });\n const result = (await response.json()) as TableResponse;\n const resultState = getState(result.state);\n const resultRows = getRows(result.data);\n\n setRows((currentRows) => (append ? [...currentRows, ...resultRows] : resultRows));\n setPagination(getPagination(result.pagination));\n setState(resultState);\n setFilters(resultState.filters);\n setHasLoaded(true);\n } finally {\n setProcessing(false);\n }\n },\n [endpoint, componentRef],\n );\n\n function sort(column: TableColumn): void {\n void load({\n ...state,\n page: 1,\n sorts: nextSort(state.sorts, column),\n });\n }\n\n function clearSort(sort: TableSort): void {\n void load({\n ...state,\n page: 1,\n sorts: state.sorts.filter((currentSort) => currentSort.key !== sort.key),\n });\n }\n\n function addFilter(clause: FilterClause): void {\n const next = [...filters, clause];\n\n setFilters(next);\n void load({\n ...state,\n filters: next,\n page: 1,\n });\n }\n\n function updateFilter(index: number, clause: FilterClause): void {\n const next = filters.map((current, position) => (position === index ? clause : current));\n\n setFilters(next);\n void load({\n ...state,\n filters: next,\n page: 1,\n });\n }\n\n function removeFilter(index: number): void {\n const next = filters.filter((_, current) => current !== index);\n\n setFilters(next);\n void load({\n ...state,\n filters: next,\n page: 1,\n });\n }\n\n function goToPage(page: number): void {\n void load({\n ...state,\n page,\n });\n }\n\n const loadMore = useCallback((): void => {\n if (processing || !pagination.hasMore) {\n return;\n }\n\n void load(\n {\n ...state,\n page: pagination.nextPage ?? currentPage + 1,\n },\n true,\n );\n }, [currentPage, load, pagination.hasMore, pagination.nextPage, processing, state]);\n\n useEffect(() => {\n if (!isLazy || hasLoaded) {\n return;\n }\n\n void load(state);\n }, [hasLoaded, isLazy, load, state]);\n\n useEffect(() => {\n function reload(event: Event): void {\n const detail = (event as ReloadComponentEvent).detail;\n\n if (detail?.component !== node.id) {\n return;\n }\n\n void load(state);\n }\n\n window.addEventListener(LATTICE_EVENT.reloadComponent, reload);\n\n return () => window.removeEventListener(LATTICE_EVENT.reloadComponent, reload);\n }, [load, node.id, state]);\n\n useEffect(() => {\n if (\n !isInfinite ||\n !pagination.hasMore ||\n processing ||\n !infiniteLoaderRef.current ||\n typeof IntersectionObserver === \"undefined\"\n ) {\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n loadMore();\n }\n },\n {\n rootMargin: \"240px\",\n },\n );\n\n observer.observe(infiniteLoaderRef.current);\n\n return () => observer.disconnect();\n }, [isInfinite, loadMore, pagination.hasMore, processing]);\n\n return {\n columns,\n rows,\n pagination,\n state,\n filters,\n addFilter,\n updateFilter,\n removeFilter,\n processing,\n hasLoaded,\n infiniteLoaderRef,\n sort,\n clearSort,\n goToPage,\n loadMore,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-table.js","names":[],"sources":["../../resources/js/table/use-table.ts"],"sourcesContent":["import { withRefHeader } from \"@lattice/lattice/core/component-ref\";\nimport { LATTICE_EVENT, type ReloadComponentEvent } from \"@lattice/lattice/events/event-names\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { getColumns, getPagination, getRows, getState } from \"./payload\";\nimport { buildEndpoint, nextSort } from \"./query\";\nimport type {\n FilterClause,\n TableColumn,\n TableNode,\n TableResponse,\n TableSort,\n TableState,\n} from \"./types\";\n\nexport function useTable(node: TableNode) {\n const columns = useMemo(() => getColumns(node.props?.columns), [node.props?.columns]);\n const endpoint = typeof node.props?.endpoint === \"string\" ? node.props.endpoint : null;\n const componentRef = typeof node.props?.ref === \"string\" ? node.props.ref : \"\";\n const isLazy = node.props?.lazy === true;\n const initialState = useMemo(() => getState(node.props?.state), [node.props?.state]);\n const [rows, setRows] = useState(() => getRows(node.props?.data));\n const [pagination, setPagination] = useState(() => getPagination(node.props?.pagination));\n const [state, setState] = useState(initialState);\n const [processing, setProcessing] = useState(isLazy);\n const [hasLoaded, setHasLoaded] = useState(!isLazy);\n const infiniteLoaderRef = useRef<HTMLDivElement | null>(null);\n const currentPage = pagination.currentPage ?? state.page;\n const isInfinite = (pagination.mode ?? \"table\") === \"infinite\";\n\n const load = useCallback(\n async (nextState: TableState, append = false): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n setProcessing(true);\n\n try {\n const response = await fetch(buildEndpoint(endpoint, nextState), {\n headers: {\n Accept: \"application/json\",\n ...withRefHeader(componentRef),\n },\n });\n const result = (await response.json()) as TableResponse;\n const resultState = getState(result.state);\n const resultRows = getRows(result.data);\n\n setRows((currentRows) => (append ? [...currentRows, ...resultRows] : resultRows));\n setPagination(getPagination(result.pagination));\n setState(resultState);\n setHasLoaded(true);\n } finally {\n setProcessing(false);\n }\n },\n [endpoint, componentRef],\n );\n\n function sort(column: TableColumn): void {\n void load({\n ...state,\n page: 1,\n sorts: nextSort(state.sorts, column),\n });\n }\n\n function clearSort(sort: TableSort): void {\n void load({\n ...state,\n page: 1,\n sorts: state.sorts.filter((currentSort) => currentSort.key !== sort.key),\n });\n }\n\n function applyFilters(next: FilterClause[]): void {\n const nextState = { ...state, filters: next, page: 1 };\n\n setState(nextState);\n void load(nextState);\n }\n\n function addFilter(clause: FilterClause): void {\n applyFilters([...state.filters, clause]);\n }\n\n function updateFilter(index: number, clause: FilterClause): void {\n applyFilters(state.filters.map((current, position) => (position === index ? clause : current)));\n }\n\n function removeFilter(index: number): void {\n applyFilters(state.filters.filter((_, current) => current !== index));\n }\n\n function goToPage(page: number): void {\n void load({\n ...state,\n page,\n });\n }\n\n const loadMore = useCallback((): void => {\n if (processing || !pagination.hasMore) {\n return;\n }\n\n void load(\n {\n ...state,\n page: pagination.nextPage ?? currentPage + 1,\n },\n true,\n );\n }, [currentPage, load, pagination.hasMore, pagination.nextPage, processing, state]);\n\n useEffect(() => {\n if (!isLazy || hasLoaded) {\n return;\n }\n\n void load(state);\n }, [hasLoaded, isLazy, load, state]);\n\n useEffect(() => {\n function reload(event: Event): void {\n const detail = (event as ReloadComponentEvent).detail;\n\n if (detail?.component !== node.id) {\n return;\n }\n\n void load(state);\n }\n\n window.addEventListener(LATTICE_EVENT.reloadComponent, reload);\n\n return () => window.removeEventListener(LATTICE_EVENT.reloadComponent, reload);\n }, [load, node.id, state]);\n\n useEffect(() => {\n if (\n !isInfinite ||\n !pagination.hasMore ||\n processing ||\n !infiniteLoaderRef.current ||\n typeof IntersectionObserver === \"undefined\"\n ) {\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n loadMore();\n }\n },\n {\n rootMargin: \"240px\",\n },\n );\n\n observer.observe(infiniteLoaderRef.current);\n\n return () => observer.disconnect();\n }, [isInfinite, loadMore, pagination.hasMore, processing]);\n\n return {\n columns,\n rows,\n pagination,\n state,\n filters: state.filters,\n addFilter,\n updateFilter,\n removeFilter,\n processing,\n hasLoaded,\n infiniteLoaderRef,\n sort,\n clearSort,\n goToPage,\n loadMore,\n };\n}\n"],"mappings":"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"}