@exxatdesignux/ui 0.2.19 → 0.4.0

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