@exxatdesignux/ui 0.2.19 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (688) hide show
  1. package/CHANGELOG.md +60 -7
  2. package/bin/sync-extras.mjs +116 -29
  3. package/consumer-extras/README.md +42 -7
  4. package/consumer-extras/cursor-rules/exxat-accessibility.mdc +39 -0
  5. package/consumer-extras/cursor-rules/exxat-board-cards.mdc +26 -0
  6. package/consumer-extras/cursor-rules/exxat-breadcrumbs-no-back.mdc +21 -0
  7. package/consumer-extras/cursor-rules/exxat-card-vs-list-rows.mdc +21 -0
  8. package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +44 -0
  9. package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +32 -0
  10. package/consumer-extras/cursor-rules/exxat-command-menu.mdc +22 -0
  11. package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +53 -0
  12. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +41 -0
  13. package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +25 -0
  14. package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +22 -0
  15. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +56 -0
  16. package/consumer-extras/cursor-rules/exxat-fontawesome-icons.mdc +31 -0
  17. package/consumer-extras/cursor-rules/exxat-kbd-shortcuts.mdc +100 -0
  18. package/consumer-extras/cursor-rules/exxat-kpi-flat-band.mdc +28 -0
  19. package/consumer-extras/cursor-rules/exxat-kpi-max-four.mdc +21 -0
  20. package/consumer-extras/cursor-rules/exxat-kpi-trends.mdc +31 -0
  21. package/consumer-extras/cursor-rules/exxat-list-page-connected-views.mdc +24 -0
  22. package/consumer-extras/cursor-rules/exxat-list-page-view-shells.mdc +31 -0
  23. package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +30 -0
  24. package/consumer-extras/cursor-rules/exxat-no-slds-leakage.mdc +78 -0
  25. package/consumer-extras/cursor-rules/exxat-no-toast.mdc +25 -0
  26. package/consumer-extras/cursor-rules/exxat-page-vs-drawer.mdc +23 -0
  27. package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +47 -0
  28. package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +52 -0
  29. package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +28 -0
  30. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +34 -0
  31. package/consumer-extras/cursor-rules/exxat-table-properties-drawer.mdc +77 -0
  32. package/consumer-extras/cursor-rules/exxat-token-discipline.mdc +103 -0
  33. package/consumer-extras/cursor-skills/exxat-accessibility/SKILL.md +1 -1
  34. package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
  35. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +4 -15
  36. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +13 -28
  37. package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +1 -1
  38. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +2 -4
  39. package/consumer-extras/handbook/HANDBOOK.md +185 -0
  40. package/consumer-extras/handbook/glossary.md +57 -0
  41. package/consumer-extras/handbook/reference-implementations.md +126 -0
  42. package/consumer-extras/handbook/voice-and-tone.md +262 -0
  43. package/consumer-extras/patterns/command-menu-pattern.md +1 -1
  44. package/consumer-extras/patterns/consumer-upgrade-checklist.md +0 -20
  45. package/consumer-extras/patterns/data-views-pattern.md +17 -54
  46. package/consumer-extras/patterns/shell-surface-elevation-pattern.md +3 -5
  47. package/dist/components/data-table/filter-date-calendar.d.ts +10 -0
  48. package/dist/components/data-table/filter-date-calendar.js +280 -0
  49. package/dist/components/data-table/filter-date-calendar.js.map +1 -0
  50. package/dist/components/data-table/filter-text-value-input.d.ts +15 -0
  51. package/dist/components/data-table/filter-text-value-input.js +561 -0
  52. package/dist/components/data-table/filter-text-value-input.js.map +1 -0
  53. package/dist/components/data-table/index.d.ts +45 -0
  54. package/dist/components/data-table/index.js +3085 -0
  55. package/dist/components/data-table/index.js.map +1 -0
  56. package/dist/components/data-table/pagination.d.ts +28 -0
  57. package/dist/components/data-table/pagination.js +3264 -0
  58. package/dist/components/data-table/pagination.js.map +1 -0
  59. package/dist/components/data-table/types.d.ts +84 -0
  60. package/dist/components/data-table/types.js +3 -0
  61. package/dist/components/data-table/types.js.map +1 -0
  62. package/dist/components/data-table/use-table-state.d.ts +116 -0
  63. package/dist/components/data-table/use-table-state.js +670 -0
  64. package/dist/components/data-table/use-table-state.js.map +1 -0
  65. package/dist/components/data-views/board-card-primitives.d.ts +22 -0
  66. package/dist/components/data-views/board-card-primitives.js +84 -0
  67. package/dist/components/data-views/board-card-primitives.js.map +1 -0
  68. package/dist/components/data-views/data-row-list.d.ts +33 -0
  69. package/dist/components/data-views/data-row-list.js +106 -0
  70. package/dist/components/data-views/data-row-list.js.map +1 -0
  71. package/dist/components/data-views/finder-panel-view.d.ts +54 -0
  72. package/dist/components/data-views/finder-panel-view.js +388 -0
  73. package/dist/components/data-views/finder-panel-view.js.map +1 -0
  74. package/dist/components/data-views/folder-grid-view.d.ts +22 -0
  75. package/dist/components/data-views/folder-grid-view.js +58 -0
  76. package/dist/components/data-views/folder-grid-view.js.map +1 -0
  77. package/dist/components/data-views/hub-table.d.ts +167 -0
  78. package/dist/components/data-views/hub-table.js +5561 -0
  79. package/dist/components/data-views/hub-table.js.map +1 -0
  80. package/dist/components/data-views/index.d.ts +27 -0
  81. package/dist/components/data-views/index.js +6575 -0
  82. package/dist/components/data-views/index.js.map +1 -0
  83. package/dist/components/data-views/list-page-board-card.d.ts +72 -0
  84. package/dist/components/data-views/list-page-board-card.js +264 -0
  85. package/dist/components/data-views/list-page-board-card.js.map +1 -0
  86. package/dist/components/data-views/list-page-board-template.d.ts +24 -0
  87. package/dist/components/data-views/list-page-board-template.js +137 -0
  88. package/dist/components/data-views/list-page-board-template.js.map +1 -0
  89. package/dist/components/data-views/list-page-connected-view-body.d.ts +19 -0
  90. package/dist/components/data-views/list-page-connected-view-body.js +116 -0
  91. package/dist/components/data-views/list-page-connected-view-body.js.map +1 -0
  92. package/dist/components/data-views/list-page-split-details-placeholder.d.ts +14 -0
  93. package/dist/components/data-views/list-page-split-details-placeholder.js +38 -0
  94. package/dist/components/data-views/list-page-split-details-placeholder.js.map +1 -0
  95. package/dist/components/data-views/list-page-split-hub-chrome.d.ts +17 -0
  96. package/dist/components/data-views/list-page-split-hub-chrome.js +54 -0
  97. package/dist/components/data-views/list-page-split-hub-chrome.js.map +1 -0
  98. package/dist/components/data-views/list-page-split-hub-tokens.d.ts +12 -0
  99. package/dist/components/data-views/list-page-split-hub-tokens.js +8 -0
  100. package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -0
  101. package/dist/components/data-views/list-page-tree-column-header.d.ts +15 -0
  102. package/dist/components/data-views/list-page-tree-column-header.js +22 -0
  103. package/dist/components/data-views/list-page-tree-column-header.js.map +1 -0
  104. package/dist/components/data-views/list-page-tree-panel-shell.d.ts +25 -0
  105. package/dist/components/data-views/list-page-tree-panel-shell.js +146 -0
  106. package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -0
  107. package/dist/components/data-views/os-folder-glyph.d.ts +35 -0
  108. package/dist/components/data-views/os-folder-glyph.js +104 -0
  109. package/dist/components/data-views/os-folder-glyph.js.map +1 -0
  110. package/dist/components/data-views/outline-tree-menu.d.ts +36 -0
  111. package/dist/components/data-views/outline-tree-menu.js +131 -0
  112. package/dist/components/data-views/outline-tree-menu.js.map +1 -0
  113. package/dist/components/table-properties/column-row.d.ts +22 -0
  114. package/dist/components/table-properties/column-row.js +153 -0
  115. package/dist/components/table-properties/column-row.js.map +1 -0
  116. package/dist/components/table-properties/draggable-list.d.ts +24 -0
  117. package/dist/components/table-properties/draggable-list.js +53 -0
  118. package/dist/components/table-properties/draggable-list.js.map +1 -0
  119. package/dist/components/table-properties/drawer-button.d.ts +110 -0
  120. package/dist/components/table-properties/drawer-button.js +2748 -0
  121. package/dist/components/table-properties/drawer-button.js.map +1 -0
  122. package/dist/components/table-properties/drawer.d.ts +100 -0
  123. package/dist/components/table-properties/drawer.js +2595 -0
  124. package/dist/components/table-properties/drawer.js.map +1 -0
  125. package/dist/components/table-properties/filter-card.d.ts +24 -0
  126. package/dist/components/table-properties/filter-card.js +854 -0
  127. package/dist/components/table-properties/filter-card.js.map +1 -0
  128. package/dist/components/table-properties/index.d.ts +14 -0
  129. package/dist/components/table-properties/index.js +2768 -0
  130. package/dist/components/table-properties/index.js.map +1 -0
  131. package/dist/components/table-properties/sort-card.d.ts +20 -0
  132. package/dist/components/table-properties/sort-card.js +102 -0
  133. package/dist/components/table-properties/sort-card.js.map +1 -0
  134. package/dist/components/templates/dedicated-search-landing-template.d.ts +21 -0
  135. package/dist/components/templates/dedicated-search-landing-template.js +254 -0
  136. package/dist/components/templates/dedicated-search-landing-template.js.map +1 -0
  137. package/dist/components/templates/dedicated-search-results-template.d.ts +15 -0
  138. package/dist/components/templates/dedicated-search-results-template.js +16 -0
  139. package/dist/components/templates/dedicated-search-results-template.js.map +1 -0
  140. package/dist/components/templates/index.d.ts +9 -0
  141. package/dist/components/templates/index.js +2720 -0
  142. package/dist/components/templates/index.js.map +1 -0
  143. package/dist/components/templates/list-page.d.ts +83 -0
  144. package/dist/components/templates/list-page.js +2433 -0
  145. package/dist/components/templates/list-page.js.map +1 -0
  146. package/dist/components/templates/nested-secondary-panel-shell.d.ts +20 -0
  147. package/dist/components/templates/nested-secondary-panel-shell.js +54 -0
  148. package/dist/components/templates/nested-secondary-panel-shell.js.map +1 -0
  149. package/dist/components/ui/accordion.d.ts +10 -0
  150. package/dist/components/ui/accordion.js +74 -0
  151. package/dist/components/ui/accordion.js.map +1 -0
  152. package/dist/components/ui/alert-dialog.d.ts +37 -0
  153. package/dist/components/ui/alert-dialog.js +201 -0
  154. package/dist/components/ui/alert-dialog.js.map +1 -0
  155. package/dist/components/ui/avatar.d.ts +84 -0
  156. package/dist/components/ui/avatar.js +328 -0
  157. package/dist/components/ui/avatar.js.map +1 -0
  158. package/dist/components/ui/badge.d.ts +13 -0
  159. package/dist/components/ui/badge.js +49 -0
  160. package/dist/components/ui/badge.js.map +1 -0
  161. package/dist/components/ui/banner.d.ts +62 -0
  162. package/dist/components/ui/banner.js +364 -0
  163. package/dist/components/ui/banner.js.map +1 -0
  164. package/dist/components/ui/breadcrumb.d.ts +14 -0
  165. package/dist/components/ui/breadcrumb.js +114 -0
  166. package/dist/components/ui/breadcrumb.js.map +1 -0
  167. package/dist/components/ui/button.d.ts +16 -0
  168. package/dist/components/ui/button.js +59 -0
  169. package/dist/components/ui/button.js.map +1 -0
  170. package/dist/components/ui/calendar.d.ts +13 -0
  171. package/dist/components/ui/calendar.js +238 -0
  172. package/dist/components/ui/calendar.js.map +1 -0
  173. package/dist/components/ui/card.d.ts +14 -0
  174. package/dist/components/ui/card.js +102 -0
  175. package/dist/components/ui/card.js.map +1 -0
  176. package/dist/components/ui/chart.d.ts +58 -0
  177. package/dist/components/ui/chart.js +292 -0
  178. package/dist/components/ui/chart.js.map +1 -0
  179. package/dist/components/ui/checkbox.d.ts +23 -0
  180. package/dist/components/ui/checkbox.js +155 -0
  181. package/dist/components/ui/checkbox.js.map +1 -0
  182. package/dist/components/ui/coach-mark.d.ts +27 -0
  183. package/dist/components/ui/coach-mark.js +306 -0
  184. package/dist/components/ui/coach-mark.js.map +1 -0
  185. package/dist/components/ui/collapsible.d.ts +8 -0
  186. package/dist/components/ui/collapsible.js +35 -0
  187. package/dist/components/ui/collapsible.js.map +1 -0
  188. package/dist/components/ui/command.d.ts +36 -0
  189. package/dist/components/ui/command.js +274 -0
  190. package/dist/components/ui/command.js.map +1 -0
  191. package/dist/components/ui/context-menu.d.ts +32 -0
  192. package/dist/components/ui/context-menu.js +245 -0
  193. package/dist/components/ui/context-menu.js.map +1 -0
  194. package/dist/components/ui/date-picker-field.d.ts +38 -0
  195. package/dist/components/ui/date-picker-field.js +550 -0
  196. package/dist/components/ui/date-picker-field.js.map +1 -0
  197. package/dist/components/ui/dialog.d.ts +22 -0
  198. package/dist/components/ui/dialog.js +200 -0
  199. package/dist/components/ui/dialog.js.map +1 -0
  200. package/dist/components/ui/dot-pattern.d.ts +21 -0
  201. package/dist/components/ui/dot-pattern.js +139 -0
  202. package/dist/components/ui/dot-pattern.js.map +1 -0
  203. package/dist/components/ui/drag-handle-grip.d.ts +10 -0
  204. package/dist/components/ui/drag-handle-grip.js +15 -0
  205. package/dist/components/ui/drag-handle-grip.js.map +1 -0
  206. package/dist/components/ui/drawer.d.ts +16 -0
  207. package/dist/components/ui/drawer.js +125 -0
  208. package/dist/components/ui/drawer.js.map +1 -0
  209. package/dist/components/ui/dropdown-menu.d.ts +45 -0
  210. package/dist/components/ui/dropdown-menu.js +353 -0
  211. package/dist/components/ui/dropdown-menu.js.map +1 -0
  212. package/dist/components/ui/export-drawer.d.ts +11 -0
  213. package/dist/components/ui/export-drawer.js +1658 -0
  214. package/dist/components/ui/export-drawer.js.map +1 -0
  215. package/dist/components/ui/field.d.ts +30 -0
  216. package/dist/components/ui/field.js +249 -0
  217. package/dist/components/ui/field.js.map +1 -0
  218. package/dist/components/ui/form.d.ts +28 -0
  219. package/dist/components/ui/form.js +110 -0
  220. package/dist/components/ui/form.js.map +1 -0
  221. package/dist/components/ui/hover-card.d.ts +9 -0
  222. package/dist/components/ui/hover-card.js +43 -0
  223. package/dist/components/ui/hover-card.js.map +1 -0
  224. package/dist/components/ui/input-group.d.ts +20 -0
  225. package/dist/components/ui/input-group.js +219 -0
  226. package/dist/components/ui/input-group.js.map +1 -0
  227. package/dist/components/ui/input-mask.d.ts +39 -0
  228. package/dist/components/ui/input-mask.js +118 -0
  229. package/dist/components/ui/input-mask.js.map +1 -0
  230. package/dist/components/ui/input.d.ts +5 -0
  231. package/dist/components/ui/input.js +30 -0
  232. package/dist/components/ui/input.js.map +1 -0
  233. package/dist/components/ui/kbd.d.ts +20 -0
  234. package/dist/components/ui/kbd.js +45 -0
  235. package/dist/components/ui/kbd.js.map +1 -0
  236. package/dist/components/ui/key-metrics-context.d.ts +19 -0
  237. package/dist/components/ui/key-metrics-context.js +26 -0
  238. package/dist/components/ui/key-metrics-context.js.map +1 -0
  239. package/dist/components/ui/key-metrics.d.ts +131 -0
  240. package/dist/components/ui/key-metrics.js +1015 -0
  241. package/dist/components/ui/key-metrics.js.map +1 -0
  242. package/dist/components/ui/label.d.ts +6 -0
  243. package/dist/components/ui/label.js +28 -0
  244. package/dist/components/ui/label.js.map +1 -0
  245. package/dist/components/ui/list-page-view-frame.d.ts +22 -0
  246. package/dist/components/ui/list-page-view-frame.js +24 -0
  247. package/dist/components/ui/list-page-view-frame.js.map +1 -0
  248. package/dist/components/ui/page-header.d.ts +51 -0
  249. package/dist/components/ui/page-header.js +372 -0
  250. package/dist/components/ui/page-header.js.map +1 -0
  251. package/dist/components/ui/payment-card-fields.d.ts +10 -0
  252. package/dist/components/ui/payment-card-fields.js +80 -0
  253. package/dist/components/ui/payment-card-fields.js.map +1 -0
  254. package/dist/components/ui/popover.d.ts +10 -0
  255. package/dist/components/ui/popover.js +47 -0
  256. package/dist/components/ui/popover.js.map +1 -0
  257. package/dist/components/ui/radio-group.d.ts +29 -0
  258. package/dist/components/ui/radio-group.js +190 -0
  259. package/dist/components/ui/radio-group.js.map +1 -0
  260. package/dist/components/ui/resizable.d.ts +16 -0
  261. package/dist/components/ui/resizable.js +51 -0
  262. package/dist/components/ui/resizable.js.map +1 -0
  263. package/dist/components/ui/scroll-area.d.ts +8 -0
  264. package/dist/components/ui/scroll-area.js +66 -0
  265. package/dist/components/ui/scroll-area.js.map +1 -0
  266. package/dist/components/ui/select.d.ts +18 -0
  267. package/dist/components/ui/select.js +186 -0
  268. package/dist/components/ui/select.js.map +1 -0
  269. package/dist/components/ui/selection-tile-grid.d.ts +52 -0
  270. package/dist/components/ui/selection-tile-grid.js +347 -0
  271. package/dist/components/ui/selection-tile-grid.js.map +1 -0
  272. package/dist/components/ui/separator.d.ts +7 -0
  273. package/dist/components/ui/separator.js +33 -0
  274. package/dist/components/ui/separator.js.map +1 -0
  275. package/dist/components/ui/sheet.d.ts +18 -0
  276. package/dist/components/ui/sheet.js +181 -0
  277. package/dist/components/ui/sheet.js.map +1 -0
  278. package/dist/components/ui/sidebar.d.ts +94 -0
  279. package/dist/components/ui/sidebar.js +805 -0
  280. package/dist/components/ui/sidebar.js.map +1 -0
  281. package/dist/components/ui/skeleton.d.ts +5 -0
  282. package/dist/components/ui/skeleton.js +22 -0
  283. package/dist/components/ui/skeleton.js.map +1 -0
  284. package/dist/components/ui/slider.d.ts +7 -0
  285. package/dist/components/ui/slider.js +66 -0
  286. package/dist/components/ui/slider.js.map +1 -0
  287. package/dist/components/ui/sonner.d.ts +6 -0
  288. package/dist/components/ui/sonner.js +38 -0
  289. package/dist/components/ui/sonner.js.map +1 -0
  290. package/dist/components/ui/status-badge.d.ts +38 -0
  291. package/dist/components/ui/status-badge.js +77 -0
  292. package/dist/components/ui/status-badge.js.map +1 -0
  293. package/dist/components/ui/table.d.ts +13 -0
  294. package/dist/components/ui/table.js +115 -0
  295. package/dist/components/ui/table.js.map +1 -0
  296. package/dist/components/ui/tabs.d.ts +15 -0
  297. package/dist/components/ui/tabs.js +93 -0
  298. package/dist/components/ui/tabs.js.map +1 -0
  299. package/dist/components/ui/textarea.d.ts +6 -0
  300. package/dist/components/ui/textarea.js +25 -0
  301. package/dist/components/ui/textarea.js.map +1 -0
  302. package/dist/components/ui/tip.d.ts +12 -0
  303. package/dist/components/ui/tip.js +61 -0
  304. package/dist/components/ui/tip.js.map +1 -0
  305. package/dist/components/ui/toggle-group.d.ts +14 -0
  306. package/dist/components/ui/toggle-group.js +104 -0
  307. package/dist/components/ui/toggle-group.js.map +1 -0
  308. package/dist/components/ui/toggle-switch.d.ts +10 -0
  309. package/dist/components/ui/toggle-switch.js +33 -0
  310. package/dist/components/ui/toggle-switch.js.map +1 -0
  311. package/dist/components/ui/toggle.d.ts +13 -0
  312. package/dist/components/ui/toggle.js +51 -0
  313. package/dist/components/ui/toggle.js.map +1 -0
  314. package/dist/components/ui/tooltip.d.ts +10 -0
  315. package/dist/components/ui/tooltip.js +68 -0
  316. package/dist/components/ui/tooltip.js.map +1 -0
  317. package/dist/components/ui/view-segmented-control.d.ts +31 -0
  318. package/dist/components/ui/view-segmented-control.js +167 -0
  319. package/dist/components/ui/view-segmented-control.js.map +1 -0
  320. package/dist/data-list-view-registry-CyBoBML4.d.ts +73 -0
  321. package/dist/hooks/use-app-theme.d.ts +24 -0
  322. package/dist/hooks/use-app-theme.js +286 -0
  323. package/dist/hooks/use-app-theme.js.map +1 -0
  324. package/dist/hooks/use-coach-mark.d.ts +86 -0
  325. package/dist/hooks/use-coach-mark.js +218 -0
  326. package/dist/hooks/use-coach-mark.js.map +1 -0
  327. package/dist/hooks/use-mobile.d.ts +3 -0
  328. package/dist/hooks/use-mobile.js +29 -0
  329. package/dist/hooks/use-mobile.js.map +1 -0
  330. package/dist/hooks/use-mod-key-label.d.ts +6 -0
  331. package/dist/hooks/use-mod-key-label.js +25 -0
  332. package/dist/hooks/use-mod-key-label.js.map +1 -0
  333. package/dist/index.d.ts +120 -0
  334. package/dist/index.js +13324 -0
  335. package/dist/index.js.map +1 -0
  336. package/dist/lib/compose-refs.d.ts +6 -0
  337. package/dist/lib/compose-refs.js +17 -0
  338. package/dist/lib/compose-refs.js.map +1 -0
  339. package/dist/lib/conditional-rule-match.d.ts +30 -0
  340. package/dist/lib/conditional-rule-match.js +66 -0
  341. package/dist/lib/conditional-rule-match.js.map +1 -0
  342. package/dist/lib/data-list-display-options.d.ts +26 -0
  343. package/dist/lib/data-list-display-options.js +14 -0
  344. package/dist/lib/data-list-display-options.js.map +1 -0
  345. package/dist/lib/data-list-view-registry.d.ts +2 -0
  346. package/dist/lib/data-list-view-registry.js +102 -0
  347. package/dist/lib/data-list-view-registry.js.map +1 -0
  348. package/dist/lib/data-list-view-surface.d.ts +2 -0
  349. package/dist/lib/data-list-view-surface.js +80 -0
  350. package/dist/lib/data-list-view-surface.js.map +1 -0
  351. package/dist/lib/data-list-view.d.ts +21 -0
  352. package/dist/lib/data-list-view.js +25 -0
  353. package/dist/lib/data-list-view.js.map +1 -0
  354. package/dist/lib/date-filter.d.ts +22 -0
  355. package/dist/lib/date-filter.js +61 -0
  356. package/dist/lib/date-filter.js.map +1 -0
  357. package/dist/lib/dev-log.d.ts +8 -0
  358. package/dist/lib/dev-log.js +10 -0
  359. package/dist/lib/dev-log.js.map +1 -0
  360. package/dist/lib/dropdown-menu-surface.d.ts +14 -0
  361. package/dist/lib/dropdown-menu-surface.js +6 -0
  362. package/dist/lib/dropdown-menu-surface.js.map +1 -0
  363. package/dist/lib/editable-target.d.ts +12 -0
  364. package/dist/lib/editable-target.js +12 -0
  365. package/dist/lib/editable-target.js.map +1 -0
  366. package/dist/lib/list-page-table-properties.d.ts +35 -0
  367. package/dist/lib/list-page-table-properties.js +81 -0
  368. package/dist/lib/list-page-table-properties.js.map +1 -0
  369. package/dist/lib/raf-throttle.d.ts +23 -0
  370. package/dist/lib/raf-throttle.js +27 -0
  371. package/dist/lib/raf-throttle.js.map +1 -0
  372. package/dist/lib/row-height.d.ts +16 -0
  373. package/dist/lib/row-height.js +10 -0
  374. package/dist/lib/row-height.js.map +1 -0
  375. package/dist/lib/table-properties-types.d.ts +83 -0
  376. package/dist/lib/table-properties-types.js +19 -0
  377. package/dist/lib/table-properties-types.js.map +1 -0
  378. package/dist/lib/utils.d.ts +5 -0
  379. package/dist/lib/utils.js +11 -0
  380. package/dist/lib/utils.js.map +1 -0
  381. package/package.json +83 -19
  382. package/src/components/data-table/filter-date-calendar.tsx +38 -0
  383. package/src/components/data-table/filter-text-value-input.tsx +77 -0
  384. package/src/components/data-table/index.tsx +1678 -0
  385. package/src/components/data-table/pagination.tsx +255 -0
  386. package/src/components/data-table/types.ts +96 -0
  387. package/src/components/data-table/use-table-state.ts +767 -0
  388. package/src/components/data-views/board-card-primitives.tsx +93 -0
  389. package/src/components/data-views/data-row-list.tsx +183 -0
  390. package/src/components/data-views/finder-panel-view.tsx +405 -0
  391. package/src/components/data-views/folder-grid-view.tsx +86 -0
  392. package/src/components/data-views/hub-table.tsx +498 -0
  393. package/src/components/data-views/index.ts +28 -0
  394. package/src/components/data-views/list-page-board-card.tsx +192 -0
  395. package/src/components/data-views/list-page-board-template.tsx +122 -0
  396. package/src/components/data-views/list-page-connected-view-body.tsx +66 -0
  397. package/src/components/data-views/list-page-split-details-placeholder.tsx +39 -0
  398. package/src/components/data-views/list-page-split-hub-chrome.tsx +60 -0
  399. package/src/components/data-views/list-page-split-hub-tokens.ts +16 -0
  400. package/src/components/data-views/list-page-tree-column-header.tsx +31 -0
  401. package/src/components/data-views/list-page-tree-panel-shell.tsx +91 -0
  402. package/src/components/data-views/os-folder-glyph.tsx +141 -0
  403. package/src/components/data-views/outline-tree-menu.tsx +157 -0
  404. package/src/components/table-properties/column-row.tsx +90 -0
  405. package/src/components/table-properties/draggable-list.ts +54 -0
  406. package/src/components/table-properties/drawer-button.tsx +300 -0
  407. package/src/components/table-properties/drawer.tsx +1148 -0
  408. package/src/components/table-properties/filter-card.tsx +251 -0
  409. package/src/components/table-properties/index.ts +36 -0
  410. package/src/components/table-properties/sort-card.tsx +63 -0
  411. package/src/components/templates/dedicated-search-landing-template.tsx +124 -0
  412. package/src/components/templates/dedicated-search-results-template.tsx +19 -0
  413. package/src/components/templates/index.ts +33 -0
  414. package/src/components/templates/list-page.tsx +602 -0
  415. package/src/components/templates/nested-secondary-panel-shell.tsx +70 -0
  416. package/src/components/ui/accordion.tsx +92 -0
  417. package/src/components/ui/alert-dialog.tsx +221 -0
  418. package/src/components/ui/avatar.tsx +13 -2
  419. package/src/components/ui/banner.tsx +2 -2
  420. package/src/components/ui/button.tsx +4 -4
  421. package/src/components/ui/calendar.tsx +1 -1
  422. package/src/components/ui/coach-mark.tsx +1 -1
  423. package/src/components/ui/context-menu.tsx +291 -0
  424. package/src/components/ui/date-picker-field.tsx +2 -2
  425. package/src/components/ui/dot-pattern.tsx +183 -0
  426. package/src/components/ui/export-drawer.tsx +375 -0
  427. package/src/components/ui/hover-card.tsx +66 -0
  428. package/src/components/ui/key-metrics-context.tsx +78 -0
  429. package/src/components/ui/key-metrics.tsx +1133 -0
  430. package/src/components/ui/list-page-view-frame.tsx +64 -0
  431. package/src/components/ui/page-header.tsx +244 -0
  432. package/src/components/ui/payment-card-fields.tsx +2 -2
  433. package/src/components/ui/resizable.tsx +68 -0
  434. package/src/components/ui/scroll-area.tsx +72 -0
  435. package/src/components/ui/selection-tile-grid.tsx +9 -2
  436. package/src/components/ui/sidebar.tsx +84 -12
  437. package/src/components/ui/slider.tsx +83 -0
  438. package/src/globals.css +2201 -7
  439. package/src/globals.d.ts +20 -0
  440. package/src/index.ts +68 -1
  441. package/src/lib/conditional-rule-match.ts +119 -0
  442. package/src/lib/data-list-display-options.ts +35 -0
  443. package/src/lib/data-list-view-registry.ts +104 -0
  444. package/src/lib/data-list-view-surface.ts +83 -0
  445. package/src/lib/data-list-view.ts +47 -0
  446. package/src/lib/dev-log.ts +10 -0
  447. package/src/lib/editable-target.ts +20 -0
  448. package/src/lib/list-page-table-properties.ts +48 -0
  449. package/src/lib/raf-throttle.ts +45 -0
  450. package/src/lib/row-height.ts +19 -0
  451. package/src/lib/table-properties-types.ts +98 -0
  452. package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
  453. package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +3 -3
  454. package/template/.cursor/rules/exxat-data-tables.mdc +1 -1
  455. package/template/.cursor/rules/exxat-ds-agents.mdc +2 -2
  456. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +2 -2
  457. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
  458. package/template/AGENTS.md +104 -78
  459. package/template/app/(app)/dashboard/loading.tsx +15 -3
  460. package/template/app/(app)/dashboard/page.tsx +14 -2
  461. package/template/app/(app)/examples/page.tsx +0 -2
  462. package/template/app/(app)/layout.tsx +17 -4
  463. package/template/app/(app)/loading.tsx +18 -1
  464. package/template/app/(app)/question-bank/find/page.tsx +1 -2
  465. package/template/app/(app)/question-bank/layout.tsx +1 -1
  466. package/template/app/(app)/question-bank/library/page.tsx +1 -2
  467. package/template/app/(app)/question-bank/list/page.tsx +1 -2
  468. package/template/app/(app)/question-bank/new/page.tsx +15 -20
  469. package/template/app/(app)/question-bank/page.tsx +1 -2
  470. package/template/app/(app)/settings/page.tsx +5 -4
  471. package/template/app/globals.css +14 -16
  472. package/template/components/ask-leo-sidebar.tsx +5 -1
  473. package/template/components/brand-color-picker.tsx +2 -2
  474. package/template/components/charts-overview.tsx +1 -1
  475. package/template/components/compliance-board-view.tsx +142 -0
  476. package/template/components/compliance-client.tsx +92 -0
  477. package/template/components/compliance-page-header.tsx +89 -0
  478. package/template/components/compliance-table.tsx +468 -0
  479. package/template/components/dashboard-report-charts.tsx +1 -1
  480. package/template/components/dashboard-tabs.tsx +1 -1
  481. package/template/components/data-table/filter-date-calendar.tsx +1 -38
  482. package/template/components/data-table/filter-text-value-input.tsx +1 -77
  483. package/template/components/data-table/index.tsx +1 -1634
  484. package/template/components/data-table/pagination.tsx +1 -255
  485. package/template/components/data-table/types.ts +1 -94
  486. package/template/components/data-table/use-table-state.test.ts +420 -0
  487. package/template/components/data-table/use-table-state.ts +1 -758
  488. package/template/components/data-view-dashboard-charts-compliance.tsx +963 -0
  489. package/template/components/data-view-dashboard-charts-team.tsx +971 -0
  490. package/template/components/data-view-dashboard-charts.tsx +1503 -0
  491. package/template/components/data-views/board-card-primitives.tsx +1 -93
  492. package/template/components/data-views/data-row-list.tsx +1 -183
  493. package/template/components/data-views/finder-panel-view.tsx +1 -405
  494. package/template/components/data-views/folder-grid-view.tsx +1 -86
  495. package/template/components/data-views/hub-table.tsx +1 -0
  496. package/template/components/data-views/index.ts +50 -37
  497. package/template/components/data-views/list-page-board-card.tsx +1 -192
  498. package/template/components/data-views/list-page-board-template.tsx +1 -122
  499. package/template/components/data-views/list-page-connected-view-body.tsx +1 -66
  500. package/template/components/data-views/list-page-split-details-placeholder.tsx +1 -39
  501. package/template/components/data-views/list-page-split-hub-chrome.tsx +1 -68
  502. package/template/components/data-views/list-page-split-hub-tokens.ts +1 -16
  503. package/template/components/data-views/list-page-tree-column-header.tsx +1 -31
  504. package/template/components/data-views/list-page-tree-panel-shell.tsx +1 -91
  505. package/template/components/data-views/list-page-view-frame.tsx +5 -53
  506. package/template/components/data-views/os-folder-glyph.tsx +1 -129
  507. package/template/components/data-views/outline-tree-menu.tsx +1 -157
  508. package/template/components/export-drawer.test.tsx +71 -0
  509. package/template/components/export-drawer.tsx +1 -375
  510. package/template/components/exxat-product-logo.tsx +5 -5
  511. package/template/components/hub-tree-panel-view.tsx +2 -2
  512. package/template/components/invite-collaborators-drawer.tsx +3 -3
  513. package/template/components/key-metrics-ask-leo-bridge.tsx +40 -0
  514. package/template/components/key-metrics.tsx +1 -1063
  515. package/template/components/leo-insight-indicator.tsx +2 -2
  516. package/template/components/new-placement-back-btn.tsx +28 -0
  517. package/template/components/new-placement-form.tsx +942 -0
  518. package/template/components/new-question-composer.tsx +456 -408
  519. package/template/components/onboarding/index.ts +9 -0
  520. package/template/components/onboarding/onboarding-01.tsx +1 -1
  521. package/template/components/onboarding/onboarding-02.tsx +1 -1
  522. package/template/components/onboarding/onboarding-03.tsx +1 -1
  523. package/template/components/onboarding/onboarding-04.tsx +1 -1
  524. package/template/components/page-header.tsx +8 -226
  525. package/template/components/placement-board-card.tsx +250 -0
  526. package/template/components/placement-detail.tsx +438 -0
  527. package/template/components/placements-board-view.tsx +397 -0
  528. package/template/components/placements-client.tsx +220 -0
  529. package/template/components/placements-list-view.tsx +124 -0
  530. package/template/components/placements-page-header.tsx +166 -0
  531. package/template/components/placements-table-cells.test.tsx +22 -0
  532. package/template/components/placements-table-cells.tsx +173 -0
  533. package/template/components/placements-table-columns.tsx +210 -0
  534. package/template/components/placements-table.tsx +934 -0
  535. package/template/components/product-switcher.tsx +3 -4
  536. package/template/components/product-wordmark.tsx +2 -1
  537. package/template/components/question-bank-client.tsx +5 -5
  538. package/template/components/question-bank-hub-client.tsx +1 -1
  539. package/template/components/question-bank-new-folder-sheet.tsx +2 -2
  540. package/template/components/question-bank-secondary-nav.tsx +3 -3
  541. package/template/components/question-bank-table.tsx +541 -431
  542. package/template/components/rotations-empty-state.tsx +50 -0
  543. package/template/components/rotations-panel-activator.tsx +8 -0
  544. package/template/components/settings-appearance-card.tsx +3 -4
  545. package/template/components/settings-client.tsx +15 -59
  546. package/template/components/settings-form-row.tsx +4 -9
  547. package/template/components/{app-sidebar-dynamic.tsx → sidebar/app-sidebar-dynamic.tsx} +1 -1
  548. package/template/components/{app-sidebar.tsx → sidebar/app-sidebar.tsx} +59 -74
  549. package/template/components/sidebar/index.ts +16 -0
  550. package/template/components/{secondary-nav.tsx → sidebar/secondary-nav.tsx} +2 -2
  551. package/template/components/{secondary-panel.tsx → sidebar/secondary-panel.tsx} +50 -7
  552. package/template/components/{sidebar-auto-collapse.tsx → sidebar/sidebar-auto-collapse.tsx} +6 -2
  553. package/template/components/{sidebar-shell.tsx → sidebar/sidebar-shell.tsx} +1 -1
  554. package/template/components/site-header.tsx +1 -1
  555. package/template/components/sites-board-view.tsx +67 -0
  556. package/template/components/sites-client.tsx +154 -0
  557. package/template/components/sites-table.tsx +249 -0
  558. package/template/components/table-properties/column-row.tsx +1 -90
  559. package/template/components/table-properties/draggable-list.ts +1 -49
  560. package/template/components/table-properties/drawer-button.tsx +1 -262
  561. package/template/components/table-properties/drawer.tsx +1 -1166
  562. package/template/components/table-properties/filter-card.tsx +1 -251
  563. package/template/components/table-properties/sort-card.tsx +1 -59
  564. package/template/components/table-properties/types.ts +28 -71
  565. package/template/components/team-board-view.tsx +122 -0
  566. package/template/components/team-client.tsx +100 -0
  567. package/template/components/team-page-header.tsx +92 -0
  568. package/template/components/team-table.tsx +553 -0
  569. package/template/components/templates/dedicated-search-landing-template.tsx +1 -124
  570. package/template/components/templates/dedicated-search-results-template.tsx +1 -19
  571. package/template/components/templates/list-page.tsx +1 -608
  572. package/template/components/templates/nested-secondary-panel-shell.tsx +1 -63
  573. package/template/components/templates/new-focus-template.tsx +659 -0
  574. package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
  575. package/template/components/ui/accordion.tsx +1 -0
  576. package/template/components/ui/alert-dialog.tsx +1 -0
  577. package/template/components/ui/context-menu.tsx +1 -0
  578. package/template/components/ui/dot-pattern.tsx +1 -183
  579. package/template/components/ui/hover-card.tsx +1 -0
  580. package/template/components/ui/resizable.tsx +1 -68
  581. package/template/components/ui/scroll-area.tsx +1 -0
  582. package/template/components/ui/slider.tsx +1 -0
  583. package/template/docs/blueprints/README.md +86 -0
  584. package/template/docs/blueprints/_template.md +91 -0
  585. package/template/docs/blueprints/board-card.md +123 -0
  586. package/template/docs/blueprints/data-table.md +139 -0
  587. package/template/docs/blueprints/key-metrics.md +128 -0
  588. package/template/docs/blueprints/list-page-template.md +123 -0
  589. package/template/docs/blueprints/page-header.md +130 -0
  590. package/template/docs/command-menu-pattern.md +1 -1
  591. package/template/docs/component-selection-guide.md +224 -0
  592. package/template/docs/components-audit-2026-05.md +158 -0
  593. package/template/docs/data-views-pattern.md +17 -54
  594. package/template/docs/drawer-vs-dialog-pattern.md +1 -3
  595. package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +95 -0
  596. package/template/docs/migrations/0002-exxat-token-namespace.md +154 -0
  597. package/template/docs/migrations/0003-globals-css-canonical.md +110 -0
  598. package/template/docs/migrations/README.md +100 -0
  599. package/template/docs/migrations/_template.md +64 -0
  600. package/template/docs/shell-surface-elevation-pattern.md +3 -5
  601. package/template/docs/token-taxonomy.md +416 -0
  602. package/template/eslint.config.mjs +27 -0
  603. package/template/hooks/use-secondary-panel-hub-nav.ts +1 -1
  604. package/template/lib/command-menu-config.ts +0 -1
  605. package/template/lib/command-menu-search-data.ts +27 -11
  606. package/template/lib/compliance-supported-views.ts +10 -0
  607. package/template/lib/conditional-rule-match.ts +6 -97
  608. package/template/lib/data-list-display-options.ts +1 -49
  609. package/template/lib/data-list-view-registry.ts +1 -104
  610. package/template/lib/data-list-view-surface.ts +1 -83
  611. package/template/lib/data-list-view.ts +1 -47
  612. package/template/lib/data-view-dashboard-placements-layout.ts +215 -0
  613. package/template/lib/data-view-dashboard-storage.ts +35 -38
  614. package/template/lib/dev-log.ts +1 -8
  615. package/template/lib/editable-target.ts +1 -10
  616. package/template/lib/list-page-table-properties.ts +1 -48
  617. package/template/lib/list-status-badges.ts +97 -4
  618. package/template/lib/mock/compliance-kpi.ts +61 -0
  619. package/template/lib/mock/compliance.ts +146 -0
  620. package/template/lib/mock/navigation.tsx +0 -9
  621. package/template/lib/mock/placements-kpi.ts +134 -0
  622. package/template/lib/mock/placements.ts +176 -0
  623. package/template/lib/mock/sites-directory.ts +16 -0
  624. package/template/lib/mock/sites-kpi.ts +25 -0
  625. package/template/lib/mock/team-kpi.ts +60 -0
  626. package/template/lib/mock/team.ts +118 -0
  627. package/template/lib/placement-board-card-layout.ts +79 -0
  628. package/template/lib/placements-supported-views.ts +12 -0
  629. package/template/lib/question-bank-supported-views.ts +0 -1
  630. package/template/lib/raf-throttle.ts +1 -45
  631. package/template/lib/row-height.ts +4 -10
  632. package/template/lib/sidebar-state-cookie.ts +11 -2
  633. package/template/lib/sites-supported-views.ts +10 -0
  634. package/template/lib/table-state-lifecycle.ts +2 -2
  635. package/template/lib/team-supported-views.ts +10 -0
  636. package/template/package.json +1 -0
  637. package/template/tests/setup.ts +25 -0
  638. package/consumer-extras/AGENTS.md +0 -76
  639. package/consumer-extras/cursor-skills/exxat-consumer-app/SKILL.md +0 -37
  640. package/consumer-extras/cursor-skills/exxat-focused-workflow-page/SKILL.md +0 -57
  641. package/consumer-extras/patterns/consumer-app-pattern.md +0 -39
  642. package/consumer-extras/patterns/focused-workflow-page-pattern.md +0 -84
  643. package/src/components/ui/button-group.tsx +0 -81
  644. package/src/theme.css +0 -16
  645. package/src/tokens/README.md +0 -15
  646. package/src/tokens/base.css +0 -337
  647. package/src/tokens/high-contrast.css +0 -1195
  648. package/src/tokens/layers.css +0 -224
  649. package/src/tokens/tailwind-bridge.css +0 -118
  650. package/src/tokens/themes.css +0 -201
  651. package/template/app/(app)/data-list/layout.tsx +0 -43
  652. package/template/app/(app)/data-list/page.tsx +0 -10
  653. package/template/app/(app)/examples/focused-workflow/page.tsx +0 -5
  654. package/template/components/app-route-loading.tsx +0 -14
  655. package/template/components/dashboard-onboarding-gallery.tsx +0 -13
  656. package/template/components/dashboard-onboarding.tsx +0 -21
  657. package/template/components/data-views/list-page-calendar-view.tsx +0 -593
  658. package/template/components/data-views/list-page-folder-columns-panel.tsx +0 -345
  659. package/template/components/examples/focused-workflow-showcase.tsx +0 -183
  660. package/template/components/list-hub-board-view.tsx +0 -68
  661. package/template/components/list-hub-client.tsx +0 -186
  662. package/template/components/list-hub-list-view.tsx +0 -36
  663. package/template/components/list-hub-panel-activator.tsx +0 -8
  664. package/template/components/list-hub-secondary-nav.tsx +0 -121
  665. package/template/components/list-hub-table.tsx +0 -336
  666. package/template/components/question-bank-folder-columns-panel.tsx +0 -104
  667. package/template/components/question-bank-list-view.tsx +0 -53
  668. package/template/components/secondary-panel/nav-link-rows.tsx +0 -83
  669. package/template/components/secondary-panels/list-hub-panel.tsx +0 -39
  670. package/template/components/secondary-panels/question-bank-panel.tsx +0 -39
  671. package/template/components/secondary-panels/registry.tsx +0 -15
  672. package/template/components/section-cards.tsx +0 -106
  673. package/template/components/templates/focused-workflow-layouts.tsx +0 -448
  674. package/template/components/templates/focused-workflow-page-template.tsx +0 -69
  675. package/template/components/templates/page-loading-shell.tsx +0 -262
  676. package/template/components/ui/button-group.tsx +0 -1
  677. package/template/docs/consumer-app-pattern.md +0 -39
  678. package/template/docs/focused-workflow-page-pattern.md +0 -84
  679. package/template/lib/list-hub-nav.ts +0 -121
  680. package/template/lib/mock/list-hub-directory.ts +0 -27
  681. package/template/lib/mock/list-hub-kpi.ts +0 -27
  682. package/template/lib/page-loading-variant.ts +0 -40
  683. /package/template/components/{getting-started.tsx → onboarding/getting-started.tsx} +0 -0
  684. /package/template/components/{nav-documents.tsx → sidebar/nav-documents.tsx} +0 -0
  685. /package/template/components/{nav-main.tsx → sidebar/nav-main.tsx} +0 -0
  686. /package/template/components/{nav-secondary.tsx → sidebar/nav-secondary.tsx} +0 -0
  687. /package/template/components/{nav-user.tsx → sidebar/nav-user.tsx} +0 -0
  688. /package/template/components/{sidebar-auto-open.tsx → sidebar/sidebar-auto-open.tsx} +0 -0
@@ -0,0 +1,86 @@
1
+ "use client"
2
+
3
+ /**
4
+ * FolderGridView — generic icon-grid layout for any list-page hub.
5
+ *
6
+ * Handles the responsive CSS grid shell, empty state, and accessibility list role.
7
+ * Pass a `renderTile` render-prop for domain-specific tile content
8
+ * (Placements, Team, Rotations, etc.).
9
+ *
10
+ * Usage:
11
+ * ```tsx
12
+ * <FolderGridView
13
+ * rows={placements}
14
+ * getRowId={r => r.id}
15
+ * renderTile={row => <PlacementFolderTile row={row} onClick={…} />}
16
+ * ariaLabel="Placements folder view"
17
+ * />
18
+ * ```
19
+ */
20
+
21
+ import * as React from "react"
22
+ import { cn } from "../../lib/utils"
23
+ import {
24
+ ListPageViewFrame,
25
+ LIST_PAGE_VIEW_FRAME_MAX_ICON_GRID,
26
+ } from "../ui/list-page-view-frame"
27
+
28
+ export interface FolderGridViewProps<T> {
29
+ rows: T[]
30
+ getRowId: (row: T) => string | number
31
+ /** Render one tile — receives the row, returns a React node (typically a `<button>`). */
32
+ renderTile: (row: T) => React.ReactNode
33
+ /** Shown when `rows` is empty. */
34
+ emptyContent?: React.ReactNode
35
+ /** `aria-label` on the grid list. */
36
+ ariaLabel?: string
37
+ className?: string
38
+ /**
39
+ * When true, constrains the grid to a centered max width so folder tiles don’t stretch
40
+ * edge-to-edge on very wide viewports.
41
+ */
42
+ constrainWidth?: boolean
43
+ }
44
+
45
+ export function FolderGridView<T>({
46
+ rows,
47
+ getRowId,
48
+ renderTile,
49
+ emptyContent,
50
+ ariaLabel = "Folder view",
51
+ className,
52
+ constrainWidth = false,
53
+ }: FolderGridViewProps<T>) {
54
+ if (rows.length === 0) {
55
+ return (
56
+ <ListPageViewFrame
57
+ maxWidthClassName={constrainWidth ? LIST_PAGE_VIEW_FRAME_MAX_ICON_GRID : undefined}
58
+ className={cn(className)}
59
+ >
60
+ <div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-border py-16 text-sm text-muted-foreground">
61
+ <i className="fa-solid fa-grid-2 mb-3 text-3xl opacity-40" aria-hidden="true" />
62
+ {emptyContent ?? <p>No records found.</p>}
63
+ </div>
64
+ </ListPageViewFrame>
65
+ )
66
+ }
67
+
68
+ return (
69
+ <ListPageViewFrame className={cn(className)}>
70
+ <div
71
+ className={cn(
72
+ "grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-8",
73
+ constrainWidth && "mx-auto max-w-6xl",
74
+ )}
75
+ role="list"
76
+ aria-label={ariaLabel}
77
+ >
78
+ {rows.map(row => (
79
+ <div key={getRowId(row)} role="listitem">
80
+ {renderTile(row)}
81
+ </div>
82
+ ))}
83
+ </div>
84
+ </ListPageViewFrame>
85
+ )
86
+ }
@@ -0,0 +1,498 @@
1
+ "use client"
2
+
3
+ /**
4
+ * `<HubTable<TRow>>` — single centralized table surface used by every list-page hub.
5
+ *
6
+ * Owns all the per-hub scaffolding that was previously duplicated in `placements-table.tsx`,
7
+ * `team-table.tsx`, `compliance-table.tsx`, `question-bank-table.tsx`, and `sites-table.tsx`:
8
+ *
9
+ * • `useTableState` setup tied to the centralized row dataset
10
+ * • `displayOptions` state + `patchDisplay`
11
+ * • `conditionalRules` state + add/remove/update handlers
12
+ * • `filterFields` derived from column `filter` defs
13
+ * • `fieldDefinitions` + `resolveColumnLabel` for the Properties drawer
14
+ * • `TablePropertiesDrawerButton` wiring with `currentView` + `supportedViewTypes`
15
+ * • `DataTable` for `view === "table"`; `ListPageConnectedViewBody` for every other view
16
+ * • Imperative `openPropertiesDrawer()` exposed via `handleRef`
17
+ *
18
+ * Each hub now only declares **what's actually different**: its column defs and a typed
19
+ * `renderers` map for the views it implements. The renderers receive `state`, `toolbar`,
20
+ * `toolbarShell`, `drawerToolbarProps`, `displayOptions`, and `patchDisplay` so they can
21
+ * either reuse the pre-composed toolbar (`toolbarShell(<MyView rows={state.rows} />)`) or
22
+ * build their own (e.g. dashboard view with extra layout-edit actions).
23
+ *
24
+ * **Single dataset rule:** rows flow through `useTableState`; `tableState.rows` is the
25
+ * filtered/sorted row bag every non-table renderer reads. There is **no** parallel mock
26
+ * array per view. See `.cursor/rules/exxat-centralized-list-dataset.mdc`.
27
+ */
28
+
29
+ import * as React from "react"
30
+ import { DataTable, DataTableToolbar } from "../data-table"
31
+ import type { ColumnDef } from "../data-table/types"
32
+ import { useTableState } from "../data-table/use-table-state"
33
+ import type { DataListViewType } from "../../lib/data-list-view"
34
+ import {
35
+ getDataListViewRenderKind,
36
+ type DataListViewRenderKind,
37
+ } from "../../lib/data-list-view-registry"
38
+ import {
39
+ DEFAULT_DATA_LIST_DISPLAY_OPTIONS,
40
+ type DataListDisplayOptions,
41
+ } from "../../lib/data-list-display-options"
42
+ import { TablePropertiesDrawerButton } from "../table-properties"
43
+ import type {
44
+ ConditionalRule,
45
+ FilterFieldDef,
46
+ FilterOperator,
47
+ } from "../../lib/table-properties-types"
48
+ import {
49
+ ListPageConnectedViewBody,
50
+ type ListPageConnectedViewRenderers,
51
+ } from "./list-page-connected-view-body"
52
+ import { DataRowList } from "./data-row-list"
53
+ import {
54
+ ListPageBoardTemplate,
55
+ type ListPageBoardColumnDef,
56
+ } from "./list-page-board-template"
57
+ import type { OpenTablePropertiesHandle } from "../../lib/list-page-table-properties"
58
+
59
+ // ──────────────────────────────────────────────────────────────────────────────
60
+ // Helpers
61
+ // ──────────────────────────────────────────────────────────────────────────────
62
+
63
+ function columnToFilterFieldDef<TRow>(c: ColumnDef<TRow>): FilterFieldDef | null {
64
+ if (!c.filter) return null
65
+ const f = c.filter
66
+ const defaultOps: FilterOperator[] =
67
+ f.type === "select" || f.type === "date" ? ["is", "is_not"] : ["contains", "not_contains"]
68
+ return {
69
+ key: c.key,
70
+ label: c.label,
71
+ icon: f.icon ?? "fa-filter",
72
+ type: f.type,
73
+ operators: (f.operators ?? defaultOps) as FilterOperator[],
74
+ options: f.options,
75
+ ...(f.textMask ? { textMask: f.textMask } : {}),
76
+ }
77
+ }
78
+
79
+ /** Derive `FilterFieldDef[]` from a hub's column defs — preferred to hand-writing both. */
80
+ export function columnsToFilterFields<TRow>(cols: ColumnDef<TRow>[]): FilterFieldDef[] {
81
+ return cols
82
+ .map(c => columnToFilterFieldDef<TRow>(c))
83
+ .filter((x): x is FilterFieldDef => x !== null)
84
+ }
85
+
86
+ /** Field definitions for the drawer's Sort / Group / Columns panels — excludes utility columns. */
87
+ export function columnsToFieldDefinitions<TRow>(
88
+ cols: ColumnDef<TRow>[],
89
+ ): { key: string; label: string; sortable: boolean }[] {
90
+ return cols
91
+ .filter(c => c.key !== "select" && c.key !== "actions")
92
+ .map(c => ({
93
+ key: c.key,
94
+ label: c.label,
95
+ sortable: !!(c.sortable && (c.sortKey ?? c.key)),
96
+ }))
97
+ }
98
+
99
+ // ──────────────────────────────────────────────────────────────────────────────
100
+ // Public types
101
+ // ──────────────────────────────────────────────────────────────────────────────
102
+
103
+ /** Subset of `TablePropertiesDrawerButton` props that `HubTable` owns. Exposed so renderers
104
+ * that build a custom toolbar (e.g. dashboard with an extra Edit-layout button) can splat
105
+ * this back into their own `<TablePropertiesDrawerButton {...drawerToolbarProps} state={s} extraActions={…} />`. */
106
+ export interface HubDrawerToolbarProps {
107
+ totalRows: number
108
+ filterFields: FilterFieldDef[]
109
+ fieldDefinitions: { key: string; label: string; sortable: boolean }[]
110
+ resolveColumnLabel: (key: string) => string
111
+ displayOptions: DataListDisplayOptions
112
+ onDisplayOptionsChange: (patch: Partial<DataListDisplayOptions>) => void
113
+ conditionalRules: ConditionalRule[]
114
+ onAddConditionalRule: (rule: Omit<ConditionalRule, "id">) => void
115
+ onRemoveConditionalRule: (id: string) => void
116
+ onUpdateConditionalRule: (id: string, patch: Partial<ConditionalRule>) => void
117
+ currentView: DataListViewType
118
+ onViewChange?: (v: DataListViewType) => void
119
+ supportedViewTypes: readonly DataListViewType[]
120
+ lifecycleTabLabel: string
121
+ boardGroupByColumnOptions?: { key: string; label: string }[]
122
+ renderFilterOptionValue?: (fieldKey: string, value: string) => React.ReactNode
123
+ pagination?: boolean
124
+ onPaginationChange?: (v: boolean) => void
125
+ }
126
+
127
+ /** Everything a non-table renderer needs. The pre-composed `toolbar` includes search +
128
+ * filter chips + the Properties button; the renderer just wraps it around its body with
129
+ * `toolbarShell`. For dashboards or other layouts that own their own toolbar, use
130
+ * `drawerToolbarProps` to assemble a custom `<TablePropertiesDrawerButton>`. */
131
+ export interface HubTableRendererArgs<TRow extends Record<string, unknown>> {
132
+ state: ReturnType<typeof useTableState<TRow>>
133
+ toolbar: React.ReactNode
134
+ toolbarShell: (body: React.ReactNode) => React.ReactNode
135
+ drawerToolbarProps: HubDrawerToolbarProps
136
+ displayOptions: DataListDisplayOptions
137
+ patchDisplay: (patch: Partial<DataListDisplayOptions>) => void
138
+ }
139
+
140
+ /** Hubs provide one renderer per `DataListViewRenderKind` they implement. The `data-table`
141
+ * kind is handled internally by `HubTable` (do not override unless you genuinely need a
142
+ * different table surface). Missing kinds render `<ListPageViewNotConfigured>` — clear empty
143
+ * state, never a silent dashboard fallback. */
144
+ export type HubTableRenderers<TRow extends Record<string, unknown>> = Partial<
145
+ Record<DataListViewRenderKind, (args: HubTableRendererArgs<TRow>) => React.ReactNode>
146
+ >
147
+
148
+ export type HubTableHandle = OpenTablePropertiesHandle
149
+
150
+ export interface HubTableProps<TRow extends Record<string, unknown>> {
151
+ /** Full row dataset (already scoped/filtered by the hub client, e.g. by URL nav). */
152
+ rows: TRow[]
153
+ /** Column defs — `filter` blocks here become Properties drawer filter fields automatically. */
154
+ columns: ColumnDef<TRow>[]
155
+ /** Active view from the `ListPageTemplate` tab. */
156
+ view: DataListViewType
157
+ onViewChange?: (v: DataListViewType) => void
158
+ /** Allowlist passed to `TablePropertiesDrawerButton` so Properties cannot offer unsupported views. */
159
+ supportedViewTypes: readonly DataListViewType[]
160
+ /** Used by `ListPageViewNotConfigured` when a supported view has no renderer. */
161
+ hubLabel: string
162
+ /** Shown below "Properties" in the drawer header. */
163
+ lifecycleTabLabel: string
164
+ /** Toolbar search input aria-label. */
165
+ searchAriaLabel: string
166
+ getRowId: (row: TRow) => string | number
167
+ getRowSelectionLabel: (row: TRow) => string
168
+ defaultSort: { key: string; dir: "asc" | "desc" }
169
+ /** DataTable empty state. Defaults to a muted "No records match your filters." */
170
+ emptyState?: React.ReactNode
171
+ /** Per-view renderers (everything other than `view === "table"`). */
172
+ renderers: HubTableRenderers<TRow>
173
+ /** Bulk-actions slot rendered when one or more rows are selected. */
174
+ bulkActionsSlot?: (selected: Set<string | number>) => React.ReactNode
175
+ /** Board-view group-by column options for the Properties drawer. */
176
+ boardGroupByColumnOptions?: { key: string; label: string }[]
177
+ /** Initial display options (toolbar search visibility, calendar panel, etc.). */
178
+ displayOptionsInit?: DataListDisplayOptions
179
+ /** Custom renderer for filter option values (e.g. status chips). */
180
+ renderFilterOptionValue?: (fieldKey: string, value: string) => React.ReactNode
181
+ /** DataTable: enable "Group by" feature. Default `true`. */
182
+ groupable?: boolean
183
+ /** DataTable: enable row selection checkboxes. Default `true`. */
184
+ selectable?: boolean
185
+ /** DataTable: row click handler (e.g. navigate to detail route). */
186
+ onRowClick?: (row: TRow) => void
187
+ /**
188
+ * Controlled `displayOptions` — when provided (with `onDisplayOptionsChange`), the hub client
189
+ * owns persistence (e.g. Placements page persists across tab switches). Otherwise `HubTable`
190
+ * owns internal state from `displayOptionsInit`.
191
+ */
192
+ displayOptions?: DataListDisplayOptions
193
+ onDisplayOptionsChange?: (patch: Partial<DataListDisplayOptions>) => void
194
+ /**
195
+ * Pagination toggle forwarded to `TablePropertiesDrawerButton` so the drawer can offer
196
+ * "Show pagination" on the Display panel. The hub still implements its own pagination chrome
197
+ * around the table body via `tableRenderer`. Defaults to `false` / no toggle.
198
+ */
199
+ pagination?: boolean
200
+ onPaginationChange?: (v: boolean) => void
201
+ /** Imperative handle (`openPropertiesDrawer`) for hub clients that pass `tablePropertiesRef`. */
202
+ handleRef?: React.Ref<HubTableHandle>
203
+ /** Optional override for the `data-table` view. Default mounts `<DataTable {…}>`. */
204
+ tableRenderer?: (args: HubTableRendererArgs<TRow>) => React.ReactNode
205
+ /**
206
+ * Forwarded to `useTableState` so the hub can switch on server-style pagination
207
+ * (e.g. Placements toggles between paged and unpaged tables).
208
+ */
209
+ paginationOverride?: { page: number; pageSize: number }
210
+ /**
211
+ * Forwarded to `useTableState` to sync toolbar search from `?q=` (Question bank search routes).
212
+ * Defining as `""` enables sync without an initial query.
213
+ */
214
+ syncedSearchFromUrl?: string
215
+
216
+ // ─── Centralized "list" and "board" defaults ───────────────────────────────
217
+ // When a hub does NOT provide a renderer for `list-with-toolbar`, but DOES provide
218
+ // `renderListRow`, `HubTable` synthesises a default that wires `DataRowList` through
219
+ // the shared toolbar. Same for `board-with-toolbar` + `renderBoardCard`. This is the
220
+ // happy path for most hubs; the explicit renderer escape hatch is only needed for
221
+ // exotic surfaces (e.g. Placements board with per-phase column search).
222
+
223
+ /** Default `list-with-toolbar` renderer body — `HubTable` wraps with toolbar + `DataRowList`. */
224
+ renderListRow?: (row: TRow) => React.ReactNode
225
+ /** Override the `aria-label` on the `<ul>` from `renderListRow`. Defaults to `hubLabel`. */
226
+ listAriaLabel?: string
227
+ /** Empty-state for the default list renderer. Defaults to "No records match your filters." */
228
+ listEmptyState?: React.ReactNode
229
+ /** Virtualise after N rows in the default list renderer. Default 100; pass `0` to disable. */
230
+ listVirtualizeThreshold?: number
231
+ /** Estimated row height (px) for the default list virtualiser. Default 96. */
232
+ listEstimatedRowHeight?: number
233
+
234
+ /** Default `board-with-toolbar` renderer body — `HubTable` wraps with toolbar + `ListPageBoardTemplate`. */
235
+ renderBoardCard?: (row: TRow) => React.ReactNode
236
+ /** Required if `renderBoardCard` is set: how rows group into columns. */
237
+ boardGroups?: ListPageBoardColumnDef<TRow>[]
238
+ /** Per-column count badge tint classes for the default board renderer. */
239
+ boardColumnCountBadgeClassName?: Record<string, string>
240
+ /** Empty column copy for the default board renderer. Defaults to "No items". */
241
+ boardEmptyColumnLabel?: string
242
+ }
243
+
244
+ // ──────────────────────────────────────────────────────────────────────────────
245
+ // Component
246
+ // ──────────────────────────────────────────────────────────────────────────────
247
+
248
+ export function HubTable<TRow extends Record<string, unknown>>({
249
+ rows,
250
+ columns,
251
+ view,
252
+ onViewChange,
253
+ supportedViewTypes,
254
+ hubLabel,
255
+ lifecycleTabLabel,
256
+ searchAriaLabel,
257
+ getRowId,
258
+ getRowSelectionLabel,
259
+ defaultSort,
260
+ emptyState,
261
+ renderers,
262
+ bulkActionsSlot,
263
+ boardGroupByColumnOptions,
264
+ displayOptionsInit,
265
+ renderFilterOptionValue,
266
+ groupable = true,
267
+ selectable = true,
268
+ onRowClick,
269
+ displayOptions: displayOptionsControlled,
270
+ onDisplayOptionsChange: onDisplayOptionsChangeControlled,
271
+ pagination,
272
+ onPaginationChange,
273
+ handleRef,
274
+ tableRenderer,
275
+ paginationOverride,
276
+ syncedSearchFromUrl,
277
+ renderListRow,
278
+ listAriaLabel,
279
+ listEmptyState,
280
+ listVirtualizeThreshold,
281
+ listEstimatedRowHeight,
282
+ renderBoardCard,
283
+ boardGroups,
284
+ boardColumnCountBadgeClassName,
285
+ boardEmptyColumnLabel,
286
+ }: HubTableProps<TRow>) {
287
+ const filterFields = React.useMemo(() => columnsToFilterFields(columns), [columns])
288
+ const fieldDefinitions = React.useMemo(() => columnsToFieldDefinitions(columns), [columns])
289
+ const resolveColumnLabel = React.useCallback(
290
+ (key: string) => columns.find(c => c.key === key)?.label ?? key,
291
+ [columns],
292
+ )
293
+
294
+ // displayOptions: controlled (parent owns state via prop pair) OR uncontrolled (HubTable owns it).
295
+ // Most hubs keep display options ephemeral; Placements persists them across tabs at the page level.
296
+ const [internalDisplayOptions, setInternalDisplayOptions] = React.useState<DataListDisplayOptions>(
297
+ displayOptionsInit ?? DEFAULT_DATA_LIST_DISPLAY_OPTIONS,
298
+ )
299
+ const isControlled =
300
+ displayOptionsControlled !== undefined && onDisplayOptionsChangeControlled !== undefined
301
+ const displayOptions = isControlled ? displayOptionsControlled : internalDisplayOptions
302
+ const patchDisplay = React.useCallback(
303
+ (patch: Partial<DataListDisplayOptions>) => {
304
+ if (isControlled) {
305
+ onDisplayOptionsChangeControlled!(patch)
306
+ } else {
307
+ setInternalDisplayOptions(prev => ({ ...prev, ...patch }))
308
+ }
309
+ },
310
+ [isControlled, onDisplayOptionsChangeControlled],
311
+ )
312
+
313
+ const [conditionalRules, setConditionalRules] = React.useState<ConditionalRule[]>([])
314
+ const addConditionalRule = React.useCallback((rule: Omit<ConditionalRule, "id">) => {
315
+ setConditionalRules(prev => [...prev, { ...rule, id: `cr-${Date.now()}` }])
316
+ }, [])
317
+ const removeConditionalRule = React.useCallback((id: string) => {
318
+ setConditionalRules(prev => prev.filter(r => r.id !== id))
319
+ }, [])
320
+ const updateConditionalRule = React.useCallback(
321
+ (id: string, patch: Partial<ConditionalRule>) => {
322
+ setConditionalRules(prev => prev.map(r => (r.id === id ? { ...r, ...patch } : r)))
323
+ },
324
+ [],
325
+ )
326
+
327
+ const tableState = useTableState<TRow>(
328
+ rows,
329
+ columns,
330
+ defaultSort,
331
+ paginationOverride,
332
+ syncedSearchFromUrl,
333
+ )
334
+
335
+ // Extract the stable setter from `useTableState` first so the
336
+ // `useImperativeHandle` deps array sees the exact value the hook reads.
337
+ // `setSheetOpen` is referentially stable, so the handle is created once.
338
+ const { setSheetOpen: openPropertiesSheet } = tableState
339
+ React.useImperativeHandle(
340
+ handleRef ?? null,
341
+ () => ({ openPropertiesDrawer: () => openPropertiesSheet(true) }),
342
+ [openPropertiesSheet],
343
+ )
344
+
345
+ const drawerToolbarProps: HubDrawerToolbarProps = {
346
+ totalRows: rows.length,
347
+ filterFields,
348
+ fieldDefinitions,
349
+ resolveColumnLabel,
350
+ displayOptions,
351
+ onDisplayOptionsChange: patchDisplay,
352
+ conditionalRules,
353
+ onAddConditionalRule: addConditionalRule,
354
+ onRemoveConditionalRule: removeConditionalRule,
355
+ onUpdateConditionalRule: updateConditionalRule,
356
+ currentView: view,
357
+ onViewChange,
358
+ supportedViewTypes,
359
+ lifecycleTabLabel,
360
+ boardGroupByColumnOptions,
361
+ renderFilterOptionValue,
362
+ ...(pagination !== undefined ? { pagination } : {}),
363
+ ...(onPaginationChange !== undefined ? { onPaginationChange } : {}),
364
+ }
365
+
366
+ const toolbar = (
367
+ <DataTableToolbar
368
+ state={tableState}
369
+ columns={columns}
370
+ searchable={displayOptions.showToolbarSearch}
371
+ searchAriaLabel={searchAriaLabel}
372
+ renderFilterOptionValue={renderFilterOptionValue}
373
+ toolbarSlot={s => <TablePropertiesDrawerButton {...drawerToolbarProps} state={s} />}
374
+ />
375
+ )
376
+
377
+ const toolbarShell = React.useCallback(
378
+ (body: React.ReactNode) => (
379
+ <div className="flex min-h-0 flex-1 flex-col">
380
+ {toolbar}
381
+ {body}
382
+ </div>
383
+ ),
384
+ // `toolbar` is recreated each render; including it would defeat memoization but
385
+ // also gives renderers a fresh closure — acceptable because renderers are called
386
+ // on render anyway. Keep deps stable so the function identity is stable.
387
+ // eslint-disable-next-line react-hooks/exhaustive-deps
388
+ [
389
+ tableState,
390
+ columns,
391
+ displayOptions.showToolbarSearch,
392
+ searchAriaLabel,
393
+ renderFilterOptionValue,
394
+ drawerToolbarProps,
395
+ ],
396
+ )
397
+
398
+ // Default `data-table` renderer — full DataTable with toolbar + bulk actions. Hubs can
399
+ // override via `tableRenderer` for pagination chrome (CountSyncer + PaginationBar) or
400
+ // any other table-view-specific wrapping.
401
+ const defaultTableRenderer = (args: HubTableRendererArgs<TRow>) => (
402
+ <div className="pb-6">
403
+ <DataTable<TRow>
404
+ data={rows}
405
+ columns={columns}
406
+ getRowId={getRowId}
407
+ getRowSelectionLabel={getRowSelectionLabel}
408
+ selectable={selectable}
409
+ searchable={displayOptions.showToolbarSearch}
410
+ showColumnHeaders={displayOptions.showColumnLabels}
411
+ groupable={groupable}
412
+ defaultSort={defaultSort}
413
+ emptyState={emptyState ?? <p className="text-sm text-muted-foreground">No records match your filters.</p>}
414
+ conditionalRules={conditionalRules}
415
+ state={args.state}
416
+ renderFilterOptionValue={renderFilterOptionValue}
417
+ toolbarSlot={s => <TablePropertiesDrawerButton {...drawerToolbarProps} state={s} />}
418
+ bulkActionsSlot={bulkActionsSlot}
419
+ onRowClick={onRowClick}
420
+ />
421
+ </div>
422
+ )
423
+
424
+ const args: HubTableRendererArgs<TRow> = {
425
+ state: tableState,
426
+ toolbar,
427
+ toolbarShell,
428
+ drawerToolbarProps,
429
+ displayOptions,
430
+ patchDisplay,
431
+ }
432
+
433
+ // Dev-time warning when a `supportedViewType` has no renderer (other than `table`,
434
+ // which has the built-in default). Mirrors `defineHubViewRenderers` from
435
+ // `lib/hub-connected-view-renderers.ts` but inline so we don't double-wrap.
436
+ if (process.env.NODE_ENV !== "production") {
437
+ for (const v of supportedViewTypes) {
438
+ const kind = getDataListViewRenderKind(v)
439
+ if (kind === "data-table") continue
440
+ if (renderers[kind] == null) {
441
+ console.warn(
442
+ `[Exxat DS][HubTable: ${hubLabel}] Missing renderer for supported view "${v}" (${kind}). ` +
443
+ "Add a renderer entry, or remove the view from supportedViewTypes.",
444
+ )
445
+ }
446
+ }
447
+ }
448
+
449
+ // Compose `ListPageConnectedViewBody` renderers: the built-in `data-table` (or hub override)
450
+ // plus each hub-provided non-table renderer. Wrapping in `() => …` defers execution until
451
+ // the active view actually selects that kind — so heavy bodies (dashboard charts) don't
452
+ // pay render cost on a table tab.
453
+ const composed: ListPageConnectedViewRenderers = {
454
+ "data-table": () => (tableRenderer ?? defaultTableRenderer)(args),
455
+ }
456
+
457
+ // Default centralized list renderer: same DataRowList shell every hub used to roll
458
+ // by hand. Hub provides only the per-row body via `renderListRow`.
459
+ if (renderers["list-with-toolbar"] == null && renderListRow != null) {
460
+ composed["list-with-toolbar"] = () =>
461
+ args.toolbarShell(
462
+ <DataRowList<TRow>
463
+ rows={args.state.rows as TRow[]}
464
+ getRowId={row => getRowId(row)}
465
+ ariaLabel={listAriaLabel ?? hubLabel}
466
+ emptyState={listEmptyState ?? "No records match your filters."}
467
+ {...(listVirtualizeThreshold !== undefined ? { virtualizeThreshold: listVirtualizeThreshold } : {})}
468
+ {...(listEstimatedRowHeight !== undefined ? { estimatedRowHeight: listEstimatedRowHeight } : {})}
469
+ renderRow={renderListRow}
470
+ />,
471
+ )
472
+ }
473
+
474
+ // Default centralized board renderer: same ListPageBoardTemplate every hub used to wrap.
475
+ // Hub provides only the per-card body via `renderBoardCard` and the column predicate set.
476
+ if (renderers["board-with-toolbar"] == null && renderBoardCard != null && boardGroups != null) {
477
+ composed["board-with-toolbar"] = () =>
478
+ args.toolbarShell(
479
+ <ListPageBoardTemplate<TRow>
480
+ columns={boardGroups}
481
+ rows={args.state.rows as TRow[]}
482
+ getRowKey={getRowId}
483
+ renderCard={renderBoardCard}
484
+ columnCountBadgeClassName={boardColumnCountBadgeClassName ?? {}}
485
+ emptyColumnLabel={boardEmptyColumnLabel ?? "No items"}
486
+ />,
487
+ )
488
+ }
489
+
490
+ for (const kind of Object.keys(renderers) as DataListViewRenderKind[]) {
491
+ const r = renderers[kind]
492
+ if (r) composed[kind] = () => r(args)
493
+ }
494
+
495
+ return <ListPageConnectedViewBody view={view} hubLabel={hubLabel} renderers={composed} />
496
+ }
497
+
498
+ HubTable.displayName = "HubTable"
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Data-views — view-body primitives for list-page hubs.
3
+ *
4
+ * Composes `DataTable`, `useTableState`, `TablePropertiesDrawerButton`, the
5
+ * `DataListViewType` registry, and the various non-table view bodies
6
+ * (DataRowList, ListPageBoardTemplate, ListPageBoardCard, split-view
7
+ * shells) into a single import surface.
8
+ *
9
+ * `HubTable<TRow>` is the binding layer: pass it columns, rows, and a
10
+ * `renderers` map of view-render-kinds and it produces a complete
11
+ * list-page hub body for every supported view tab.
12
+ */
13
+
14
+ export * from "./hub-table"
15
+ export * from "./data-row-list"
16
+ export * from "./list-page-connected-view-body"
17
+ export * from "./list-page-board-template"
18
+ export * from "./list-page-board-card"
19
+ export * from "./board-card-primitives"
20
+ export * from "./list-page-tree-column-header"
21
+ export * from "./list-page-split-details-placeholder"
22
+ export * from "./list-page-split-hub-chrome"
23
+ export * from "./list-page-split-hub-tokens"
24
+ export * from "./list-page-tree-panel-shell"
25
+ export * from "./finder-panel-view"
26
+ export * from "./folder-grid-view"
27
+ export * from "./outline-tree-menu"
28
+ export * from "./os-folder-glyph"