@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
@@ -2,7 +2,9 @@
2
2
 
3
3
  **Purpose:** One place for product patterns so tools (Cursor, Codex, etc.) and contributors apply the same rules. **Imperative sections** use MUST / MUST NOT / SHOULD so they are easy to parse.
4
4
 
5
- **Scope:** The Next.js app in this directory. **Path:** If your workspace root is only this folder, use **`./AGENTS.md`**. If the workspace is the parent repo, use **`exxat-ds/AGENTS.md`**.
5
+ **Scope:** The Next.js app in this directory. **Path:** If your workspace root is only this folder, use **`./AGENTS.md`**. If the workspace is the parent monorepo, use **`apps/web/AGENTS.md`** (this file).
6
+
7
+ > **First-time reader?** Open **`docs/HANDBOOK.md`** first — it's a 10-minute orientation that links into the right section here. This file is the **authoritative §-numbered manual**; the handbook is the map. Other quick entry points: **`docs/glossary.md`** (shared vocabulary), **`docs/voice-and-tone.md`** (copy rules), **`docs/reference-implementations.md`** (canonical reference pages).
6
8
 
7
9
  Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tables, keyboard hints, accessibility) when the parent repo is open.
8
10
 
@@ -14,31 +16,32 @@ Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tab
14
16
  2. **Before** changing **keyboard hints or shortcuts**, read **§7** and root `.cursor/rules/exxat-kbd-shortcuts.mdc`.
15
17
  3. **Before** changing **table behavior**, read **§3** and root `.cursor/rules/exxat-data-tables.mdc`. **Before** wiring **`TablePropertiesDrawer`** on **`ListPageTemplate`** (view tabs), read **§4.2** and **`.cursor/rules/exxat-table-properties-drawer.mdc`**.
16
18
  4. **Before** building or changing **tabs, nav, dialogs, icon-only controls, or color/contrast**, read **§8** and **`.cursor/skills/exxat-accessibility/SKILL.md`** (from monorepo root when the parent repo is open).
17
- 5. **Before** adding or changing **Data view charts** (dashboard tab on list hubs) or **graph keyboard styling**, read **§4.3** and **`exxat-ds/.cursor/rules/exxat-dashboard-view-charts.mdc`**.
19
+ 5. **Before** adding or changing **Data view charts** (dashboard tab on list hubs) or **graph keyboard styling**, read **§4.3** and **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`**.
18
20
  6. **Before** adding or changing **board (kanban) cards** on list hubs, read **§4.4** and the **`exxat-board-cards`** skill (**`.cursor/skills/`** or **`.claude/skills/`** at repo root — same content).
19
21
  7. **Before** adding **folder, panel, or other non-table view bodies** (centered grids, reusable shells), read **§4.5** and **`.cursor/rules/exxat-list-page-view-shells.mdc`** / **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`**.
20
22
  8. **Before** adding or changing **Font Awesome** icons in app UI, read **`.cursor/rules/exxat-fontawesome-icons.mdc`** (Kit subsetting, weights, **`aria-hidden`** on **`<i>`**).
21
23
  9. **Before** rendering **record IDs, question IDs, or other system identifiers**, read **`.cursor/rules/exxat-mono-ids.mdc`** and **`.cursor/skills/exxat-mono-ids/SKILL.md`** (**`font-mono tabular-nums`**).
22
- 10. **Before** adding a **primary nav row** that opens a **nested secondary nav panel** (Question bank style), read **§4.6** and **`.cursor/rules/exxat-primary-nav-secondary-panel.mdc`**.
24
+ 10. **Before** adding a **primary nav row** that opens a **nested secondary nav panel** (Library style), read **§4.6** and **`.cursor/rules/exxat-primary-nav-secondary-panel.mdc`**.
23
25
  11. **Before** adding **shared access / invite collaborators** on a hub (face stack + invite sheet), read **§4.7** and **`.cursor/rules/exxat-collaboration-access.mdc`** / **`.cursor/skills/exxat-collaboration-access/SKILL.md`**.
24
26
  12. **Before** adding **onboarding tours, feature walkthroughs, or coach marks**, read **§11** and `references/coach-marks.md`.
25
27
  13. **Before** changing the **global command palette (⌘K)** or search/AI entry UX, read **§7.1** and **`docs/command-menu-pattern.md`**.
26
28
  14. **Before** choosing **drawer vs dialog vs new page** for a task flow, read **§6.4**, **`docs/data-views-pattern.md`** (Page vs drawer), and **`docs/drawer-vs-dialog-pattern.md`** (modal vs side panel on the same route).
27
- 15. **Before** adding or changing a **dedicated form, wizard, or sectioned settings route**, read **`docs/focused-workflow-page-pattern.md`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**, **`.cursor/skills/exxat-focused-workflow-page/SKILL.md`**, and run **§14** checklist.
28
- 16. **Before** adding **success/error/confirmation feedback**, read **§6.5** and **`.cursor/rules/exxat-no-toast.mdc`** (no toast or snackbars).
29
- 17. Prefer **composing existing components** over new one-off UI. If something is missing, **extend** shared components under `components/`, not a single page file.
29
+ 15. **Before** adding **success/error/confirmation feedback**, read **§6.5** and **`.cursor/rules/exxat-no-toast.mdc`** (no toast or snackbars).
30
+ 16. Prefer **composing existing components** over new one-off UI. If something is missing, **extend** shared components under `components/`, not a single page file.
30
31
  - **MUST** scan `components/` (especially `components/ui/`, `components/data-views/`, `components/templates/`, `components/key-metrics.tsx`, `components/page-header.tsx`, and the charts/banner/dot-pattern surfaces) **before** writing any new UI. If a primitive or composition already exists, **use it** — don't build a parallel one.
31
- - **Examples of existing surfaces to reuse:** card grid → `ListPageBoardCard` + `BoardCardIconRow` / `BoardCardTwoLineBlock`; AI / dot animation → `AiThinkingOverlay` + `DotPattern`; search input → `InputGroup` + `InputGroupAddon` + `InputGroupInput`; page title → `PageHeader` (serif via `font-heading`); list hub shell → `ListPageTemplate` (`metrics`, `defaultTabs`, `renderContent`); **dedicated form / wizard / settings route** → **`FocusedWorkflowPageTemplate`** + **`focused-workflow-layouts.tsx`** (**§14**); metrics strip → `KeyMetrics`; **view body gutter + centered max-width** → **`ListPageViewFrame`** (**§4.5**); **shared access / invite** → **`PageHeader` `variant="collaboration"`** + **`InviteCollaboratorsDrawer`** (**§4.7**).
32
+ - **Examples of existing surfaces to reuse:** card grid → `ListPageBoardCard` + `BoardCardIconRow` / `BoardCardTwoLineBlock`; AI / dot animation → `AiThinkingOverlay` + `DotPattern`; search input → `InputGroup` + `InputGroupAddon` + `InputGroupInput`; page title → `PageHeader` (serif via `font-heading`); list hub shell → `ListPageTemplate` (`metrics`, `defaultTabs`, `renderContent`); metrics strip → `KeyMetrics`; **view body gutter + centered max-width** → **`ListPageViewFrame`** (**§4.5**); **shared access / invite** → **`PageHeader` `variant="collaboration"`** + **`InviteCollaboratorsDrawer`** (**§4.7**).
32
33
  - **If** nothing fits and you would add a **new shared primitive or large bespoke widget**: **ask the user** for direction first — **`.cursor/rules/exxat-reuse-before-custom.mdc`** (unless the task already explicitly approved a greenfield build).
33
- 18. **Match** naming, imports, and patterns of the nearest reference implementation (usually Placements).
34
- 19. **Before** adding entity **mock data**, a **new view tab**, or **detail/inspector** panels on a list hub, read **`.cursor/rules/exxat-centralized-list-dataset.mdc`** and **`.cursor/skills/exxat-centralized-list-dataset/SKILL.md`** (single **`useTableState`** row bag for every view; **no** parallel mock arrays per view).
35
- 20. **Before** choosing **cards vs table rows vs simple lists** for a hub, read **`docs/card-vs-rows-pattern.md`** and **`.cursor/rules/exxat-card-vs-list-rows.mdc`**.
36
- 21. **Before** adding **`KeyMetrics`** strips on list hubs or dashboard key-metrics cards, read **`docs/kpi-strip-max-four-pattern.md`** and **`.cursor/rules/exxat-kpi-max-four.mdc`** (at most **four** tiles).
37
- 22. **Before** styling **`KeyMetrics variant="flat"`** (list hub metrics strip, dashboard mix KPI band), read **`docs/kpi-flat-band-pattern.md`** and **`.cursor/rules/exxat-kpi-flat-band.mdc`** / **`.cursor/skills/exxat-kpi-flat-band/SKILL.md`** (transparent band, OKLCH glow, border hairlines only).
38
- 23. **Before** changing **secondary panel** or **sidebar** brand chrome, read **`docs/shell-surface-elevation-pattern.md`** and **§4.6** ( **`--secondary-panel-bg`**, active product theme).
39
- 24. **Before** adding **new shared UI primitives** or bespoke widgets when nothing in **`components/`** fits after scanning, follow **`.cursor/rules/exxat-reuse-before-custom.mdc`** — **ask the user** for direction unless the task already approved a greenfield build.
40
-
41
- **Longer narrative and architecture:** `docs/data-views-pattern.md`, `docs/drawer-vs-dialog-pattern.md`, **`docs/focused-workflow-page-pattern.md`**, `docs/card-vs-rows-pattern.md`, `docs/kpi-strip-max-four-pattern.md`, **`docs/kpi-flat-band-pattern.md`**, **`docs/shell-surface-elevation-pattern.md`**, `docs/command-menu-pattern.md`, `docs/collaboration-access-pattern.md` (keep in sync with this handbook for big refactors).
34
+ 17. **Match** naming, imports, and patterns of the nearest reference implementation (usually Placements).
35
+ 18. **Before** adding entity **mock data**, a **new view tab**, or **detail/inspector** panels on a list hub, read **`.cursor/rules/exxat-centralized-list-dataset.mdc`** and **`.cursor/skills/exxat-centralized-list-dataset/SKILL.md`** (single **`useTableState`** row bag for every view; **no** parallel mock arrays per view).
36
+ 19. **Before** choosing **cards vs table rows vs simple lists** for a hub, read **`docs/card-vs-rows-pattern.md`** and **`.cursor/rules/exxat-card-vs-list-rows.mdc`**.
37
+ 20. **Before** adding **`KeyMetrics`** strips on list hubs or dashboard key-metrics cards, read **`docs/kpi-strip-max-four-pattern.md`** and **`.cursor/rules/exxat-kpi-max-four.mdc`** (at most **four** tiles).
38
+ 21. **Before** styling **`KeyMetrics variant="flat"`** (list hub metrics strip, dashboard mix KPI band), read **`docs/kpi-flat-band-pattern.md`** and **`.cursor/rules/exxat-kpi-flat-band.mdc`** / **`.cursor/skills/exxat-kpi-flat-band/SKILL.md`** (transparent band, OKLCH glow, border hairlines only).
39
+ 22. **Before** changing **secondary panel** or **sidebar** brand chrome, read **`docs/shell-surface-elevation-pattern.md`** and **§4.6** ( **`--secondary-panel-bg`**, active product theme).
40
+ 23. **Before** adding **new shared UI primitives** or bespoke widgets when nothing in **`components/`** fits after scanning, follow **`.cursor/rules/exxat-reuse-before-custom.mdc`** — **ask the user** for direction unless the task already approved a greenfield build.
41
+ 24. **Before** introducing a **color, spacing, radius, or shadow value** in JSX `className`, inline `style`, CSS, or a `cn()` / `clsx()` argument, read **`docs/token-taxonomy.md`** and **`.cursor/rules/exxat-token-discipline.mdc`**. **New code SHOULD reach for the L0 Exxat namespace first** (`var(--exxat-color-surface-1)`, `bg-surface-1`, `bg-brand-1`, `rounded-2`, …) — the older shadcn-style names (`--background`, `bg-brand`, `rounded-md`, …) remain as L1 aliases and continue to work. No hex literals in app code; check `packages/ui/tokens/hooks-index.json` for available tokens + deprecations (163 tokens · 36 namespaces). ESLint catches violations via `exxat-ds/no-hex-color` + `exxat-ds/no-deprecated-tokens` (plugin: **`@exxatdesignux/eslint-plugin`**).
42
+ 25. **Before** adopting any pattern from a **sibling Salesforce / SLDS / LWC** repo (e.g. `design-system-2-starter-kit`), read **`.cursor/rules/exxat-no-slds-leakage.mdc`**. **No** `slds-*` classes, **no** `<lightning-*>` markup, **no** synthetic-shadow assumptions, **no** SLDS token names (`--slds-g-color-*`). Document architectural ideas as Exxat blueprints (`docs/blueprints/`) instead of copying SLDS code.
43
+
44
+ **Longer narrative and architecture:** `docs/data-views-pattern.md`, `docs/drawer-vs-dialog-pattern.md`, `docs/card-vs-rows-pattern.md`, `docs/kpi-strip-max-four-pattern.md`, **`docs/kpi-flat-band-pattern.md`**, **`docs/shell-surface-elevation-pattern.md`**, `docs/command-menu-pattern.md`, `docs/collaboration-access-pattern.md` (keep in sync with this handbook for big refactors).
42
45
 
43
46
  ---
44
47
 
@@ -46,7 +49,7 @@ Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tab
46
49
 
47
50
  1. **User / task instructions** in the current session (highest).
48
51
  2. This **`AGENTS.md`** for Exxat DS product patterns.
49
- 3. **`.cursor/rules/*.mdc`** at repo root (`exxat-data-tables`, `exxat-list-page-connected-views`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-table-properties-drawer`, `exxat-board-cards`, `exxat-page-vs-drawer`, `exxat-drawer-vs-dialog`, `exxat-card-vs-list-rows`, `exxat-kpi-max-four`, `exxat-reuse-before-custom`, `exxat-no-toast`, `exxat-kbd-shortcuts`, `exxat-accessibility`, `exxat-fontawesome-icons`, **`exxat-mono-ids`**, `exxat-primary-nav-secondary-panel`, `exxat-collaboration-access`, `exxat-ds-agents`) and any rules under **`exxat-ds/.cursor/rules/`** (including **`exxat-dashboard-view-charts`** for Data view charts).
52
+ 3. **`.cursor/rules/*.mdc`** at repo root (`exxat-data-tables`, `exxat-list-page-connected-views`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-table-properties-drawer`, `exxat-board-cards`, `exxat-page-vs-drawer`, `exxat-drawer-vs-dialog`, `exxat-card-vs-list-rows`, `exxat-kpi-max-four`, `exxat-reuse-before-custom`, `exxat-no-toast`, `exxat-kbd-shortcuts`, `exxat-accessibility`, `exxat-fontawesome-icons`, **`exxat-mono-ids`**, `exxat-primary-nav-secondary-panel`, `exxat-collaboration-access`, `exxat-ds-agents`) and any rules under **`apps/web/.cursor/rules/`** (including **`exxat-dashboard-view-charts`** for Data view charts).
50
53
  4. Project **skills** under `.cursor/skills/` when relevant — e.g. **shadcn**, **exxat-accessibility** (WCAG / ARIA / touch / contrast), **exxat-board-cards** (kanban card shell, status badges, primitives), **exxat-list-page-view-shells** (centered view bodies, **`ListPageViewFrame`**), **exxat-centralized-list-dataset** (one **`useTableState`** row bag + shared maps across all list-hub views and **`TablePropertiesDrawer`**), **exxat-collaboration-access** (face rail + invite sheet + library access), **exxat-dedicated-search-surfaces** (landing vs results split, **`DedicatedSearch*`** templates + recents without hydration drift), **exxat-drawer-vs-dialog**, **exxat-card-vs-list-rows**, **exxat-kpi-max-four**, **`exxat-mono-ids`** (monospace system identifiers).
51
54
 
52
55
  If two documents conflict, prefer the **more specific** rule for the file type, then **newer** team decisions captured in `AGENTS.md`.
@@ -55,7 +58,7 @@ If two documents conflict, prefer the **more specific** rule for the file type,
55
58
 
56
59
  ## 3. Data tables (product lists)
57
60
 
58
- **MUST** for any screen that is a **browsable, filterable grid of records** (lists, directories, placements, team roster, etc.):
61
+ **MUST** for any screen that is a **browsable, filterable grid of records** (directories, tokens, library items, columns showcase, etc.):
59
62
 
60
63
  | Requirement | Action |
61
64
  |-------------|--------|
@@ -64,7 +67,9 @@ If two documents conflict, prefer the **more specific** rule for the file type,
64
67
  | Filters | Use the **shared filter model** (`FilterFieldDef`, operators, chips) consistent with existing list pages. |
65
68
  | Table properties | Expose **Table properties** via **`TablePropertiesDrawer`** (`@/components/table-properties`) — columns, density, related options — same pattern as Placements / data list. |
66
69
 
67
- **Reference:** `components/data-list-table.tsx`, `components/data-table/`.
70
+ **Reference:** `components/library-table.tsx`, `components/columns-showcase.tsx`, `components/data-table/`.
71
+
72
+ **Scaling past ~2K rows:** Turn on **`pagination={true}`** on **`HubTable`** and pick a page size; lists + boards already auto-virtualize at 100 rows. Beyond ~50K, lift filter / sort / page state via **`paginationOverride`** and fetch one page at a time — full upgrade path in **`docs/large-dataset-strategy.md`**.
68
73
 
69
74
  **MUST NOT:** Build product list pages with only `@/components/ui/table`, raw `<table>`, or a third-party grid that bypasses this stack.
70
75
 
@@ -76,7 +81,7 @@ If two documents conflict, prefer the **more specific** rule for the file type,
76
81
 
77
82
  **MUST:** If the main surface is a **`DataTable`** (or equivalent data grid), wrap it in **`ListPageTemplate`** so the **views toolbar** exists (tabs, add view, per-tab settings). Do **not** place `DataTable` only under `PageHeader` without the tab shell.
78
83
 
79
- **Reference implementations:** `components/list-hub-client.tsx` (List hub), `components/question-bank-client.tsx` (Question bank). Template mirror: `packages/ui/template/components/list-hub-*.tsx`, `question-bank-*.tsx`.
84
+ **Reference implementations:** `components/library-hub-client.tsx` (full hub), `components/columns-showcase.tsx` (single-view catalog), `components/tokens-themes-client.tsx` (hub + secondary panel).
80
85
 
81
86
  **Rationale:** Consistent navigation, saved views, per-tab view type (table / list / board / dashboard), export at template level.
82
87
 
@@ -86,7 +91,7 @@ If two documents conflict, prefer the **more specific** rule for the file type,
86
91
 
87
92
  **MUST NOT** ship a **new primary nav hub** as an **empty or placeholder-only page** (e.g. a paragraph saying “replace this later” with no **`DataTable`**, mock data, or connected views). When a route is linked from **`lib/mock/navigation.tsx`**, land users on the same **hub stack** as Team / Placements: **`ListPageTemplate`** + typed mock rows (typically **≥ ~12**), search, filters, **`TablePropertiesDrawer`**, and all view tabs the template supports (**§4.1**), unless the product explicitly scopes a route as a non-data shell (rare).
88
93
 
89
- **Mock data:** Put typed row arrays in **`lib/mock/<entity>.ts`**. Add **`lib/mock/<entity>-kpi.ts`** (or colocated helpers) with pure functions **`entityKpiMetrics(rows)`** / **`entityKpiInsight(rows)`** returning **`MetricItem[]`** / **`MetricInsight`** for **`KeyMetrics`**. Each **`MetricItem`** must set **`trend`** to match the signed change; use **`trendPolarity`** when an increase is **not** favorable (defects, review flags, overdue — see **`docs/kpi-trend-pattern.md`** and **`.cursor/rules/exxat-kpi-trends.mdc`**). **`entityKpiMetrics`** for **`ListPageTemplate`** metrics and Data-tab key-metrics cards: return **at most four** **`MetricItem`** — **`docs/kpi-strip-max-four-pattern.md`**, **`lib/dashboard-layout-merge.ts`** (`KEY_METRICS_KPI_COUNT_MAX`), **`.cursor/rules/exxat-kpi-max-four.mdc`**. The page client passes full mock rows into one table component; KPI helpers receive **`tableState.rows`** inside that component so search/filters apply to list, board, dashboard, and table together.
94
+ **Mock data:** Put typed row arrays in **`lib/mock/<entity>.ts`**. Add **`lib/mock/<entity>-kpi.ts`** (or colocated helpers) with pure functions **`entityKpiMetrics(rows)`** / **`entityKpiInsight(rows)`** returning **`MetricItem[]`** / **`MetricInsight`** for **`KeyMetrics`**. Each **`MetricItem`** must set **`trend`** to match the signed change; use **`trendPolarity`** when an increase is **not** favorable (defects, review flags, overdue — see **`docs/kpi-trend-pattern.md`** and **`.cursor/rules/exxat-kpi-trends.mdc`**). **`delta`** is the **count change** that renders next to the arrow (e.g. `"+5"`, `"-3"`); contextual prose like `"left + right"` / `"vs last week"` goes in **`MetricItem.description`** (caption below the value). When there is no direction *and* no count, leave **`delta: ""`** + **`trend: "neutral"`** — **`KeyMetrics`** hides the chip; **MUST NOT** hand-roll a `—` placeholder. **`entityKpiMetrics`** for **`ListPageTemplate`** metrics and Data-tab key-metrics cards: return **at most four** **`MetricItem`** — **`docs/kpi-strip-max-four-pattern.md`**, **`lib/dashboard-layout-merge.ts`** (`KEY_METRICS_KPI_COUNT_MAX`), **`.cursor/rules/exxat-kpi-max-four.mdc`**. The page client passes full mock rows into one table component; KPI helpers receive **`tableState.rows`** inside that component so search/filters apply to list, board, dashboard, and table together.
90
95
 
91
96
  **Centralized dataset (rows + table properties + alternate views):** **MUST** use one **`useTableState`** row bag for the **`DataTable`**, **`TablePropertiesDrawer`** (columns/density on **that** table), and **every** record-bearing **`DataListViewType`** — **folder**, **panel**, **tree**, etc. — via **`tableState.rows`**. **MUST NOT** import a second **`lib/mock/<entity>`** array into a view-only module while the grid filters state; **MUST NOT** fork a duplicate row type for inspectors. Shared **properties**: tab labels **`DATA_LIST_VIEW_TILES`** (`lib/data-list-view.ts`), status **`lib/list-status-badges.ts`**, KPI helpers from **`tableState.rows`**. **Presentation:** non-table bodies use **`ListPageViewFrame`** and **`components/data-views/`** primitives fed by the **same** **`tableState.rows`** (**§4.5**). **Rule + skill:** **`.cursor/rules/exxat-centralized-list-dataset.mdc`**, **`.cursor/skills/exxat-centralized-list-dataset/SKILL.md`**.
92
97
 
@@ -94,19 +99,6 @@ If two documents conflict, prefer the **more specific** rule for the file type,
94
99
 
95
100
  **Details:** `docs/data-views-pattern.md` (mock data, connected views, dashboard view).
96
101
 
97
- ### 4.1.1 View registry + `ListPageConnectedViewBody` (required for new hubs)
98
-
99
- **MUST** route view bodies through the shared registry — **MUST NOT** use `if (view === "board")` chains with a dashboard fallback.
100
-
101
- | Step | Action |
102
- |------|--------|
103
- | **Register** | Add the tile in **`lib/data-list-view.ts`**; capabilities derive in **`lib/data-list-view-registry.ts`** (`renderKind`, `showsListPageHubMetricsStrip`). |
104
- | **Declare hub** | **`lib/<hub>-supported-views.ts`** — pass the same array to **`ListPageTemplate`** (`supportedViewTypes`) and **`TablePropertiesDrawerButton`** (`supportedViewTypes`). |
105
- | **Render** | Hub **`*-table.tsx`** returns **`ListPageConnectedViewBody`** with **`defineHubViewRenderers(supportedViewTypes, { … })`** — one entry per **`DataListViewRenderKind`**; dev warns on gaps; missing kinds show **`ListPageViewNotConfigured`** (never silent dashboard). |
106
- | **Bodies** | Generic UI in **`components/data-views/`** (`ListPageCalendarView`, `ListPageBoardTemplate`, `ListPageFolderColumnsPanel`, `FolderGridView`, …); entity wiring in thin hub wrappers (e.g. **`QuestionBankFolderColumnsPanel`**). **MUST NOT** export QB-only tree branches from the generic **`data-views`** barrel. |
107
-
108
- **Golden references (this app):** `components/list-hub-table.tsx`, `components/question-bank-table.tsx`. **Template** (`packages/ui/template/`): same list-hub + question-bank stack — keep in sync when publishing **`@exxatdesignux/ui`**.
109
-
110
102
  ### 4.2 `TablePropertiesDrawer` and the active view
111
103
 
112
104
  **MUST:** Any page that uses **`ListPageTemplate`** with **`tab.viewType`** (table / list / board / dashboard) and renders **`TablePropertiesDrawer`** **MUST** pass:
@@ -115,11 +107,41 @@ If two documents conflict, prefer the **more specific** rule for the file type,
115
107
  |------|--------|
116
108
  | **`currentView`** | The same **`DataListViewType`** as the tab’s active view (e.g. **`view={tab.viewType}`** on the table component). |
117
109
  | **`onViewChange`** | From **`renderContent={(tab, updateTab) => ...}`**: **`(v) => updateTab({ viewType: v, icon: dataListViewIcon(v) })`** — import **`dataListViewIcon`** from **`@/lib/data-list-view`**. |
118
- | **`supportedViewTypes`** | Same **`lib/<hub>-supported-views.ts`** array as **`ListPageTemplate`** — limits Properties view tiles and **⌘1–9** Add-view shortcuts to views the hub implements. |
119
110
 
120
- Thread **`view`**, **`onViewChange`**, and **`supportedViewTypes`** from the **client** → **table / toolbar wrapper** → **`TablePropertiesDrawer`**. If **`currentView`** is omitted, the drawer defaults to **table** labels and controls even on **Board**, which is incorrect.
111
+ Thread **`view`** and **`onViewChange`** from the **client** → **table / toolbar wrapper** → **`TablePropertiesDrawer`**. If **`currentView`** is omitted, the drawer defaults to **table** labels and controls even on **Board**, which is incorrect.
112
+
113
+ **Reference:** `components/library-table.tsx`, `components/columns-showcase.tsx`, `components/tokens-themes-client.tsx`. Root **`.cursor/rules/exxat-table-properties-drawer.mdc`**.
114
+
115
+ #### Deep-linking the drawer to a specific panel
116
+
117
+ `TablePropertiesDrawer` accepts an optional **`initialPanel`** prop so callsites can open the drawer focused on a named panel — `"main"` (default), `"table-display"`, `"filter"`, `"sort"`, `"group"`, `"columns"`, or `"conditional-rules"`. The current built-in use is the **Add Conditional Rule** item in every column header menu, which deep-links to the **Conditional rules** panel.
118
+
119
+ **MUST**:
121
120
 
122
- **Reference:** `components/list-hub-table.tsx`, `components/question-bank-table.tsx`; template **`components/placements-table.tsx`**, **`team-table.tsx`**. Root **`.cursor/rules/exxat-table-properties-drawer.mdc`**.
121
+ 1. `useTableState` exposes **`sheetInitialPanel`** + **`setSheetInitialPanel`** alongside `sheetOpen` / `setSheetOpen`. Pass **`initialPanel={sheetInitialPanel}`** to `TablePropertiesDrawer` from the toolbar / button wrapper. Reference: `packages/ui/src/components/table-properties/drawer-button.tsx`.
122
+ 2. The toolbar **Properties** button MUST clear the deep-link before opening so a plain "open Properties" click always lands on the main index panel:
123
+
124
+ ```tsx
125
+ onClick={() => {
126
+ setSheetInitialPanel?.(null)
127
+ setSheetOpen(true)
128
+ }}
129
+ ```
130
+
131
+ 3. Deep-link callsites MUST set panel + open in **the same batched setState call** so the drawer mounts with the right panel in one render:
132
+
133
+ ```tsx
134
+ setSheetInitialPanel("conditional-rules")
135
+ setSheetOpen(true)
136
+ ```
137
+
138
+ 4. From inside a Radix `DropdownMenu`, queue the work into `onCloseAutoFocus` (see `columnMenuPendingActionRef` in `packages/ui/src/components/data-table/index.tsx`) — opening the non-modal Sheet synchronously from `onSelect` races with the menu close cycle.
139
+
140
+ **MUST NOT**: introduce a second source of truth for "which panel" — `sheetInitialPanel` is the only deep-link channel; the drawer's internal `sheetPanel` stays internal.
141
+
142
+ #### View-type tile grid
143
+
144
+ The drawer's "View type" tile grid (and the Export drawer's "File format" grid) renders through `SelectionTileGrid` with `interaction="button"` + `labelPlacement="inside"`. The shared `selectionTileClassNames` utility applies **`aspect-square`** + `leading-tight` so every tile is the same uniform square regardless of how many tiles populate the last row of the `grid-cols-N` track. **Prefer** the shared `SelectionTileGrid` (or `selectionTileClassNames` directly) instead of inventing flex/grid wrappers for tile-style pickers — that's the only way to keep the squares uniform across the system.
123
145
 
124
146
  ### 4.3 Data view dashboard — charts, customisation, and parity with the gallery
125
147
 
@@ -128,15 +150,15 @@ Thread **`view`**, **`onViewChange`**, and **`supportedViewTypes`** from the **c
128
150
  | Topic | Rule |
129
151
  |-------|------|
130
152
  | **Accessibility** | Each chart uses **`ChartFigure`** (keyboard + live region) and **`ChartDataTable`** (`sr-only` table fallback), inside **`ChartCard`** — same stack as **`charts-overview.tsx`**. **MUST NOT** ship bare Recharts-only charts on these surfaces. |
131
- | **Two “dashboard” surfaces** | The **`/dashboard`** route uses **`DashboardTabs`** + **`ChartsOverview`** (gallery / demos). The **Data** tab on list hubs uses **`*DashboardChartsSection`** (`PlacementsDashboardChartsSection`, Team, Compliance) and **`data-view-dashboard-charts*.tsx`**. Both share **`ChartFigure`**, **`ChartCard`**, and **`useChartVariant()`**; they are **not** duplicate chart engines — product charts belong in the shared components above. |
153
+ | **Two “dashboard” surfaces** | The **`/dashboard`** route uses **`DashboardTabs`** + **`ChartsOverview`** (gallery / demos). The **Data** tab on a hub uses a hub-specific `*DashboardChartsSection` (reference: **`LibraryDashboardChartsSection`** in **`components/library-dashboard-charts.tsx`**, wired from **`library-table.tsx`**). Both share **`ChartFigure`**, **`ChartCard`**, and **`useChartVariant()`**; they are **not** duplicate chart engines — product charts belong in the shared components above. |
132
154
  | **Keyboard selection (bars & pies)** | Match the **`/dashboard` gallery**: use **`CHART_KBD_ACTIVE_BAR`** and **`CHART_KBD_ACTIVE_PIE_SHAPE`** from **`@/lib/chart-keyboard-selection`** with Recharts **`activeBar` + `activeIndex`** on **`Bar`** and **`activeShape` + `activeIndex`** on **`Pie`**. **MUST NOT** rely on **`fillOpacity` dimming alone** on **`Cell`** as the only keyboard-selected state — it diverges from the gallery and from WCAG-aligned focus feedback. |
133
- | **Customise UI** | Toggle **Edit layout** on the hub dashboard toolbar (`DataListDashboardShell` / Team / Compliance). **`layoutEditMode`** shows on-canvas drag reorder, remove, width (half / full width), chart type, add chart, reset — **no** separate Sheet for layout. Target for coach marks: **`[aria-label='Edit dashboard layout']`**. |
155
+ | **Customise UI** | Toggle **Edit layout** on the hub dashboard toolbar inside **`PlacementsTable`** / **`TeamTable`** / **`ComplianceTable`** (the dashboard tab body renders `*DashboardChartsSection` directly — there is no shared `DashboardShell` wrapper). **`layoutEditMode`** shows on-canvas drag reorder, remove, width (half / full width), chart type, add chart, reset — **no** separate Sheet for layout. Target for coach marks: **`[aria-label='Edit dashboard layout']`**. |
134
156
  | **Toolbar in edit mode** | Do **not** render **`DataTableToolbar`** while **`layoutEditMode`** — hides search, filters, **Properties**, and the edit affordance in one row. Canvas **Done** / **Cancel** / **Reset** stay on the charts section. |
135
157
  | **Key metrics card** | Dashboard **`key-metrics`** uses **`KeyMetrics`** **`variant="card"`** (not **`flat`**). Users choose how many KPIs to show (**1–4**) via the canvas control in edit mode; persist **`keyMetricsKpiCount`** in the same layout object. Half-width (**span 1**) sets **`metricsHalfWidthLayout`**. |
136
158
  | **Data wiring** | **`PlacementsDashboardChartsSection`** (and Team / Compliance equivalents) **MUST** receive **`cardSpans`** and **`cardChartTypes`** (or rely on defaults **inside** the component). **MUST NOT** omit them without defaults — runtime crash (`undefined[id]`). |
137
- | **Persistence (centralized)** | Layout for all three hubs is stored in one bundle: **`lib/data-view-dashboard-storage.ts`** (`exxat-ds:data-view-dashboards:v1`, scopes **`placements` \| `team` \| `compliance`**). Placements wrappers: **`loadDashboardLayout`** / **`saveDashboardLayout`**; generic API: **`loadDataViewLayout`** / **`saveDataViewLayout`**. Legacy per-hub keys are migrated when a scope is missing. **MUST NOT** add a fourth localStorage key pattern for the same layout shape without extending this module. |
159
+ | **Persistence (centralized)** | Hub dashboard layouts share one bundle: **`lib/data-view-dashboard-storage.ts`** (key **`exxat-ds:data-view-dashboards:v1`**). Each hub registers under a string scope (e.g. **`library`**); the generic API is **`loadDataViewLayout`** / **`saveDataViewLayout`** + **`mergeDashboardLayoutGeneric`** (`lib/dashboard-layout-merge.ts`) for default-layout safety. **MUST NOT** add a sibling `localStorage` key for the same layout shape without extending this module. |
138
160
 
139
- **Reference:** `components/data-view-dashboard-charts.tsx`, `data-view-dashboard-charts-team.tsx`, `data-view-dashboard-charts-compliance.tsx`, `components/data-list-table.tsx` (`DataListDashboardShell`), `lib/chart-keyboard-selection.ts`, `lib/data-view-dashboard-storage.ts`, **`exxat-ds/.cursor/rules/exxat-dashboard-view-charts.mdc`**.
161
+ **Reference:** `components/library-dashboard-charts.tsx` (`LibraryDashboardChartsSection`), `components/library-table.tsx` (dashboard tab body wires the section + edit toolbar inline), `components/charts-overview.tsx` (full-page gallery), `lib/chart-keyboard-selection.ts`, `lib/data-view-dashboard-storage.ts`, **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`**.
140
162
 
141
163
  ### 4.4 Board cards (kanban)
142
164
 
@@ -148,10 +170,9 @@ Thread **`view`**, **`onViewChange`**, and **`supportedViewTypes`** from the **c
148
170
  | **Information hierarchy** | **(1)** **`ListPageBoardCardTitleRow`** — title + optional **`ListPageBoardCardAvatar`** (`trailing`). **(2)** **`ListPageBoardCardBadgeRow`** — status / tags as **`Badge`** chips when the entity has a status (not raw body text for status). **(3)** **`ListPageBoardCardBody`** — facts via **`BoardCardTwoLineBlock`** and/or **`BoardCardIconRow`** from **`board-card-primitives.tsx`**. **(4)** Optional **`ListPageBoardCardSecondary`** for empty-state hints. |
149
171
  | **Facts rows** | Prefer **`BoardCardTwoLineBlock`** (icon + primary line + optional secondary line) so rows match Placements. **`line2`** may be omitted for a single-line fact. Use **`BoardCardIconRow`** when the cell mirrors **`ColumnDef` cell renderers** (e.g. Placements). |
150
172
  | **Avatar** | Use **`ListPageBoardCardAvatar`** with entity **`initials`** when present; otherwise derive with **`initialsFromDisplayName`** from **`lib/initials-from-name.ts`** (e.g. compliance owner name). |
151
- | **Status labels + colors** | **All list hubs** (**Placements**, **Team**, **Compliance**, **Question bank**, …) **MUST** define status **labels**, **tint classes**, and **icons** in **`lib/list-status-badges.ts`**. Render with **`ListHubStatusBadge`**, or **`StatusBadge`** from **`components/data-list-table-cells.tsx`** for Placements (wrapper over **`ListHubStatusBadge`** + **`PLACEMENT_STATUS_*`**). **`surface="table"`** for **`DataTable`** / **list** rows; **`surface="board"`** in **`ListPageBoardCardBadgeRow`**. **SHOULD** map values onto **`LIST_HUB_STATUS_TINT_*`** (success / warning / neutral / danger / **info**) before inventing new palettes. **MUST NOT** duplicate maps in feature files or add **`uppercase`** / **`tracking-wide`**. |
152
- | **Placements-specific** | **`BoardPlacementCard`** may keep domain logic (lifecycle tabs, conditional row background, **`TablePropertiesDrawer`** column wiring); it still composes **`ListPageBoardCard`** parts and primitives. **Placements** status uses **`StatusBadge`** in **`components/data-list-table-cells.tsx`**, which wraps **`ListHubStatusBadge`** with **`PLACEMENT_STATUS_*`** maps in **`lib/list-status-badges.ts`** (same system as other hubs). |
173
+ | **Status labels + colors** | **All list hubs** **MUST** render status chips with **`ListHubStatusBadge`** and compose per-domain label / tint / icon maps next to the entity's mock data (reference: `lib/mock/library.ts` + `components/library-board-view.tsx`). Generic semantic tints live in **`lib/list-status-badges.ts`** (**`LIST_HUB_STATUS_TINT_SUCCESS / WARNING / INFO / NEUTRAL / DANGER`**). **`surface="table"`** for **`DataTable`** / **list** rows; **`surface="board"`** in **`ListPageBoardCardBadgeRow`**. **SHOULD** map domain statuses onto **`LIST_HUB_STATUS_TINT_*`** before inventing new palettes. **MUST NOT** duplicate the same tint table across feature files or add **`uppercase`** / **`tracking-wide`**. |
153
174
 
154
- **Reference:** **`components/data-views/placement-board-card.tsx`**, **`components/team-board-view.tsx`**, **`components/compliance-board-view.tsx`**, **`components/question-bank-board-view.tsx`**, **`components/list-hub-status-badge.tsx`**, **`lib/list-status-badges.ts`**, **`components/data-views/list-page-board-template.tsx`**. **Skill (Cursor + Claude):** **`.cursor/skills/exxat-board-cards/SKILL.md`** and **`.claude/skills/exxat-board-cards/SKILL.md`** (duplicate for Claude Code).
175
+ **Reference:** **`components/library-board-view.tsx`**, **`components/list-hub-status-badge.tsx`**, **`lib/list-status-badges.ts`** (generic tints), **`components/data-views/list-page-board-template.tsx`**, **`@exxatdesignux/ui/components/list-page-board-card`** (primitive). **Skill (Cursor + Claude):** **`.cursor/skills/exxat-board-cards/SKILL.md`** and **`.claude/skills/exxat-board-cards/SKILL.md`**.
155
176
 
156
177
  ### 4.5 View layout shells (centered, reusable, not page-tied)
157
178
 
@@ -160,7 +181,7 @@ Thread **`view`**, **`onViewChange`**, and **`supportedViewTypes`** from the **c
160
181
  | Topic | Rule |
161
182
  |-------|------|
162
183
  | **Folder / icon / panel-style views** | Compose **`FolderGridView`**, **`FinderPanelView`**, or another **`data-views/`** primitive; those shells **should** use **`ListPageViewFrame`** internally or as a direct wrapper so every hub gets the same rhythm. |
163
- | **New view types** | Implement the **generic** grid/shell under **`components/data-views/`** with render props; **`TeamTable`** / **`QuestionBankTable`** **MUST** only wire data + callbacks — **MUST NOT** own one-off full-page grid markup that another entity would duplicate. |
184
+ | **New view types** | Implement the **generic** grid/shell under **`components/data-views/`** with render props; **`TeamTable`** / **`LibraryTable`** **MUST** only wire data + callbacks — **MUST NOT** own one-off full-page grid markup that another entity would duplicate. |
164
185
  | **`DataTable` branch** | **MUST NOT** wrap **`DataTable`** in **`ListPageViewFrame`** when it would **stack** horizontal inset with the table toolbar (**§5**). |
165
186
 
166
187
  **Cursor rule:** **`.cursor/rules/exxat-list-page-view-shells.mdc`**. **Skill:** **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`**.
@@ -173,14 +194,14 @@ Thread **`view`**, **`onViewChange`**, and **`supportedViewTypes`** from the **c
173
194
 
174
195
  | Step | Action |
175
196
  |------|--------|
176
- | **Nav** | Set **`secondaryPanel`** on the **`NavLinkItem`** in **`lib/mock/navigation.tsx`** to a **stable id** (e.g. **`"question-bank"`**). **`url`** stays the **hub route**. |
197
+ | **Nav** | Set **`secondaryPanel`** on the **`NavLinkItem`** in **`lib/mock/navigation.tsx`** to a **stable id** (e.g. **`"library"`**). **`url`** stays the **hub route**. |
177
198
  | **Registry** | Map that id in **`PANELS`** inside **`components/secondary-panel.tsx`** to a component that renders **panel header** + **secondary nav** UI. |
178
- | **Route** | Mount **`*PanelActivator`** on the hub that calls **`useAutoPanel(id)`** with the **same id** so the panel opens while the route is mounted (see **`QuestionBankPanelActivator`** on **`QuestionBankClient`**). |
179
- | **Data** | Keep using **one** **`useTableState`** row bag; **scope** filters via **URL** + shared helpers (**`lib/question-bank-nav.ts`**) so **refresh** and **links** match the panel — **`.cursor/rules/exxat-centralized-list-dataset.mdc`**. |
199
+ | **Route** | Mount **`*PanelActivator`** on the hub that calls **`useAutoPanel(id)`** with the **same id** so the panel opens while the route is mounted (see **`LibraryPanelActivator`** on **`LibraryClient`**). |
200
+ | **Data** | Keep using **one** **`useTableState`** row bag; **scope** filters via **URL** + shared helpers (**`lib/library-nav.ts`**) so **refresh** and **links** match the panel — **`.cursor/rules/exxat-centralized-list-dataset.mdc`**. |
180
201
 
181
202
  **MUST NOT:** Set **`secondaryPanel`** without **`PANELS[id]`** and **`useAutoPanel`** — users see **collapsed** main nav with **no** panel body.
182
203
 
183
- **Folder-scoped library (Question bank):** When the URL is scoped to a folder (**`scope === "folder"`** + **`folderId`** via **`lib/question-bank-nav.ts`**), the hub **`QuestionBankPageHeader`** **⋯ More** menu **MUST** include **Customize folder** and open **`QuestionBankNewFolderSheet`** from the **hub client** so the action works on **every** **`ListPageTemplate`** view tab — not only inside **`QuestionBankTable`** branches that mount their own sheet. **Pattern:** **`docs/question-bank-hub-header-pattern.md`**. **Cursor rule:** **`.cursor/rules/exxat-question-bank-hub-header.mdc`**.
204
+ **Folder-scoped library (Library):** When the URL is scoped to a folder (**`scope === "folder"`** + **`folderId`** via **`lib/library-nav.ts`**), the hub **`LibraryPageHeader`** **⋯ More** menu **MUST** include **Customize folder** and open **`LibraryNewFolderSheet`** from the **hub client** so the action works on **every** **`ListPageTemplate`** view tab — not only inside **`LibraryTable`** branches that mount their own sheet. **Pattern:** **`docs/library-hub-header-pattern.md`**. **Cursor rule:** **`.cursor/rules/exxat-library-hub-header.mdc`**.
184
205
 
185
206
  **Surface elevation:** Secondary panel = **level 1** between primary sidebar (**`--sidebar`**, level 0) and page canvas (**`--background`**, level 2). **`NestedSecondaryPanelShell`** uses **`bg-[var(--secondary-panel-bg)]`** — OKLCH mix from **`--brand-tint*`** per active product (**One** indigo, **Prism** rose, **`theme-custom`** when accent differs from default). **MUST NOT** set panel to **`bg-sidebar`** or a fixed rose fill for all products. **`docs/shell-surface-elevation-pattern.md`**.
186
207
 
@@ -203,7 +224,7 @@ Thread **`view`**, **`onViewChange`**, and **`supportedViewTypes`** from the **c
203
224
 
204
225
  **MUST NOT:** **`Select`** in **`InputGroupAddon`** without **`InputGroupInput`** / **`SelectGroup`**; per-person cards in the roster; a second invite control **beside** an existing face rail.
205
226
 
206
- **Narrative:** **`docs/collaboration-access-pattern.md`**. **Cursor rule:** **`.cursor/rules/exxat-collaboration-access.mdc`**. **Skill:** **`.cursor/skills/exxat-collaboration-access/SKILL.md`**. **Reference:** Question bank header + client + **`InviteCollaboratorsDrawer`**.
227
+ **Narrative:** **`docs/collaboration-access-pattern.md`**. **Cursor rule:** **`.cursor/rules/exxat-collaboration-access.mdc`**. **Skill:** **`.cursor/skills/exxat-collaboration-access/SKILL.md`**. **Reference:** Library header + client + **`InviteCollaboratorsDrawer`**.
207
228
 
208
229
  ### 4.8 Dedicated search (landing vs results)
209
230
 
@@ -242,7 +263,7 @@ Below the threshold, these MAY be omitted unless the page is a **primary hub** (
242
263
 
243
264
  Match **Placements**:
244
265
 
245
- - **Primary CTA:** one **default (filled)** `Button`, often `size="lg"` — e.g. New placement, Invite member. **MUST NOT** use `variant="outline"` for that primary action.
266
+ - **Primary CTA:** one **default (filled)** `Button`, often `size="lg"` — e.g. "New question", "Invite collaborator", "Add token". **MUST NOT** use `variant="outline"` for that primary action.
246
267
  - **More (⋯):** outline **icon** button → menu including **Export** → **`ExportDrawer`** (or same pattern).
247
268
 
248
269
  **Subtitle:** Short line with **count + freshness** (e.g. `24 records · Last updated now`) when useful — see `PlacementsPageHeader` / `TeamPageHeader`.
@@ -251,7 +272,7 @@ Match **Placements**:
251
272
 
252
273
  **Primary nav destinations** that show **large or highly interactive** datasets **MUST** use the **primary page template**:
253
274
 
254
- - **`ListPageTemplate`** + **`KeyMetrics`** (when metrics apply) + export wiring + the same **client composition** as **`DataListClient`** / **`TeamClient`** — not a minimal `PageHeader`-only layout for that hub.
275
+ - **`ListPageTemplate`** + **`KeyMetrics`** (when metrics apply) + export wiring + the same **client composition** as **`PlacementsClient`** / **`TeamClient`** — not a minimal `PageHeader`-only layout for that hub.
255
276
 
256
277
  **MUST NOT** treat a main hub table page as a “light” sub-section: use the same shell as Placements (tabs, optional metrics strip, template-level export).
257
278
 
@@ -266,9 +287,7 @@ Match **Placements**:
266
287
 
267
288
  **Rationale:** Drawers preserve **spatial context**; dialogs enforce **focus**; full pages avoid cramming complex work into overlays.
268
289
 
269
- **Details:** `docs/data-views-pattern.md` (Page vs drawer), **`docs/drawer-vs-dialog-pattern.md`** (drawer vs modal on the same route), **`docs/focused-workflow-page-pattern.md`** (dedicated form/wizard/settings shell — **`FocusedWorkflowPageTemplate`** + body layouts). Root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**, **`.cursor/skills/exxat-focused-workflow-page/SKILL.md`**.
270
-
271
- **Focused workflow routes:** Primary / long / multi-step / sectioned settings on an **own URL** → **`FocusedWorkflowPageTemplate`** (§14 checklist) — **not** **`ListPageTemplate`**, **not** Miller-column explorers.
290
+ **Details:** `docs/data-views-pattern.md` (Page vs drawer), **`docs/drawer-vs-dialog-pattern.md`** (drawer vs modal on the same route). Root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
272
291
 
273
292
  ### 6.5 Messaging — no toast
274
293
 
@@ -291,7 +310,7 @@ Follow root **`.cursor/rules/exxat-kbd-shortcuts.mdc`**. Summary:
291
310
 
292
311
  ### 7.1 Global command palette (⌘K)
293
312
 
294
- **Product intent:** **`CommandMenu`** is **global search** and the primary **AI entry**—not a second nav tree. Config: **`buildCommandMenuConfig()`** in **`lib/command-menu-config.ts`**, provider in **`app/(app)/layout.tsx`**. Optional searchable rows (e.g. placements / student names) come from **`dataGroups`**, typically via **`getCommandMenuSearchDataGroups()`** in **`lib/command-menu-search-data.ts`**.
313
+ **Product intent:** **`CommandMenu`** is **global search** and the primary **AI entry**—not a second nav tree. Config: **`buildCommandMenuConfig()`** in **`lib/command-menu-config.ts`**, provider in **`app/(app)/layout.tsx`**. Optional searchable rows (e.g. student names, question stems, record IDs) come from **`dataGroups`**, typically via **`getCommandMenuSearchDataGroups()`** in **`lib/command-menu-search-data.ts`**.
295
314
 
296
315
  | SHOULD | Rationale |
297
316
  |--------|-----------|
@@ -310,7 +329,7 @@ Follow root **`.cursor/rules/exxat-kbd-shortcuts.mdc`**. Summary:
310
329
 
311
330
  **Standard:** **WCAG 2.1 Level AA** (and **2.2** where noted, e.g. target size).
312
331
 
313
- **Authoritative detail (badges, placement count colors, audit table):** **`.cursor/skills/exxat-accessibility/SKILL.md`** at the monorepo root (when the parent repo is open). If the skill path differs in your checkout, search for **`exxat-accessibility`**.
332
+ **Authoritative detail (badges, sidebar count colors, audit table):** **`.cursor/skills/exxat-accessibility/SKILL.md`** at the monorepo root (when the parent repo is open). If the skill path differs in your checkout, search for **`exxat-accessibility`**.
314
333
 
315
334
  ### 8.1 ARIA roles & structure (SC 1.3.1)
316
335
 
@@ -434,7 +453,7 @@ Keyboard shortcut hints rendered **inline inside a `Button`** (primary, secondar
434
453
  <TooltipContent><span>Close</span><Kbd>Esc</Kbd></TooltipContent>
435
454
  ```
436
455
 
437
- Reference: `components/new-placement-form.tsx` (Next/Back buttons); full shortcut table in **`.cursor/rules/exxat-kbd-shortcuts.mdc`**.
456
+ Reference: `components/new-library-item-form.tsx` (Next/Back buttons); full shortcut table in **`.cursor/rules/exxat-kbd-shortcuts.mdc`**.
438
457
 
439
458
  ---
440
459
 
@@ -442,24 +461,21 @@ Reference: `components/new-placement-form.tsx` (Next/Back buttons); full shortcu
442
461
 
443
462
  | Need | Reuse | Where |
444
463
  |------|--------|--------|
445
- | View tabs + shell | `ListPageTemplate` (+ **`supportedViewTypes`**) | `components/templates/list-page.tsx` |
446
- | Focused form / wizard / settings route | `FocusedWorkflowPageTemplate` + layouts in `focused-workflow-layouts.tsx` | `components/templates/focused-workflow-page-template.tsx` — **`docs/focused-workflow-page-pattern.md`** |
447
- | View router | `ListPageConnectedViewBody`, `defineHubViewRenderers`, `data-list-view-registry` | `components/data-views/list-page-connected-view-body.tsx`, `lib/hub-connected-view-renderers.ts`, `lib/data-list-view-registry.ts` |
464
+ | View tabs + shell | `ListPageTemplate` | `components/templates/list-page.tsx` |
448
465
  | Table + toolbar | `DataTable`, `DataTableToolbar`, `useTableState` | `components/data-table/` |
449
- | Properties | `TablePropertiesDrawer` (+ **`currentView`** / **`onViewChange`** / **`supportedViewTypes`** — §4.2) | `@/components/table-properties` |
450
- | List hub (golden) | `ListHubClient`, `ListHubTable` | `components/list-hub-client.tsx`, `list-hub-table.tsx` |
451
- | Question bank | `QuestionBankClient`, `QuestionBankTable` | `components/question-bank-client.tsx`, `question-bank-table.tsx` |
452
- | Template-only hubs (npm) | Placements, Team, Compliance, Sites | `packages/ui/template/components/*` diff on upgrade |
453
- | Dashboard view tab (KPIs + charts) | **`DashboardReportCharts`**; default **`ChartsOverview`** (placement demo). **Team** passes **`chartsSection`** (`TeamDashboardChartsSection`) so graphs match roster rows. KPIs from **`tableState.rows`** | `components/dashboard-report-charts.tsx`, `data-view-dashboard-charts-team.tsx`, `data-list-table.tsx` |
466
+ | Properties | `TablePropertiesDrawer` (+ **`currentView`** / **`onViewChange`** when using view tabs — §4.2) | `@/components/table-properties` |
467
+ | Full hub (table / board / dashboard) | `LibraryHubClient`, `LibraryTable` | `components/library-hub-client.tsx`, `components/library-table.tsx` |
468
+ | Single-view catalog hub | `ColumnsClient`, `ColumnsShowcase` | `components/columns-client.tsx`, `components/columns-showcase.tsx` |
469
+ | Dashboard view tab (KPIs + charts) | **`DashboardReportCharts`**; default **`ChartsOverview`** (full-page gallery). Hubs pass **`chartsSection`** with their own `*DashboardChartsSection` so graphs match the row set. KPIs from **`tableState.rows`**. | `components/dashboard-report-charts.tsx`, `components/library-dashboard-charts.tsx`, `components/library-table.tsx` |
454
470
  | Data view layout + graph keyboard tokens | **`loadDataViewLayout` / `saveDataViewLayout`**, **`CHART_KBD_ACTIVE_BAR`**, **`CHART_KBD_ACTIVE_PIE_SHAPE`** | `lib/data-view-dashboard-storage.ts`, `lib/chart-keyboard-selection.ts` |
455
- | Customize dashboard coach marks | Shared steps in **`lib/dashboard-customize-coach-mark.ts`**; flows **`placements-dashboard-customize`**, **`team-dashboard-customize`**, **`compliance-dashboard-customize`** | `hooks/use-coach-mark.ts` (`enabled`, `dependsOnDismissedFlowId`), `data-list-table.tsx`, `team-table.tsx`, `compliance-table.tsx` |
456
- | Board columns (simple hubs) | **`ListPageBoardTemplate`** + **`ListPageBoardCard`** + primitives + **`lib/list-status-badges`** + **`ListHubStatusBadge`** (when applicable) | `components/data-views/list-page-board-template.tsx`, `list-hub-status-badge.tsx`, `team-board-view.tsx`, **`§4.4`** |
471
+ | Customize dashboard coach marks | Shared steps in **`lib/dashboard-customize-coach-mark.ts`**; one flow per hub scope (e.g. **`library-dashboard-customize`**) | `hooks/use-coach-mark.ts` (`enabled`, `dependsOnDismissedFlowId`), `library-table.tsx` |
472
+ | Board columns (simple hubs) | **`ListPageBoardTemplate`** + **`ListPageBoardCard`** + primitives + **`lib/list-status-badges`** + **`ListHubStatusBadge`** (when applicable) | `components/data-views/list-page-board-template.tsx`, `list-hub-status-badge.tsx`, `library-board-view.tsx`, **`§4.4`** |
457
473
  | Full dashboard route | `DashboardTabs`, `KeyMetrics`, `ChartsOverview` | `app/(app)/dashboard/page.tsx`, `components/dashboard-tabs.tsx` |
458
- | Board cards | **`ListPageBoardCard`** + primitives + entity card (**§4.4**) | `components/data-views/list-page-board-card.tsx`, `board-card-primitives.tsx`, `placement-board-card.tsx` |
474
+ | Board cards | **`ListPageBoardCard`** + primitives + entity card (**§4.4**) | `components/data-views/list-page-board-card.tsx`, `board-card-primitives.tsx`, `library-board-view.tsx` |
459
475
  | **Application sidebar** (school/program, product, profile, child nav) | **`AppSidebar`**, **`TeamSwitcher`**, **`NavUser`**, collapsible + **popover** (icon rail) | `components/app-sidebar.tsx`, `nav-user.tsx`, `product-switcher.tsx`, `lib/mock/navigation.tsx`, `lib/logo-dev.ts`, `lib/stock-portrait.ts` — patterns in **exxat-ds-skill §3.1** |
460
- | **Collaboration & access** (face rail + invite sheet) | **`PageHeader` `variant="collaboration"`**, **`InviteCollaboratorsDrawer`**, **`lib/collaborator-access.ts`** | `components/page-header.tsx`, `components/invite-collaborators-drawer.tsx`, `components/question-bank-page-header.tsx`, `components/question-bank-client.tsx`, **`§4.7`**, **`docs/collaboration-access-pattern.md`** |
476
+ | **Collaboration & access** (face rail + invite sheet) | **`PageHeader` `variant="collaboration"`**, **`InviteCollaboratorsDrawer`**, **`lib/collaborator-access.ts`** | `components/page-header.tsx`, `components/invite-collaborators-drawer.tsx`, `components/library-page-header.tsx`, `components/library-client.tsx`, **`§4.7`**, **`docs/collaboration-access-pattern.md`** |
461
477
  | **Dedicated search** (empty `?q=` landing vs results) | **`DedicatedSearchLandingTemplate`**, **`DedicatedSearchUrlComposer`**, **`DedicatedSearchRecents`**, **`DedicatedSearchResultsHeaderChrome`**, **`lib/dedicated-search-recents.ts`** | **`§4.8`**, **`components/templates/dedicated-search-*`**, **`components/dedicated-search-*.tsx`** |
462
- | Persistence (example) | Page + lifecycle keys | `lib/data-list-persistence.ts`, `DataListClient` / `DataListTable` |
478
+ | Persistence (example) | Page + lifecycle keys | `lib/data-list-persistence.ts`, `PlacementsClient` / `PlacementsTable` |
463
479
  | Coach marks / tours | `CoachMark`, `useCoachMark`, coach mark registry | `components/ui/coach-mark.tsx`, `hooks/use-coach-mark.ts`, `lib/coach-mark-registry.ts` |
464
480
  | Settings page | Coach mark management | `app/(app)/settings/page.tsx`, `components/settings-client.tsx` |
465
481
 
@@ -484,8 +500,8 @@ Reference: `components/new-placement-form.tsx` (Next/Back buttons); full shortcu
484
500
 
485
501
  ## 10. Persistence (when copying Placements behavior)
486
502
 
487
- - **Page-level:** tabs, `showMetrics`, `displayOptions`, `activeTabId` — see `lib/data-list-persistence.ts` and `DataListClient`.
488
- - **Per-lifecycle / tab:** sort, filters, columns, etc. — see `DataListTable` and `scheduleLifecycleSave`.
503
+ - **Page-level:** tabs, `showMetrics`, `displayOptions`, `activeTabId` — see `lib/data-list-persistence.ts` and `PlacementsClient`.
504
+ - **Per-lifecycle / tab:** sort, filters, columns, etc. — see `PlacementsTable` and `scheduleLifecycleSave`.
489
505
 
490
506
  New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrations.
491
507
 
@@ -514,7 +530,7 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
514
530
  - **Brand-colored:** popover background is `bg-brand-deep text-white` — not `bg-popover`.
515
531
  - **Persistent:** once completed/skipped, the flow is dismissed via `localStorage` and won't reshow until reset from Settings.
516
532
  - **Settings page:** `/settings` lists all registered flows with reset/preview controls.
517
- - **Sequencing / gating:** `useCoachMark` supports **`enabled`** (e.g. only when **`view === "dashboard"`**) and **`dependsOnDismissedFlowId`** (e.g. customize-dashboard after **`placements-views-tour`**). Completed flows dispatch **`COACH_MARK_FLOW_COMPLETED_EVENT`** on `window` so follow-up tours can open in the same tab.
533
+ - **Sequencing / gating:** `useCoachMark` supports **`enabled`** (e.g. only when **`view === "dashboard"`**) and **`dependsOnDismissedFlowId`** (e.g. customize-dashboard after a "views" tour completes). Completed flows dispatch **`COACH_MARK_FLOW_COMPLETED_EVENT`** on `window` so follow-up tours can open in the same tab.
518
534
  - **Customize Data dashboard:** registered flows target **`[aria-label='Edit dashboard layout']`**; shared step copy lives in **`lib/dashboard-customize-coach-mark.ts`**.
519
535
 
520
536
  ### Variants
@@ -524,16 +540,15 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
524
540
  - **With image** — set `image` + `imageAlt` on the step
525
541
  - **Without image** — text-only
526
542
 
527
- **Reference:** `references/coach-marks.md` in the skill, `components/dashboard-tabs.tsx` (dashboard tour), `components/data-list-client.tsx` (views tour).
543
+ **Reference:** `references/coach-marks.md` in the skill, `components/dashboard-tabs.tsx` (dashboard tour), `components/library-hub-client.tsx` (views tour).
528
544
 
529
545
  ---
530
546
 
531
547
  ## 12. Documentation
532
548
 
533
549
  - **Deep dive:** `docs/data-views-pattern.md` (includes **Page vs drawer** with **§6.4**)
550
+ - **Scaling to 5K+ rows:** `docs/large-dataset-strategy.md` (client mode, pagination, server mode, virtualization follow-up)
534
551
  - **Drawer vs dialog (same route):** `docs/drawer-vs-dialog-pattern.md` — **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**
535
- - **Focused workflow (form / wizard / settings route):** `docs/focused-workflow-page-pattern.md` — **`.cursor/rules/exxat-focused-workflow-page.mdc`**, **`.cursor/skills/exxat-focused-workflow-page/SKILL.md`**
536
- - **Consumer app (npm):** `docs/consumer-app-pattern.md` — **`packages/ui/consumer-extras/AGENTS.md`**, **`.cursor/rules/exxat-consumer-app.mdc`**, **`.cursor/skills/exxat-consumer-app/SKILL.md`**
537
552
  - **Cards vs table rows:** `docs/card-vs-rows-pattern.md` — **`.cursor/rules/exxat-card-vs-list-rows.mdc`**
538
553
  - **KPI strip (max four tiles):** `docs/kpi-strip-max-four-pattern.md` — **`.cursor/rules/exxat-kpi-max-four.mdc`**
539
554
  - **KPI flat band (list hubs):** `docs/kpi-flat-band-pattern.md` — **`.cursor/rules/exxat-kpi-flat-band.mdc`**
@@ -541,7 +556,38 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
541
556
  - **KPI deltas & trend arrows:** `docs/kpi-trend-pattern.md` (`MetricItem.trendPolarity`, `KeyMetrics`, chart mini-metrics)
542
557
  - **Global command palette (⌘K):** `docs/command-menu-pattern.md`
543
558
  - **No toast / snackbars:** **§6.5**, root **`.cursor/rules/exxat-no-toast.mdc`**
544
- - **This handbook:** `exxat-ds/AGENTS.md` (keep checklist sections updated when patterns change)
559
+ - **Token taxonomy:** `docs/token-taxonomy.md` — namespaces, layering (L0 / L1 / L2 / L3), naming, deprecation policy. Machine-readable index at `packages/ui/tokens/hooks-index.json` (163 tokens · 36 namespaces · regenerate via `pnpm --filter @exxatdesignux/ui tokens:index`).
560
+ - **Exxat L0 canonical namespace:** `--exxat-color-surface-*`, `--exxat-color-ink-*`, `--exxat-color-brand-*`, `--exxat-radius-*`, `--exxat-spacing-*`, … (taxonomy §2.0; rollout: `docs/migrations/0002-exxat-token-namespace.md`).
561
+ - **Component selection guide:** `docs/component-selection-guide.md` — decision tree across the whole DS.
562
+ - **Blueprints:** `docs/blueprints/` — framework-agnostic specs. Start with `page-header.md` and `data-table.md`; add new ones via `_template.md`.
563
+ - **Migrations:** `docs/migrations/` — token rename + removal history. Open a new entry alongside every breaking change.
564
+ - **Components audit:** `docs/components-audit-2026-05.md` — observation log; §2.1 (form-layout / section-cards) and §2.2 (onboarding consolidation) both resolved 2026-05-19.
565
+ - **This handbook:** `apps/web/AGENTS.md` (keep checklist sections updated when patterns change)
566
+
567
+ ### 12.1 Design-system meta-rules
568
+
569
+ | Concern | Rule | Enforcement |
570
+ |---|---|---|
571
+ | Salesforce / SLDS / LWC cross-contamination | **`.cursor/rules/exxat-no-slds-leakage.mdc`** | ESLint: `exxat-ds/no-slds-classes`, `exxat-ds/no-lightning-elements` |
572
+ | Hex literals, deprecated tokens, wrong token family | **`.cursor/rules/exxat-token-discipline.mdc`** | ESLint: `exxat-ds/no-hex-color`, `exxat-ds/no-deprecated-tokens` |
573
+ | No-toast feedback policy | **`.cursor/rules/exxat-no-toast.mdc`** (§6.5) | ESLint: `exxat-ds/no-sonner-toast` |
574
+
575
+ The ESLint rules ship as a **workspace package**:
576
+ **`packages/eslint-plugin-exxat-ds/`** (published as `@exxatdesignux/eslint-plugin`).
577
+ `apps/web/eslint.config.mjs` imports it via `import exxatDs from "@exxatdesignux/eslint-plugin"`
578
+ and consumers of `@exxatdesignux/ui` can install the plugin from npm with the
579
+ same wiring. See [`packages/eslint-plugin-exxat-ds/README.md`](../../packages/eslint-plugin-exxat-ds/README.md)
580
+ for rule docs and authoring guidance.
581
+
582
+ When you **introduce** a new token in `packages/ui/src/globals.css` (the canonical CSS — app/template `globals.css` are thin `@import` shells):
583
+
584
+ 1. **Prefer L0** — declare the canonical name in the `Exxat L0 — canonical namespace`
585
+ block (`--exxat-color-<bucket>-<slot>` / `--exxat-radius-N` / `--exxat-spacing-N`).
586
+ 2. Add a row to `docs/token-taxonomy.md` in the right § (§2.0 if L0; §2.1–§2.17 for legacy L1 surfaces).
587
+ 3. Run `pnpm --filter @exxatdesignux/ui tokens:index` and commit the
588
+ regenerated `packages/ui/tokens/hooks-index.json`.
589
+ 4. If you are **deprecating** a token, also open a numbered entry under
590
+ `docs/migrations/` (see `docs/migrations/README.md` template).
545
591
 
546
592
  ---
547
593
 
@@ -549,13 +595,13 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
549
595
 
550
596
  | MUST | MUST NOT |
551
597
  |------|----------|
552
- | Use `DataTable` + search + filters + `TablePropertiesDrawer` for product data lists; with **`ListPageTemplate`** view tabs, pass **`currentView`** + **`onViewChange`** (§4.2) | Introduce a second table stack for the same surfaces; omit **`currentView`** on multi-view pages |
598
+ | Use **`HubTable`** (from **`@/components/data-views`**) inside **`ListPageTemplate.renderContent`** — it wires `useTableState`, the **toolbar** (search + filter chips + filter dropdown + sort), and **`TablePropertiesDrawerButton`** in one place. Pass **`view`** / **`onViewChange`** through (§4.2); raw **`DataTable`** is fine **only** outside hubs (drawer/dialog mini-grids) | Mount raw **`<DataTable>`** in a hub or showcase — users lose filter chips and Properties; introduce a second table stack for the same surfaces; omit **`currentView`** on multi-view pages |
553
599
  | Wrap main `DataTable` in `ListPageTemplate` | `DataTable` only under `PageHeader` without view tabs |
554
600
  | Use primary template (`ListPageTemplate` + metrics + export pattern) for primary hubs with large data | Hub pages that look like “nested cards” with staggered margins |
555
601
  | Match Placements for export + primary CTA + More menu | Outline button as the single primary CTA on exportable pages |
556
602
  | Pair `Kbd` hints with real shortcuts | Browser-reserved chords for app actions |
557
603
  | Global palette: **§7.1** — search + quick in-menu AI vs **Ask Leo**; **`dataGroups`** + **`searchOnly`** for bulky indexes | Palette as link-only dump; AI that belongs in **Ask Leo** forced into the palette; mounting full **`dataGroups`** on open when **`searchOnly`** should hide them |
558
- | **§6.4** — **drawer** when **page context + quick** view/actions; **dialog** for **blocking** confirm/alert/short choice; **focused workflow route** (`FocusedWorkflowPageTemplate`) for primary / long / wizard / sectioned settings | Forcing **full workflows** into a drawer when a route fits; using a **dialog** when users must **reference** the grid (prefer drawer); **`ListPageTemplate`** or Miller columns on dedicated create/edit routes |
604
+ | **§6.4** — **drawer** when **page context + quick** view/actions; **dialog** for **blocking** confirm/alert/short choice; **new page** for primary / long / own-URL flows | Forcing **full workflows** into a drawer when a route fits; using a **dialog** when users must **reference** the grid (prefer drawer); **routing** for tasks that are only quick glances over a hub |
559
605
  | **KPI strips** — **≤ 4** `MetricItem` per **`KeyMetrics`** on template metrics + Data-tab key-metrics cards (**`KEY_METRICS_KPI_COUNT_MAX`**) | Fifth+ headline tile in the same strip; duplicate tiles to pad count |
560
606
  | **Cards vs rows** — **DataTable** for dense comparable hubs; **`ListPageBoardCard`** / **`ListPageViewFrame`** when visual/kanban/folder — **`docs/card-vs-rows-pattern.md`** | Card walls for **50+** homogeneous records where the product expects **sort/filter/compare** without a deliberate UX exception |
561
607
  | **Reuse before custom** — scan **`components/`** + **§9**; **ask the user** before new shared primitives or large bespoke widgets — **`exxat-reuse-before-custom.mdc`** | Parallel stacks; silent new “table” or metric systems when **`DataTable`** / **`KeyMetrics`** already apply |
@@ -565,9 +611,9 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
565
611
  | Data view charts: **`ChartFigure`** + **`ChartDataTable`**; keyboard highlight via **`chart-keyboard-selection`** (§4.3); layout via **`data-view-dashboard-storage`** | Ad-hoc `localStorage` keys for dashboard layout; opacity-only “selection” without `activeBar`/`activeShape` |
566
612
  | Board cards: **`ListPageBoardCard`** shell; status via **`ListHubStatusBadge`** + **`lib/list-status-badges`**; no **`uppercase`** on status chips (§4.4) | One-off board card markup; status as plain body text; duplicated status maps outside **`list-status-badges`**; **empty placeholder** primary hubs (§4.1) |
567
613
  | **§4.5** — Non-table view bodies use **`ListPageViewFrame`** (+ **`data-views/`** shells); new grids are generic components, not route-only markup | Duplicated `mx-4` / `max-w-*` per hub; wrapping **`DataTable`** so inset **doubles** (**§5**) |
568
- | **§4.6** — **`secondaryPanel`** + **`PANELS`** + **`useAutoPanel`** together for nested scope nav; **folder URL scope** → header **⋯** **Customize folder** + client-mounted **`QuestionBankNewFolderSheet`** (**`exxat-question-bank-hub-header.mdc`**) | **`secondaryPanel`** id with no panel component or activator; folder scope with customize **only** inside a single view tab’s subtree |
614
+ | **§4.6** — **`secondaryPanel`** + **`PANELS`** + **`useAutoPanel`** together for nested scope nav; **folder URL scope** → header **⋯** **Customize folder** + client-mounted **`LibraryNewFolderSheet`** (**`exxat-library-hub-header.mdc`**) | **`secondaryPanel`** id with no panel component or activator; folder scope with customize **only** inside a single view tab’s subtree |
569
615
  | **§4.7** — **`PageHeader` `variant="collaboration"`** + **`CollaborationAccessFlow`** / **`InviteCollaboratorsDrawer`**; empty **Add collaborator** + non-empty face rail; roster + invite from **`collaborator-access.ts`** | Extra invite beside a populated face rail; per-person roster cards; forked access enums; toast on invite |
570
- | **§4.8** — **`DedicatedSearch*`** templates + composer + recents; **no** `localStorage` in **`useState`** initial paint; hub-specific **`patchSearchParams`** only | Forked `*QuestionBank*SearchLanding*` shells for another entity; hydration mismatch on recents |
616
+ | **§4.8** — **`DedicatedSearch*`** templates + composer + recents; **no** `localStorage` in **`useState`** initial paint; hub-specific **`patchSearchParams`** only | Forked `*Library*SearchLanding*` shells for another entity; hydration mismatch on recents |
571
617
  | **Font Awesome** — Kit in **`app/layout.tsx`**; **`fa-light` / `fa-solid`** conventions; **`aria-hidden`** on decorative **`<i>`**; run **`fa:subset-audit`** when adding glyphs (**`exxat-fontawesome-icons.mdc`**) | Parallel icon libraries for the same product chrome |
572
618
  | **System IDs** — **`font-mono tabular-nums`** on question/record keys; mono **only** the ID token in mixed subtitles (**`exxat-mono-ids.mdc`**) | Mono on names, statuses, dates, or whole subtitle lines |
573
619
 
@@ -578,20 +624,20 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
578
624
  Copy and complete when implementing or reviewing:
579
625
 
580
626
  - [ ] **Centralized dataset:** One **`useTableState`** / **`tableState.rows`** for **all** view tabs and inspectors; **TablePropertiesDrawer** on the **same** `DataTable`; **no** parallel mock arrays per view — **`.cursor/rules/exxat-centralized-list-dataset.mdc`**.
581
- - [ ] **View registry (§4.1.1):** **`lib/<hub>-supported-views.ts`**; **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`**; same **`supportedViewTypes`** on template + Properties; no silent dashboard fallback**`docs/data-views-pattern.md`**.
627
+ - [ ] **Hub primitive (`HubTable`):** Every page that mounts a hub grid inside **`ListPageTemplate`** uses **`HubTable`** (from **`@/components/data-views`**), not raw **`<DataTable>`**. **`HubTable`** wires `useTableState`, the toolbar (search + filter chips + filter dropdown + sort), and **`TablePropertiesDrawerButton`** in one place; raw **`<DataTable>`** is reserved for tiny embedded grids (drawer/dialog body). When a column ships **`filter:`**, the chips appear automatically **MUST NOT** add a parallel search/filter UI above the table — **`.cursor/rules/exxat-data-tables.mdc`**.
582
628
  - [ ] **Reuse:** `ListPageTemplate`, `DataTable` / `useTableState`, `TablePropertiesDrawer` — no parallel bespoke tabs/filters. **New shared primitives:** **ask the user** after scanning **`components/`** + **§9** — **`.cursor/rules/exxat-reuse-before-custom.mdc`**.
583
629
  - [ ] **Tabs:** Any main `DataTable` sits under `ListPageTemplate` with appropriate view tabs.
584
630
  - [ ] **Inset:** No double horizontal padding around `DataTable`.
585
631
  - [ ] **§4.5 View shells:** Folder / panel / icon views use **`ListPageViewFrame`** (or a **`data-views/`** component that uses it); no page-tied-only grid wrappers; **`DataTable`** not double-wrapped (**§5**).
586
632
  - [ ] **> ~10 items:** Search, filter, sort, properties (per surface type in §6.1).
587
633
  - [ ] **Exportable data:** Filled primary CTA; **⋯** menu with Export → `ExportDrawer`.
588
- - [ ] **Primary hub + large data:** Same composition as `DataListClient` / `TeamClient` (template + metrics when applicable).
634
+ - [ ] **Primary hub + large data:** Same composition as `PlacementsClient` / `TeamClient` (template + metrics when applicable).
589
635
  - [ ] **All view tabs:** List/board/dashboard use **`tableState.rows`**; dashboard view uses **`KeyMetrics`** + shared KPI helpers — no “not wired” placeholders or duplicate metric cards.
590
636
  - [ ] **Properties drawer:** **`TablePropertiesDrawer`** receives **`currentView`** and **`onViewChange`** from **`renderContent`** / **`updateTab`** + **`dataListViewIcon`** (§4.2) — not table-only copy on Board/List/Dashboard.
591
637
  - [ ] **Data view dashboard (Placements / Team / Compliance):** Charts use **`ChartFigure`** + **`ChartDataTable`**; **Edit layout** on toolbar; **`activeBar` / `activeShape`** keyboard styling from **`lib/chart-keyboard-selection`** — not opacity-only **`Cell`** hacks (§4.3).
592
638
  - [ ] **Dashboard layout persistence:** **`lib/data-view-dashboard-storage`** (or **`saveDashboardLayout`** / **`loadDashboardLayout`** on Placements); **`mergeDashboardLayout`** on load — no new ad-hoc storage keys for the same layout (§4.3).
593
639
  - [ ] **⌘K palette (§7.1):** If adding or changing **`dataGroups`**, map rows in **`lib/command-menu-search-data.ts`** (not `command-menu.tsx`); use **`searchOnly`** on bulky groups; keep **`docs/command-menu-pattern.md`** aligned.
594
- - [ ] **Page vs drawer vs dialog (§6.4):** Quick auxiliary with **parent context** and interactable hub → **drawer/sheet**; **blocking** short confirm → **dialog**; primary or long flows → **focused workflow route** or other dedicated page — **`docs/data-views-pattern.md`**, **`docs/drawer-vs-dialog-pattern.md`**, **`docs/focused-workflow-page-pattern.md`**.
640
+ - [ ] **Page vs drawer vs dialog (§6.4):** Quick auxiliary with **parent context** and interactable hub → **drawer/sheet**; **blocking** short confirm → **dialog**; primary or long flows → **new route** — **`docs/data-views-pattern.md`**, **`docs/drawer-vs-dialog-pattern.md`**.
595
641
  - [ ] **Cards vs rows:** Primary sortable hub with many homogeneous records → **`DataTable`**; kanban / visual tiles → **`ListPageBoardCard`** — **`docs/card-vs-rows-pattern.md`**, **`.cursor/rules/exxat-card-vs-list-rows.mdc`**.
596
642
  - [ ] **KPI count (max four):** **`entityKpiMetrics`** (and any static **`MetricItem[]`** for the same strip) has **≤ 4** tiles for template metrics + Data-tab key-metrics — **`docs/kpi-strip-max-four-pattern.md`**, **`.cursor/rules/exxat-kpi-max-four.mdc`**.
597
643
  - [ ] **No toast (§6.5):** No **`toast()`** / Sonner / snackbars — use banners, inline status, or dialogs.
@@ -603,29 +649,15 @@ Copy and complete when implementing or reviewing:
603
649
  - [ ] **Accessibility:** §8 — tablist/toolbar patterns, **≥24px** targets for icon-only controls, contrast on tinted surfaces, dialog/sheet/drawer **titles**; **every icon that communicates info has a text alternative** — adjacent label (preferred) OR `aria-label` + `Tooltip` (§8.6 Case A/B/C, covers informational icons like calendar-for-date, status dots, AND icon-only buttons); **kbd inside a button uses `<Kbd variant="bare">`** (§8.7); re-run **axe** on Placements when changing views toolbar.
604
650
  - [ ] **Coach marks (§11):** `CoachMark` + `useCoachMark`; register in **`coach-mark-registry`**; use **`enabled`** / **`dependsOnDismissedFlowId`** when a tour must wait for another flow or a specific view (e.g. **dashboard**); customize-dashboard flows use **`lib/dashboard-customize-coach-mark.ts`**.
605
651
  - [ ] **Application sidebar (§9.1):** **`ExxatProductLogo`** for product; **`logoDevUrl`** for schools; team switcher **`DropdownMenuContent`** keeps the explicit wide school/program surface (**`!w-max`** + min/max width); expanded switcher **`h-auto min-h-12`**; no **`CollapsibleTrigger` → `SidebarMenuButton` with `tooltip` prop**; child links **popover** on icon rail; profile **`stockPortraitUrl`** + **`referrerPolicy="no-referrer"`** on **`AvatarImage`**.
606
- - [ ] **Secondary panel (§4.6):** If **`NavLinkItem.secondaryPanel`** is set — **`PANELS[id]`** in **`secondary-panel.tsx`**, hub mounts **`useAutoPanel(id)`**, scope syncs to URL + **`tableState.rows`** — **`.cursor/rules/exxat-primary-nav-secondary-panel.mdc`**. Panel shell uses **`--secondary-panel-bg`** (brand OKLCH, not **`bg-sidebar`**) — **`docs/shell-surface-elevation-pattern.md`**. **Question bank folder scope:** header **⋯** → **Customize folder** + **`QuestionBankNewFolderSheet`** on **`QuestionBankClient`** — **`docs/question-bank-hub-header-pattern.md`**, **`.cursor/rules/exxat-question-bank-hub-header.mdc`**.
652
+ - [ ] **Secondary panel (§4.6):** If **`NavLinkItem.secondaryPanel`** is set — **`PANELS[id]`** in **`secondary-panel.tsx`**, hub mounts **`useAutoPanel(id)`**, scope syncs to URL + **`tableState.rows`** — **`.cursor/rules/exxat-primary-nav-secondary-panel.mdc`**. Panel shell uses **`--secondary-panel-bg`** (brand OKLCH, not **`bg-sidebar`**) — **`docs/shell-surface-elevation-pattern.md`**. **Library folder scope:** header **⋯** → **Customize folder** + **`LibraryNewFolderSheet`** on **`LibraryClient`** — **`docs/library-hub-header-pattern.md`**, **`.cursor/rules/exxat-library-hub-header.mdc`**.
607
653
  - [ ] **Flat KPI strip:** **`KeyMetrics variant="flat"`** — transparent cells, radial glow only, **`flatMetricsHairlineClass`** borders — **`docs/kpi-flat-band-pattern.md`**, **`.cursor/rules/exxat-kpi-flat-band.mdc`**.
608
654
  - [ ] **Collaboration & access (§4.7):** Shared hubs use **`variant="collaboration"`**, empty **Add collaborator** / non-empty face rail, **⋯ → Invite people**, **`CollaborationAccessFlow`** or **`InviteCollaboratorsDrawer`**, **`lib/collaborator-access.ts`**, roster **name → email → role tags** — **`.cursor/rules/exxat-collaboration-access.mdc`**.
609
655
  - [ ] **Dedicated search (§4.8):** Landing uses **`DedicatedSearchLandingTemplate`**; results use **`DedicatedSearchResultsHeaderChrome`** + outer **`DEDICATED_SEARCH_RESULTS_OUTER_CONTENT_CLASSNAME`**; **`DedicatedSearchUrlComposer`** + **`DedicatedSearchRecents`** with **`createDedicatedSearchRecentsController`** — **`.cursor/rules/exxat-dedicated-search-surfaces.mdc`**.
610
- - [ ] **KPI trends:** **`MetricItem.trend`** matches the delta direction; **`trendPolarity`** set for “more is worse” metrics (flags, defects, overdue) — **`docs/kpi-trend-pattern.md`**, **`.cursor/rules/exxat-kpi-trends.mdc`**.
656
+ - [ ] **KPI trends:** **`MetricItem.trend`** matches the delta direction; **`trendPolarity`** set for “more is worse” metrics (flags, defects, overdue); **`delta`** is a count (not prose) and is **left empty** when there is no comparison (chip is suppressed no `—` placeholder); supporting prose lives in **`MetricItem.description`** (renders below the value) — **`docs/kpi-trend-pattern.md`**, **`.cursor/rules/exxat-kpi-trends.mdc`**.
657
+ - [ ] **Person rails — no overlap:** Face rails / reviewer piles / collaborator stacks render avatars **side-by-side** with **`gap-1`** / **`gap-1.5`** (use **`AvatarGroup`** + **`AvatarGroupCount`** for **`+N`**); **MUST NOT** restore negative-margin overlap (`-space-x-*` + `*:ring-*`) — **`.cursor/rules/exxat-person-identity-display.mdc`**.
611
658
  - [ ] **Font Awesome:** New glyphs covered by **`fa:subset-audit`** / Kit subset; decorative **`<i>`** has **`aria-hidden`**; icon-only controls follow **§8.6** — **`.cursor/rules/exxat-fontawesome-icons.mdc`**.
612
659
  - [ ] **System IDs:** Visible **`questionId`**, record keys, and copy-pasteable identifiers use **`font-mono tabular-nums`**; mixed lines mono-wrap **only** the ID — **`.cursor/rules/exxat-mono-ids.mdc`**, **`.cursor/skills/exxat-mono-ids/SKILL.md`**.
613
660
 
614
661
  ---
615
662
 
616
- ## 14. AI execution checklist (focused workflow route)
617
-
618
- Copy and complete when implementing or reviewing a **dedicated form, wizard, or settings** page (not a list hub):
619
-
620
- - [ ] **`FocusedWorkflowPageTemplate`** on **`app/(app)/…/page.tsx`** — **`siteHeader`** with **`back`** or **`breadcrumbs`** + **`title`**.
621
- - [ ] **`maxWidth`**: **`md`** | **`lg`** | **`xl`** — not list-hub **`max-w-[1440px]`**.
622
- - [ ] **One body layout:** **`FocusedWorkflowSingleColumn`** | **`FocusedWorkflowStepForm`** | **`FocusedWorkflowSidebarSections`** | **`FocusedWorkflowEmptyState`**.
623
- - [ ] **Wizard / actions:** **`FocusedWorkflowWizardFooter`** or **`FocusedWorkflowActionFooter`** + **`Shortcut`** + **`<Kbd variant="bare">`** (**`exxat-kbd-shortcuts.mdc`**).
624
- - [ ] **Domain UI** in **`*-composer.tsx`** / **`*-client.tsx`**; **`FocusedWorkflow*`** names stay generic.
625
- - [ ] **No** **`ListPageTemplate`**, **no** **`ListPageFolderColumnsPanel`**, **no** Miller-column split explorer in this shell.
626
- - [ ] **No toast (§6.5)** for product feedback on this route.
627
- - [ ] **Reference:** **`/examples/focused-workflow`**, **`docs/focused-workflow-page-pattern.md`**, **`.cursor/skills/exxat-focused-workflow-page/SKILL.md`**.
628
-
629
- ---
630
-
631
- *Last updated: focused workflow page pattern + §14 checklist + rule/skill; KPI flat band + shell surface elevation; §4.6 secondary panel OKLCH; monospace system IDs; question bank folder header; drawer vs dialog / card vs rows / KPI max-four; §4.8 dedicated search; §4.7 collaboration; §4.1 centralized dataset; §4.5 view shells; Font Awesome; §9.1 sidebar; §4.4 board cards; §6.5 no toast; §7.1 command palette; §13 checklist.*
663
+ *Last updated: HubTable is the canonical hub primitive (raw DataTable only outside hubs); filter button tooltip nesting fix; KPI delta vs description (chip suppressed when empty) + no overlapping avatars (`AvatarGroup` is gapped, not negative-margin); KPI flat band + shell surface elevation pattern docs/rules/skills; §4.6 secondary panel OKLCH; monospace system IDs; library folder header; drawer vs dialog / card vs rows / KPI max-four; §4.8 dedicated search; §4.7 collaboration; §4.1 centralized dataset; §4.5 view shells; Font Awesome; §9.1 sidebar; §4.4 board cards; §6.5 no toast; §7.1 command palette; §13 checklist.*
@@ -0,0 +1,11 @@
1
+ import { Suspense } from "react"
2
+
3
+ import { ColumnsClient } from "@/components/columns-client"
4
+
5
+ export default function ColumnsPage() {
6
+ return (
7
+ <Suspense fallback={null}>
8
+ <ColumnsClient />
9
+ </Suspense>
10
+ )
11
+ }