@exxatdesignux/ui 0.2.18 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (618) hide show
  1. package/CHANGELOG.md +69 -1
  2. package/bin/sync-extras.mjs +116 -29
  3. package/consumer-extras/README.md +43 -4
  4. package/consumer-extras/cursor-rules/exxat-accessibility.mdc +39 -0
  5. package/consumer-extras/cursor-rules/exxat-board-cards.mdc +26 -0
  6. package/consumer-extras/cursor-rules/exxat-breadcrumbs-no-back.mdc +21 -0
  7. package/consumer-extras/cursor-rules/exxat-card-vs-list-rows.mdc +21 -0
  8. package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +44 -0
  9. package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +32 -0
  10. package/consumer-extras/cursor-rules/exxat-command-menu.mdc +22 -0
  11. package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +53 -0
  12. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +41 -0
  13. package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +25 -0
  14. package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +22 -0
  15. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +56 -0
  16. package/consumer-extras/cursor-rules/exxat-fontawesome-icons.mdc +31 -0
  17. package/consumer-extras/cursor-rules/exxat-kbd-shortcuts.mdc +100 -0
  18. package/consumer-extras/cursor-rules/exxat-kpi-flat-band.mdc +28 -0
  19. package/consumer-extras/cursor-rules/exxat-kpi-max-four.mdc +21 -0
  20. package/consumer-extras/cursor-rules/exxat-kpi-trends.mdc +31 -0
  21. package/consumer-extras/cursor-rules/exxat-list-page-connected-views.mdc +24 -0
  22. package/consumer-extras/cursor-rules/exxat-list-page-view-shells.mdc +31 -0
  23. package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +30 -0
  24. package/consumer-extras/cursor-rules/exxat-no-slds-leakage.mdc +78 -0
  25. package/consumer-extras/cursor-rules/exxat-no-toast.mdc +25 -0
  26. package/consumer-extras/cursor-rules/exxat-page-vs-drawer.mdc +23 -0
  27. package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +47 -0
  28. package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +52 -0
  29. package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +28 -0
  30. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +34 -0
  31. package/consumer-extras/cursor-rules/exxat-table-properties-drawer.mdc +77 -0
  32. package/consumer-extras/cursor-rules/exxat-token-discipline.mdc +103 -0
  33. package/consumer-extras/cursor-skills/exxat-accessibility/SKILL.md +1 -1
  34. package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
  35. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +1 -1
  36. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +9 -9
  37. package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +1 -1
  38. package/consumer-extras/handbook/HANDBOOK.md +185 -0
  39. package/consumer-extras/handbook/glossary.md +57 -0
  40. package/consumer-extras/handbook/reference-implementations.md +126 -0
  41. package/consumer-extras/handbook/voice-and-tone.md +262 -0
  42. package/consumer-extras/patterns/command-menu-pattern.md +1 -1
  43. package/consumer-extras/patterns/data-views-pattern.md +14 -14
  44. package/dist/components/data-table/filter-date-calendar.d.ts +10 -0
  45. package/dist/components/data-table/filter-date-calendar.js +280 -0
  46. package/dist/components/data-table/filter-date-calendar.js.map +1 -0
  47. package/dist/components/data-table/filter-text-value-input.d.ts +15 -0
  48. package/dist/components/data-table/filter-text-value-input.js +561 -0
  49. package/dist/components/data-table/filter-text-value-input.js.map +1 -0
  50. package/dist/components/data-table/index.d.ts +45 -0
  51. package/dist/components/data-table/index.js +3085 -0
  52. package/dist/components/data-table/index.js.map +1 -0
  53. package/dist/components/data-table/pagination.d.ts +28 -0
  54. package/dist/components/data-table/pagination.js +3264 -0
  55. package/dist/components/data-table/pagination.js.map +1 -0
  56. package/dist/components/data-table/types.d.ts +84 -0
  57. package/dist/components/data-table/types.js +3 -0
  58. package/dist/components/data-table/types.js.map +1 -0
  59. package/dist/components/data-table/use-table-state.d.ts +116 -0
  60. package/dist/components/data-table/use-table-state.js +670 -0
  61. package/dist/components/data-table/use-table-state.js.map +1 -0
  62. package/dist/components/data-views/board-card-primitives.d.ts +22 -0
  63. package/dist/components/data-views/board-card-primitives.js +84 -0
  64. package/dist/components/data-views/board-card-primitives.js.map +1 -0
  65. package/dist/components/data-views/data-row-list.d.ts +33 -0
  66. package/dist/components/data-views/data-row-list.js +106 -0
  67. package/dist/components/data-views/data-row-list.js.map +1 -0
  68. package/dist/components/data-views/finder-panel-view.d.ts +54 -0
  69. package/dist/components/data-views/finder-panel-view.js +388 -0
  70. package/dist/components/data-views/finder-panel-view.js.map +1 -0
  71. package/dist/components/data-views/folder-grid-view.d.ts +22 -0
  72. package/dist/components/data-views/folder-grid-view.js +58 -0
  73. package/dist/components/data-views/folder-grid-view.js.map +1 -0
  74. package/dist/components/data-views/hub-table.d.ts +167 -0
  75. package/dist/components/data-views/hub-table.js +5561 -0
  76. package/dist/components/data-views/hub-table.js.map +1 -0
  77. package/dist/components/data-views/index.d.ts +27 -0
  78. package/dist/components/data-views/index.js +6575 -0
  79. package/dist/components/data-views/index.js.map +1 -0
  80. package/dist/components/data-views/list-page-board-card.d.ts +72 -0
  81. package/dist/components/data-views/list-page-board-card.js +264 -0
  82. package/dist/components/data-views/list-page-board-card.js.map +1 -0
  83. package/dist/components/data-views/list-page-board-template.d.ts +24 -0
  84. package/dist/components/data-views/list-page-board-template.js +137 -0
  85. package/dist/components/data-views/list-page-board-template.js.map +1 -0
  86. package/dist/components/data-views/list-page-connected-view-body.d.ts +19 -0
  87. package/dist/components/data-views/list-page-connected-view-body.js +116 -0
  88. package/dist/components/data-views/list-page-connected-view-body.js.map +1 -0
  89. package/dist/components/data-views/list-page-split-details-placeholder.d.ts +14 -0
  90. package/dist/components/data-views/list-page-split-details-placeholder.js +38 -0
  91. package/dist/components/data-views/list-page-split-details-placeholder.js.map +1 -0
  92. package/dist/components/data-views/list-page-split-hub-chrome.d.ts +17 -0
  93. package/dist/components/data-views/list-page-split-hub-chrome.js +54 -0
  94. package/dist/components/data-views/list-page-split-hub-chrome.js.map +1 -0
  95. package/dist/components/data-views/list-page-split-hub-tokens.d.ts +12 -0
  96. package/dist/components/data-views/list-page-split-hub-tokens.js +8 -0
  97. package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -0
  98. package/dist/components/data-views/list-page-tree-column-header.d.ts +15 -0
  99. package/dist/components/data-views/list-page-tree-column-header.js +22 -0
  100. package/dist/components/data-views/list-page-tree-column-header.js.map +1 -0
  101. package/dist/components/data-views/list-page-tree-panel-shell.d.ts +25 -0
  102. package/dist/components/data-views/list-page-tree-panel-shell.js +146 -0
  103. package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -0
  104. package/dist/components/data-views/os-folder-glyph.d.ts +35 -0
  105. package/dist/components/data-views/os-folder-glyph.js +104 -0
  106. package/dist/components/data-views/os-folder-glyph.js.map +1 -0
  107. package/dist/components/data-views/outline-tree-menu.d.ts +36 -0
  108. package/dist/components/data-views/outline-tree-menu.js +131 -0
  109. package/dist/components/data-views/outline-tree-menu.js.map +1 -0
  110. package/dist/components/table-properties/column-row.d.ts +22 -0
  111. package/dist/components/table-properties/column-row.js +153 -0
  112. package/dist/components/table-properties/column-row.js.map +1 -0
  113. package/dist/components/table-properties/draggable-list.d.ts +24 -0
  114. package/dist/components/table-properties/draggable-list.js +53 -0
  115. package/dist/components/table-properties/draggable-list.js.map +1 -0
  116. package/dist/components/table-properties/drawer-button.d.ts +110 -0
  117. package/dist/components/table-properties/drawer-button.js +2748 -0
  118. package/dist/components/table-properties/drawer-button.js.map +1 -0
  119. package/dist/components/table-properties/drawer.d.ts +100 -0
  120. package/dist/components/table-properties/drawer.js +2595 -0
  121. package/dist/components/table-properties/drawer.js.map +1 -0
  122. package/dist/components/table-properties/filter-card.d.ts +24 -0
  123. package/dist/components/table-properties/filter-card.js +854 -0
  124. package/dist/components/table-properties/filter-card.js.map +1 -0
  125. package/dist/components/table-properties/index.d.ts +14 -0
  126. package/dist/components/table-properties/index.js +2768 -0
  127. package/dist/components/table-properties/index.js.map +1 -0
  128. package/dist/components/table-properties/sort-card.d.ts +20 -0
  129. package/dist/components/table-properties/sort-card.js +102 -0
  130. package/dist/components/table-properties/sort-card.js.map +1 -0
  131. package/dist/components/templates/dedicated-search-landing-template.d.ts +21 -0
  132. package/dist/components/templates/dedicated-search-landing-template.js +254 -0
  133. package/dist/components/templates/dedicated-search-landing-template.js.map +1 -0
  134. package/dist/components/templates/dedicated-search-results-template.d.ts +15 -0
  135. package/dist/components/templates/dedicated-search-results-template.js +16 -0
  136. package/dist/components/templates/dedicated-search-results-template.js.map +1 -0
  137. package/dist/components/templates/index.d.ts +9 -0
  138. package/dist/components/templates/index.js +2720 -0
  139. package/dist/components/templates/index.js.map +1 -0
  140. package/dist/components/templates/list-page.d.ts +83 -0
  141. package/dist/components/templates/list-page.js +2433 -0
  142. package/dist/components/templates/list-page.js.map +1 -0
  143. package/dist/components/templates/nested-secondary-panel-shell.d.ts +20 -0
  144. package/dist/components/templates/nested-secondary-panel-shell.js +54 -0
  145. package/dist/components/templates/nested-secondary-panel-shell.js.map +1 -0
  146. package/dist/components/ui/accordion.d.ts +10 -0
  147. package/dist/components/ui/accordion.js +74 -0
  148. package/dist/components/ui/accordion.js.map +1 -0
  149. package/dist/components/ui/alert-dialog.d.ts +37 -0
  150. package/dist/components/ui/alert-dialog.js +201 -0
  151. package/dist/components/ui/alert-dialog.js.map +1 -0
  152. package/dist/components/ui/avatar.d.ts +84 -0
  153. package/dist/components/ui/avatar.js +328 -0
  154. package/dist/components/ui/avatar.js.map +1 -0
  155. package/dist/components/ui/badge.d.ts +13 -0
  156. package/dist/components/ui/badge.js +49 -0
  157. package/dist/components/ui/badge.js.map +1 -0
  158. package/dist/components/ui/banner.d.ts +62 -0
  159. package/dist/components/ui/banner.js +364 -0
  160. package/dist/components/ui/banner.js.map +1 -0
  161. package/dist/components/ui/breadcrumb.d.ts +14 -0
  162. package/dist/components/ui/breadcrumb.js +114 -0
  163. package/dist/components/ui/breadcrumb.js.map +1 -0
  164. package/dist/components/ui/button.d.ts +16 -0
  165. package/dist/components/ui/button.js +59 -0
  166. package/dist/components/ui/button.js.map +1 -0
  167. package/dist/components/ui/calendar.d.ts +13 -0
  168. package/dist/components/ui/calendar.js +238 -0
  169. package/dist/components/ui/calendar.js.map +1 -0
  170. package/dist/components/ui/card.d.ts +14 -0
  171. package/dist/components/ui/card.js +102 -0
  172. package/dist/components/ui/card.js.map +1 -0
  173. package/dist/components/ui/chart.d.ts +58 -0
  174. package/dist/components/ui/chart.js +292 -0
  175. package/dist/components/ui/chart.js.map +1 -0
  176. package/dist/components/ui/checkbox.d.ts +23 -0
  177. package/dist/components/ui/checkbox.js +155 -0
  178. package/dist/components/ui/checkbox.js.map +1 -0
  179. package/dist/components/ui/coach-mark.d.ts +27 -0
  180. package/dist/components/ui/coach-mark.js +306 -0
  181. package/dist/components/ui/coach-mark.js.map +1 -0
  182. package/dist/components/ui/collapsible.d.ts +8 -0
  183. package/dist/components/ui/collapsible.js +35 -0
  184. package/dist/components/ui/collapsible.js.map +1 -0
  185. package/dist/components/ui/command.d.ts +36 -0
  186. package/dist/components/ui/command.js +274 -0
  187. package/dist/components/ui/command.js.map +1 -0
  188. package/dist/components/ui/context-menu.d.ts +32 -0
  189. package/dist/components/ui/context-menu.js +245 -0
  190. package/dist/components/ui/context-menu.js.map +1 -0
  191. package/dist/components/ui/date-picker-field.d.ts +38 -0
  192. package/dist/components/ui/date-picker-field.js +550 -0
  193. package/dist/components/ui/date-picker-field.js.map +1 -0
  194. package/dist/components/ui/dialog.d.ts +22 -0
  195. package/dist/components/ui/dialog.js +200 -0
  196. package/dist/components/ui/dialog.js.map +1 -0
  197. package/dist/components/ui/dot-pattern.d.ts +21 -0
  198. package/dist/components/ui/dot-pattern.js +139 -0
  199. package/dist/components/ui/dot-pattern.js.map +1 -0
  200. package/dist/components/ui/drag-handle-grip.d.ts +10 -0
  201. package/dist/components/ui/drag-handle-grip.js +15 -0
  202. package/dist/components/ui/drag-handle-grip.js.map +1 -0
  203. package/dist/components/ui/drawer.d.ts +16 -0
  204. package/dist/components/ui/drawer.js +125 -0
  205. package/dist/components/ui/drawer.js.map +1 -0
  206. package/dist/components/ui/dropdown-menu.d.ts +45 -0
  207. package/dist/components/ui/dropdown-menu.js +353 -0
  208. package/dist/components/ui/dropdown-menu.js.map +1 -0
  209. package/dist/components/ui/export-drawer.d.ts +11 -0
  210. package/dist/components/ui/export-drawer.js +1658 -0
  211. package/dist/components/ui/export-drawer.js.map +1 -0
  212. package/dist/components/ui/field.d.ts +30 -0
  213. package/dist/components/ui/field.js +249 -0
  214. package/dist/components/ui/field.js.map +1 -0
  215. package/dist/components/ui/form.d.ts +28 -0
  216. package/dist/components/ui/form.js +110 -0
  217. package/dist/components/ui/form.js.map +1 -0
  218. package/dist/components/ui/hover-card.d.ts +9 -0
  219. package/dist/components/ui/hover-card.js +43 -0
  220. package/dist/components/ui/hover-card.js.map +1 -0
  221. package/dist/components/ui/input-group.d.ts +20 -0
  222. package/dist/components/ui/input-group.js +219 -0
  223. package/dist/components/ui/input-group.js.map +1 -0
  224. package/dist/components/ui/input-mask.d.ts +39 -0
  225. package/dist/components/ui/input-mask.js +118 -0
  226. package/dist/components/ui/input-mask.js.map +1 -0
  227. package/dist/components/ui/input.d.ts +5 -0
  228. package/dist/components/ui/input.js +30 -0
  229. package/dist/components/ui/input.js.map +1 -0
  230. package/dist/components/ui/kbd.d.ts +20 -0
  231. package/dist/components/ui/kbd.js +45 -0
  232. package/dist/components/ui/kbd.js.map +1 -0
  233. package/dist/components/ui/key-metrics-context.d.ts +19 -0
  234. package/dist/components/ui/key-metrics-context.js +26 -0
  235. package/dist/components/ui/key-metrics-context.js.map +1 -0
  236. package/dist/components/ui/key-metrics.d.ts +131 -0
  237. package/dist/components/ui/key-metrics.js +1015 -0
  238. package/dist/components/ui/key-metrics.js.map +1 -0
  239. package/dist/components/ui/label.d.ts +6 -0
  240. package/dist/components/ui/label.js +28 -0
  241. package/dist/components/ui/label.js.map +1 -0
  242. package/dist/components/ui/list-page-view-frame.d.ts +22 -0
  243. package/dist/components/ui/list-page-view-frame.js +24 -0
  244. package/dist/components/ui/list-page-view-frame.js.map +1 -0
  245. package/dist/components/ui/page-header.d.ts +51 -0
  246. package/dist/components/ui/page-header.js +372 -0
  247. package/dist/components/ui/page-header.js.map +1 -0
  248. package/dist/components/ui/payment-card-fields.d.ts +10 -0
  249. package/dist/components/ui/payment-card-fields.js +80 -0
  250. package/dist/components/ui/payment-card-fields.js.map +1 -0
  251. package/dist/components/ui/popover.d.ts +10 -0
  252. package/dist/components/ui/popover.js +47 -0
  253. package/dist/components/ui/popover.js.map +1 -0
  254. package/dist/components/ui/radio-group.d.ts +29 -0
  255. package/dist/components/ui/radio-group.js +190 -0
  256. package/dist/components/ui/radio-group.js.map +1 -0
  257. package/dist/components/ui/resizable.d.ts +16 -0
  258. package/dist/components/ui/resizable.js +51 -0
  259. package/dist/components/ui/resizable.js.map +1 -0
  260. package/dist/components/ui/scroll-area.d.ts +8 -0
  261. package/dist/components/ui/scroll-area.js +66 -0
  262. package/dist/components/ui/scroll-area.js.map +1 -0
  263. package/dist/components/ui/select.d.ts +18 -0
  264. package/dist/components/ui/select.js +186 -0
  265. package/dist/components/ui/select.js.map +1 -0
  266. package/dist/components/ui/selection-tile-grid.d.ts +52 -0
  267. package/dist/components/ui/selection-tile-grid.js +347 -0
  268. package/dist/components/ui/selection-tile-grid.js.map +1 -0
  269. package/dist/components/ui/separator.d.ts +7 -0
  270. package/dist/components/ui/separator.js +33 -0
  271. package/dist/components/ui/separator.js.map +1 -0
  272. package/dist/components/ui/sheet.d.ts +18 -0
  273. package/dist/components/ui/sheet.js +181 -0
  274. package/dist/components/ui/sheet.js.map +1 -0
  275. package/dist/components/ui/sidebar.d.ts +94 -0
  276. package/dist/components/ui/sidebar.js +805 -0
  277. package/dist/components/ui/sidebar.js.map +1 -0
  278. package/dist/components/ui/skeleton.d.ts +5 -0
  279. package/dist/components/ui/skeleton.js +22 -0
  280. package/dist/components/ui/skeleton.js.map +1 -0
  281. package/dist/components/ui/slider.d.ts +7 -0
  282. package/dist/components/ui/slider.js +66 -0
  283. package/dist/components/ui/slider.js.map +1 -0
  284. package/dist/components/ui/sonner.d.ts +6 -0
  285. package/dist/components/ui/sonner.js +38 -0
  286. package/dist/components/ui/sonner.js.map +1 -0
  287. package/dist/components/ui/status-badge.d.ts +38 -0
  288. package/dist/components/ui/status-badge.js +77 -0
  289. package/dist/components/ui/status-badge.js.map +1 -0
  290. package/dist/components/ui/table.d.ts +13 -0
  291. package/dist/components/ui/table.js +115 -0
  292. package/dist/components/ui/table.js.map +1 -0
  293. package/dist/components/ui/tabs.d.ts +15 -0
  294. package/dist/components/ui/tabs.js +93 -0
  295. package/dist/components/ui/tabs.js.map +1 -0
  296. package/dist/components/ui/textarea.d.ts +6 -0
  297. package/dist/components/ui/textarea.js +25 -0
  298. package/dist/components/ui/textarea.js.map +1 -0
  299. package/dist/components/ui/tip.d.ts +12 -0
  300. package/dist/components/ui/tip.js +61 -0
  301. package/dist/components/ui/tip.js.map +1 -0
  302. package/dist/components/ui/toggle-group.d.ts +14 -0
  303. package/dist/components/ui/toggle-group.js +104 -0
  304. package/dist/components/ui/toggle-group.js.map +1 -0
  305. package/dist/components/ui/toggle-switch.d.ts +10 -0
  306. package/dist/components/ui/toggle-switch.js +33 -0
  307. package/dist/components/ui/toggle-switch.js.map +1 -0
  308. package/dist/components/ui/toggle.d.ts +13 -0
  309. package/dist/components/ui/toggle.js +51 -0
  310. package/dist/components/ui/toggle.js.map +1 -0
  311. package/dist/components/ui/tooltip.d.ts +10 -0
  312. package/dist/components/ui/tooltip.js +68 -0
  313. package/dist/components/ui/tooltip.js.map +1 -0
  314. package/dist/components/ui/view-segmented-control.d.ts +31 -0
  315. package/dist/components/ui/view-segmented-control.js +167 -0
  316. package/dist/components/ui/view-segmented-control.js.map +1 -0
  317. package/dist/data-list-view-registry-CyBoBML4.d.ts +73 -0
  318. package/dist/hooks/use-app-theme.d.ts +24 -0
  319. package/dist/hooks/use-app-theme.js +286 -0
  320. package/dist/hooks/use-app-theme.js.map +1 -0
  321. package/dist/hooks/use-coach-mark.d.ts +86 -0
  322. package/dist/hooks/use-coach-mark.js +218 -0
  323. package/dist/hooks/use-coach-mark.js.map +1 -0
  324. package/dist/hooks/use-mobile.d.ts +3 -0
  325. package/dist/hooks/use-mobile.js +29 -0
  326. package/dist/hooks/use-mobile.js.map +1 -0
  327. package/dist/hooks/use-mod-key-label.d.ts +6 -0
  328. package/dist/hooks/use-mod-key-label.js +25 -0
  329. package/dist/hooks/use-mod-key-label.js.map +1 -0
  330. package/dist/index.d.ts +120 -0
  331. package/dist/index.js +13324 -0
  332. package/dist/index.js.map +1 -0
  333. package/dist/lib/compose-refs.d.ts +6 -0
  334. package/dist/lib/compose-refs.js +17 -0
  335. package/dist/lib/compose-refs.js.map +1 -0
  336. package/dist/lib/conditional-rule-match.d.ts +30 -0
  337. package/dist/lib/conditional-rule-match.js +66 -0
  338. package/dist/lib/conditional-rule-match.js.map +1 -0
  339. package/dist/lib/data-list-display-options.d.ts +26 -0
  340. package/dist/lib/data-list-display-options.js +14 -0
  341. package/dist/lib/data-list-display-options.js.map +1 -0
  342. package/dist/lib/data-list-view-registry.d.ts +2 -0
  343. package/dist/lib/data-list-view-registry.js +102 -0
  344. package/dist/lib/data-list-view-registry.js.map +1 -0
  345. package/dist/lib/data-list-view-surface.d.ts +2 -0
  346. package/dist/lib/data-list-view-surface.js +80 -0
  347. package/dist/lib/data-list-view-surface.js.map +1 -0
  348. package/dist/lib/data-list-view.d.ts +21 -0
  349. package/dist/lib/data-list-view.js +25 -0
  350. package/dist/lib/data-list-view.js.map +1 -0
  351. package/dist/lib/date-filter.d.ts +22 -0
  352. package/dist/lib/date-filter.js +61 -0
  353. package/dist/lib/date-filter.js.map +1 -0
  354. package/dist/lib/dev-log.d.ts +8 -0
  355. package/dist/lib/dev-log.js +10 -0
  356. package/dist/lib/dev-log.js.map +1 -0
  357. package/dist/lib/dropdown-menu-surface.d.ts +14 -0
  358. package/dist/lib/dropdown-menu-surface.js +6 -0
  359. package/dist/lib/dropdown-menu-surface.js.map +1 -0
  360. package/dist/lib/editable-target.d.ts +12 -0
  361. package/dist/lib/editable-target.js +12 -0
  362. package/dist/lib/editable-target.js.map +1 -0
  363. package/dist/lib/list-page-table-properties.d.ts +35 -0
  364. package/dist/lib/list-page-table-properties.js +81 -0
  365. package/dist/lib/list-page-table-properties.js.map +1 -0
  366. package/dist/lib/raf-throttle.d.ts +23 -0
  367. package/dist/lib/raf-throttle.js +27 -0
  368. package/dist/lib/raf-throttle.js.map +1 -0
  369. package/dist/lib/row-height.d.ts +16 -0
  370. package/dist/lib/row-height.js +10 -0
  371. package/dist/lib/row-height.js.map +1 -0
  372. package/dist/lib/table-properties-types.d.ts +83 -0
  373. package/dist/lib/table-properties-types.js +19 -0
  374. package/dist/lib/table-properties-types.js.map +1 -0
  375. package/dist/lib/utils.d.ts +5 -0
  376. package/dist/lib/utils.js +11 -0
  377. package/dist/lib/utils.js.map +1 -0
  378. package/package.json +83 -18
  379. package/src/components/data-table/filter-date-calendar.tsx +38 -0
  380. package/src/components/data-table/filter-text-value-input.tsx +77 -0
  381. package/src/components/data-table/index.tsx +1678 -0
  382. package/src/components/data-table/pagination.tsx +255 -0
  383. package/src/components/data-table/types.ts +96 -0
  384. package/src/components/data-table/use-table-state.ts +767 -0
  385. package/src/components/data-views/board-card-primitives.tsx +93 -0
  386. package/src/components/data-views/data-row-list.tsx +183 -0
  387. package/src/components/data-views/finder-panel-view.tsx +405 -0
  388. package/src/components/data-views/folder-grid-view.tsx +86 -0
  389. package/src/components/data-views/hub-table.tsx +498 -0
  390. package/src/components/data-views/index.ts +28 -0
  391. package/src/components/data-views/list-page-board-card.tsx +192 -0
  392. package/src/components/data-views/list-page-board-template.tsx +122 -0
  393. package/src/components/data-views/list-page-connected-view-body.tsx +66 -0
  394. package/src/components/data-views/list-page-split-details-placeholder.tsx +39 -0
  395. package/src/components/data-views/list-page-split-hub-chrome.tsx +60 -0
  396. package/src/components/data-views/list-page-split-hub-tokens.ts +16 -0
  397. package/src/components/data-views/list-page-tree-column-header.tsx +31 -0
  398. package/src/components/data-views/list-page-tree-panel-shell.tsx +91 -0
  399. package/src/components/data-views/os-folder-glyph.tsx +141 -0
  400. package/src/components/data-views/outline-tree-menu.tsx +157 -0
  401. package/src/components/table-properties/column-row.tsx +90 -0
  402. package/src/components/table-properties/draggable-list.ts +54 -0
  403. package/src/components/table-properties/drawer-button.tsx +300 -0
  404. package/src/components/table-properties/drawer.tsx +1148 -0
  405. package/src/components/table-properties/filter-card.tsx +251 -0
  406. package/src/components/table-properties/index.ts +36 -0
  407. package/src/components/table-properties/sort-card.tsx +63 -0
  408. package/src/components/templates/dedicated-search-landing-template.tsx +124 -0
  409. package/src/components/templates/dedicated-search-results-template.tsx +19 -0
  410. package/src/components/templates/index.ts +33 -0
  411. package/src/components/templates/list-page.tsx +602 -0
  412. package/src/components/templates/nested-secondary-panel-shell.tsx +70 -0
  413. package/src/components/ui/accordion.tsx +92 -0
  414. package/src/components/ui/alert-dialog.tsx +221 -0
  415. package/src/components/ui/avatar.tsx +13 -2
  416. package/src/components/ui/banner.tsx +2 -2
  417. package/src/components/ui/calendar.tsx +1 -1
  418. package/src/components/ui/coach-mark.tsx +1 -1
  419. package/src/components/ui/context-menu.tsx +291 -0
  420. package/src/components/ui/date-picker-field.tsx +2 -2
  421. package/src/components/ui/dot-pattern.tsx +183 -0
  422. package/src/components/ui/export-drawer.tsx +375 -0
  423. package/src/components/ui/hover-card.tsx +66 -0
  424. package/src/components/ui/key-metrics-context.tsx +78 -0
  425. package/src/components/ui/key-metrics.tsx +1133 -0
  426. package/src/components/ui/list-page-view-frame.tsx +64 -0
  427. package/src/components/ui/page-header.tsx +244 -0
  428. package/src/components/ui/payment-card-fields.tsx +2 -2
  429. package/src/components/ui/resizable.tsx +68 -0
  430. package/src/components/ui/scroll-area.tsx +72 -0
  431. package/src/components/ui/selection-tile-grid.tsx +9 -2
  432. package/src/components/ui/sidebar.tsx +84 -12
  433. package/src/components/ui/slider.tsx +83 -0
  434. package/src/globals.css +494 -151
  435. package/src/globals.d.ts +20 -0
  436. package/src/index.ts +68 -1
  437. package/src/lib/conditional-rule-match.ts +119 -0
  438. package/src/lib/data-list-display-options.ts +35 -0
  439. package/src/lib/data-list-view-registry.ts +104 -0
  440. package/src/lib/data-list-view-surface.ts +83 -0
  441. package/src/lib/data-list-view.ts +47 -0
  442. package/src/lib/dev-log.ts +10 -0
  443. package/src/lib/editable-target.ts +20 -0
  444. package/src/lib/list-page-table-properties.ts +48 -0
  445. package/src/lib/raf-throttle.ts +45 -0
  446. package/src/lib/row-height.ts +19 -0
  447. package/src/lib/table-properties-types.ts +98 -0
  448. package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
  449. package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +3 -3
  450. package/template/.cursor/rules/exxat-data-tables.mdc +1 -1
  451. package/template/.cursor/rules/exxat-ds-agents.mdc +2 -2
  452. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +2 -2
  453. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
  454. package/template/AGENTS.md +84 -20
  455. package/template/app/(app)/examples/page.tsx +0 -1
  456. package/template/app/(app)/layout.tsx +17 -4
  457. package/template/app/(app)/question-bank/layout.tsx +1 -1
  458. package/template/app/(app)/question-bank/new/page.tsx +11 -24
  459. package/template/app/globals.css +13 -1972
  460. package/template/components/ask-leo-sidebar.tsx +5 -1
  461. package/template/components/brand-color-picker.tsx +2 -2
  462. package/template/components/charts-overview.tsx +1 -1
  463. package/template/components/compliance-table.tsx +240 -384
  464. package/template/components/dashboard-report-charts.tsx +1 -1
  465. package/template/components/dashboard-tabs.tsx +1 -1
  466. package/template/components/data-table/filter-date-calendar.tsx +1 -38
  467. package/template/components/data-table/filter-text-value-input.tsx +1 -77
  468. package/template/components/data-table/index.tsx +1 -1634
  469. package/template/components/data-table/pagination.tsx +1 -255
  470. package/template/components/data-table/types.ts +1 -94
  471. package/template/components/data-table/use-table-state.test.ts +420 -0
  472. package/template/components/data-table/use-table-state.ts +1 -758
  473. package/template/components/data-view-dashboard-charts-compliance.tsx +2 -2
  474. package/template/components/data-view-dashboard-charts-team.tsx +2 -2
  475. package/template/components/data-view-dashboard-charts.tsx +2 -2
  476. package/template/components/data-views/board-card-primitives.tsx +1 -93
  477. package/template/components/data-views/data-row-list.tsx +1 -183
  478. package/template/components/data-views/finder-panel-view.tsx +1 -405
  479. package/template/components/data-views/folder-grid-view.tsx +1 -86
  480. package/template/components/data-views/hub-table.tsx +1 -0
  481. package/template/components/data-views/index.ts +42 -1
  482. package/template/components/data-views/list-page-board-card.tsx +1 -192
  483. package/template/components/data-views/list-page-board-template.tsx +1 -122
  484. package/template/components/data-views/list-page-connected-view-body.tsx +1 -0
  485. package/template/components/data-views/list-page-split-details-placeholder.tsx +1 -39
  486. package/template/components/data-views/list-page-split-hub-chrome.tsx +1 -60
  487. package/template/components/data-views/list-page-split-hub-tokens.ts +1 -16
  488. package/template/components/data-views/list-page-tree-column-header.tsx +1 -31
  489. package/template/components/data-views/list-page-tree-panel-shell.tsx +1 -91
  490. package/template/components/data-views/list-page-view-frame.tsx +5 -53
  491. package/template/components/data-views/os-folder-glyph.tsx +1 -129
  492. package/template/components/data-views/outline-tree-menu.tsx +1 -157
  493. package/template/components/export-drawer.test.tsx +71 -0
  494. package/template/components/export-drawer.tsx +1 -375
  495. package/template/components/exxat-product-logo.tsx +5 -5
  496. package/template/components/hub-tree-panel-view.tsx +2 -2
  497. package/template/components/invite-collaborators-drawer.tsx +3 -3
  498. package/template/components/key-metrics-ask-leo-bridge.tsx +40 -0
  499. package/template/components/key-metrics.tsx +1 -1063
  500. package/template/components/leo-insight-indicator.tsx +2 -2
  501. package/template/components/new-placement-back-btn.tsx +1 -1
  502. package/template/components/new-placement-form.tsx +63 -189
  503. package/template/components/new-question-composer.tsx +432 -402
  504. package/template/components/onboarding/index.ts +9 -0
  505. package/template/components/onboarding/onboarding-01.tsx +1 -1
  506. package/template/components/onboarding/onboarding-02.tsx +1 -1
  507. package/template/components/onboarding/onboarding-03.tsx +1 -1
  508. package/template/components/onboarding/onboarding-04.tsx +1 -1
  509. package/template/components/page-header.tsx +8 -226
  510. package/template/components/placement-board-card.tsx +71 -83
  511. package/template/components/placements-board-view.tsx +3 -10
  512. package/template/components/placements-client.tsx +10 -42
  513. package/template/components/placements-list-view.tsx +22 -69
  514. package/template/components/placements-table-columns.tsx +8 -438
  515. package/template/components/placements-table.tsx +588 -1296
  516. package/template/components/product-switcher.tsx +1 -1
  517. package/template/components/product-wordmark.tsx +2 -1
  518. package/template/components/question-bank-client.tsx +4 -1
  519. package/template/components/question-bank-hub-client.tsx +1 -1
  520. package/template/components/question-bank-new-folder-sheet.tsx +2 -2
  521. package/template/components/question-bank-secondary-nav.tsx +3 -3
  522. package/template/components/question-bank-table.tsx +294 -526
  523. package/template/components/rotations-empty-state.tsx +1 -1
  524. package/template/components/rotations-panel-activator.tsx +1 -1
  525. package/template/components/settings-appearance-card.tsx +1 -1
  526. package/template/components/{app-sidebar-dynamic.tsx → sidebar/app-sidebar-dynamic.tsx} +1 -1
  527. package/template/components/{app-sidebar.tsx → sidebar/app-sidebar.tsx} +4 -4
  528. package/template/components/sidebar/index.ts +16 -0
  529. package/template/components/{secondary-nav.tsx → sidebar/secondary-nav.tsx} +2 -2
  530. package/template/components/{secondary-panel.tsx → sidebar/secondary-panel.tsx} +6 -3
  531. package/template/components/{sidebar-auto-collapse.tsx → sidebar/sidebar-auto-collapse.tsx} +6 -2
  532. package/template/components/{sidebar-shell.tsx → sidebar/sidebar-shell.tsx} +1 -1
  533. package/template/components/site-header.tsx +1 -1
  534. package/template/components/{sites-all-client.tsx → sites-client.tsx} +1 -1
  535. package/template/components/sites-table.tsx +124 -257
  536. package/template/components/table-properties/column-row.tsx +1 -90
  537. package/template/components/table-properties/draggable-list.ts +1 -49
  538. package/template/components/table-properties/drawer-button.tsx +1 -249
  539. package/template/components/table-properties/drawer.tsx +1 -1105
  540. package/template/components/table-properties/filter-card.tsx +1 -251
  541. package/template/components/table-properties/sort-card.tsx +1 -59
  542. package/template/components/table-properties/types.ts +28 -71
  543. package/template/components/team-table.tsx +242 -382
  544. package/template/components/templates/dedicated-search-landing-template.tsx +1 -124
  545. package/template/components/templates/dedicated-search-results-template.tsx +1 -19
  546. package/template/components/templates/list-page.tsx +1 -584
  547. package/template/components/templates/nested-secondary-panel-shell.tsx +1 -62
  548. package/template/components/templates/new-focus-template.tsx +659 -0
  549. package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
  550. package/template/components/ui/accordion.tsx +1 -0
  551. package/template/components/ui/alert-dialog.tsx +1 -0
  552. package/template/components/ui/context-menu.tsx +1 -0
  553. package/template/components/ui/dot-pattern.tsx +1 -183
  554. package/template/components/ui/hover-card.tsx +1 -0
  555. package/template/components/ui/resizable.tsx +1 -68
  556. package/template/components/ui/scroll-area.tsx +1 -0
  557. package/template/components/ui/slider.tsx +1 -0
  558. package/template/docs/blueprints/README.md +86 -0
  559. package/template/docs/blueprints/_template.md +91 -0
  560. package/template/docs/blueprints/board-card.md +123 -0
  561. package/template/docs/blueprints/data-table.md +139 -0
  562. package/template/docs/blueprints/key-metrics.md +128 -0
  563. package/template/docs/blueprints/list-page-template.md +123 -0
  564. package/template/docs/blueprints/page-header.md +130 -0
  565. package/template/docs/command-menu-pattern.md +1 -1
  566. package/template/docs/component-selection-guide.md +224 -0
  567. package/template/docs/components-audit-2026-05.md +158 -0
  568. package/template/docs/data-views-pattern.md +14 -14
  569. package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +95 -0
  570. package/template/docs/migrations/0002-exxat-token-namespace.md +154 -0
  571. package/template/docs/migrations/0003-globals-css-canonical.md +110 -0
  572. package/template/docs/migrations/README.md +100 -0
  573. package/template/docs/migrations/_template.md +64 -0
  574. package/template/docs/token-taxonomy.md +416 -0
  575. package/template/eslint.config.mjs +27 -0
  576. package/template/hooks/use-secondary-panel-hub-nav.ts +1 -1
  577. package/template/lib/command-menu-config.ts +0 -1
  578. package/template/lib/compliance-supported-views.ts +10 -0
  579. package/template/lib/conditional-rule-match.ts +6 -97
  580. package/template/lib/data-list-display-options.ts +1 -35
  581. package/template/lib/data-list-view-registry.ts +1 -0
  582. package/template/lib/data-list-view-surface.ts +1 -69
  583. package/template/lib/data-list-view.ts +1 -38
  584. package/template/lib/dev-log.ts +1 -8
  585. package/template/lib/editable-target.ts +1 -10
  586. package/template/lib/hub-connected-view-renderers.ts +58 -0
  587. package/template/lib/list-hub-supported-views.ts +10 -0
  588. package/template/lib/list-page-table-properties.ts +1 -52
  589. package/template/lib/mock/navigation.tsx +0 -8
  590. package/template/lib/mock/placements.ts +0 -7
  591. package/template/lib/placement-board-card-layout.ts +41 -41
  592. package/template/lib/placements-supported-views.ts +12 -0
  593. package/template/lib/question-bank-supported-views.ts +12 -0
  594. package/template/lib/raf-throttle.ts +1 -45
  595. package/template/lib/row-height.ts +4 -10
  596. package/template/lib/sidebar-state-cookie.ts +11 -2
  597. package/template/lib/sites-supported-views.ts +10 -0
  598. package/template/lib/team-supported-views.ts +10 -0
  599. package/template/package.json +1 -0
  600. package/template/tests/setup.ts +25 -0
  601. package/src/theme.css +0 -1132
  602. package/template/app/(app)/data-list/[id]/page.tsx +0 -44
  603. package/template/app/(app)/data-list/new/page.tsx +0 -34
  604. package/template/app/(app)/data-list/page.tsx +0 -10
  605. package/template/components/compliance-list-view.tsx +0 -54
  606. package/template/components/dashboard-onboarding-gallery.tsx +0 -13
  607. package/template/components/dashboard-onboarding.tsx +0 -21
  608. package/template/components/question-bank-list-view.tsx +0 -53
  609. package/template/components/section-cards.tsx +0 -106
  610. package/template/components/sites-list-view.tsx +0 -42
  611. package/template/components/team-list-view.tsx +0 -59
  612. package/template/lib/placement-lifecycle.ts +0 -5
  613. /package/template/components/{getting-started.tsx → onboarding/getting-started.tsx} +0 -0
  614. /package/template/components/{nav-documents.tsx → sidebar/nav-documents.tsx} +0 -0
  615. /package/template/components/{nav-main.tsx → sidebar/nav-main.tsx} +0 -0
  616. /package/template/components/{nav-secondary.tsx → sidebar/nav-secondary.tsx} +0 -0
  617. /package/template/components/{nav-user.tsx → sidebar/nav-user.tsx} +0 -0
  618. /package/template/components/{sidebar-auto-open.tsx → sidebar/sidebar-auto-open.tsx} +0 -0
@@ -0,0 +1,41 @@
1
+ ---
2
+ description: Exxat DS — product data tables must use DataTable with search, filters, and table properties; no alternate table stacks.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — data tables (mandatory pattern)
7
+
8
+ ## Use one stack for product data lists
9
+
10
+ For **any app screen that shows a browsable, filterable grid of records** (lists, directories, placements, tokens, columns showcase, etc.):
11
+
12
+ 1. **Inside `ListPageTemplate` (every primary hub + every showcase page that mounts a hub-style grid) MUST use `HubTable`** from `@/components/data-views`. `HubTable` is the **canonical** wrapper that wires `useTableState`, the toolbar (**search + filter chips + filter dropdown + sort**), the **Table properties drawer**, view-type tiles, bulk-actions, and conditional rules in one place. Pages that drop down to raw `<DataTable>` silently lose filters and Properties — **MUST NOT** ship a hub or showcase that way.
13
+ 2. **Outside `ListPageTemplate`** (rare — e.g. embedded mini-grids, modal sub-tables, drawer body lists), use `DataTable` from `@/components/data-table` directly. Even then, prefer composing a small `toolbarSlot` with `TablePropertiesDrawerButton` whenever the grid is more than a handful of rows.
14
+ 3. **Pagination:** Wrap with `DataTablePaginated` when server-style paging is required (Placements is the reference).
15
+ 4. **Search:** `HubTable` wires the toolbar search automatically; only consumers that pass `searchable={false}` to `displayOptionsInit` can opt out, and they MUST justify it in the call-site comment.
16
+ 5. **Filters:** Configure per-column `filter:` blocks in `ColumnDef` (text / select / date / number) — `HubTable` turns those into chips automatically via `columnsToFilterFields`. **MUST NOT** ship one-off filter inputs above the table that duplicate this.
17
+ 6. **Table properties:** Always reachable. `HubTable` mounts `TablePropertiesDrawerButton` in `toolbarSlot`; on **`ListPageTemplate`** pages with **table / list / board / dashboard** tabs it **MUST** also receive **`currentView`** and **`onViewChange`** (see **`apps/web/AGENTS.md` §4.2** and **`.cursor/rules/exxat-table-properties-drawer.mdc`**) so Properties matches the selected view.
18
+ 7. **Dropdown menus:** `DropdownMenuContent` uses the shared **`@exxatdesignux/ui`** default (**intrinsic `w-max`**, **`min-w-52`**, capped **`max-w`**) for view settings, row ⋯, column menus, and filter pickers — **pure CSS**, no **`ResizeObserver`**. Override only for deliberate narrow/wide rails (e.g. pagination **`w-20`**, account trigger-width, school switcher **`!w-max min-w-72 …`**). See **`docs/data-views-pattern.md`** (“Dropdown menus”).
19
+
20
+ **Reference implementations:**
21
+
22
+ - `components/placements-table.tsx` — full hub: paged table, board, dashboard, list, conditional rules, dashboard customize, bulk actions.
23
+ - `components/sites-table.tsx` — table + finder/board.
24
+ - `components/team-table.tsx` — table + dashboard + list.
25
+ - `components/columns-showcase.tsx` — minimal hub (single `table` view); good reference for showcase pages.
26
+ - `components/tokens-themes-client.tsx` — minimal hub + secondary panel scope.
27
+
28
+ ## Do not
29
+
30
+ - Do **not** build product list pages with `@/components/ui/table` alone, raw `<table>` markup, or third-party data grids.
31
+ - Do **not** mount raw `<DataTable>` inside `ListPageTemplate.renderContent` — use `HubTable`. Raw `<DataTable>` does not ship the Properties drawer or filter chips; users lose discoverability.
32
+ - Do **not** introduce a second “table component” pattern for the same product surfaces (splitting search/filters/properties across incompatible implementations).
33
+
34
+ ## Exceptions
35
+
36
+ - **Tiny, read-only tables inside charts or analytics cards** (e.g. chart figure captions / summary matrices) may use minimal markup when they are not primary data-list experiences — still prefer tokens and accessibility, but the full hub stack is not required there.
37
+ - **Drawer body and dialog sub-grids** (small, secondary, scoped to a transient flow) — raw `<DataTable>` is acceptable; still expose search if rows > ~10.
38
+
39
+ ## See also
40
+
41
+ - **`apps/web/AGENTS.md`** — full MUST/MUST NOT, list-page template, primary hubs, checklist.
@@ -0,0 +1,25 @@
1
+ # Exxat DS — dedicated search surfaces
2
+
3
+ **Authoritative detail:** **`apps/web/AGENTS.md` §4.8**, **`.cursor/skills/exxat-dedicated-search-surfaces/SKILL.md`**.
4
+
5
+ ## Intent
6
+
7
+ Some hubs use **one route** (or sibling routes) with **empty vs non-empty** primary search query:
8
+
9
+ - **Landing** — centered hero, composer, optional recents; no results grid (or minimal chrome).
10
+ - **Results** — `ListPageTemplate` + table/list driven by the same filtered row bag as the rest of the hub.
11
+
12
+ Shared building blocks use **generic** `DedicatedSearch*` names under `components/`, `components/templates/`, and `lib/dedicated-search-*.ts`. Domain code passes **`patchSearchParams`**, **recents controller**, and copy.
13
+
14
+ ## MUST
15
+
16
+ - Keep **first paint** of recents **storage-free** (no `localStorage` in `useState` initial state) — see skill.
17
+ - Prefer **`DedicatedSearchLandingTemplate`**, **`DedicatedSearchUrlComposer`**, **`DedicatedSearchRecents`**, **`DedicatedSearchResultsHeaderChrome`**, **`DEDICATED_SEARCH_RESULTS_OUTER_CONTENT_CLASSNAME`** before copying markup into a new hub.
18
+
19
+ ## MUST NOT
20
+
21
+ - Introduce parallel `*QuestionBankSearchLanding*` (or similar) components for another entity — extend the generic layer and compose in the hub client.
22
+
23
+ ## See also
24
+
25
+ - **`exxat-list-page-connected-views.mdc`**, **`exxat-centralized-list-dataset.mdc`** — results branch still uses one row bag + `ListPageTemplate`.
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: Exxat DS — drawer/sheet vs modal dialog vs route for flows and confirmations.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — drawer vs dialog
7
+
8
+ ## MUST
9
+
10
+ 1. **Drawer / sheet** — Hub-**adjacent** work where **parent context** (list, filters, selection) stays relevant: properties, export, invites, long option lists beside the grid.
11
+ 2. **Dialog** — **Blocking**, **short** focus: destructive confirm, legal/acknowledgment, single-step choice, alert when the user must not interact with the page behind until resolved.
12
+ 3. **Route** — **Primary**, **long**, or **bookmarkable** flows — **`AGENTS.md` §6.4**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**.
13
+
14
+ ## MUST NOT
15
+
16
+ - Put **irreversible delete** only in a dismissible toast — use **dialog** (or drawer with explicit confirm) per **`exxat-no-toast.mdc`**.
17
+ - Use a **centered dialog** for **wide tables of export columns** when a **drawer** matches mental model and space.
18
+
19
+ ## See also
20
+
21
+ - **`docs/drawer-vs-dialog-pattern.md`** · **`.cursor/skills/exxat-drawer-vs-dialog/SKILL.md`**
22
+ - **`exxat-page-vs-drawer.mdc`** (drawer vs **route**)
@@ -0,0 +1,56 @@
1
+ ---
2
+ description: Exxat DS — follow AGENTS.md; DataTable, ListPageTemplate, primary hubs, export, Kbd
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — AI handbook (binding)
7
+
8
+ **App location:** `apps/web/` in this **pnpm monorepo**. The legacy single-folder layout (`exxat-ds/`) was migrated in 2026-05; the path no longer exists. Shared design system lives at `packages/ui/` (`@exxatdesignux/ui`).
9
+
10
+ **Read `AGENTS.md`:** `apps/web/AGENTS.md` from the monorepo root, or `./AGENTS.md` when the workspace is the `apps/web/` folder only (same file).
11
+
12
+ Before implementing or reviewing **list / table / board / dashboard / data-heavy** pages, read **AGENTS.md** (rule precedence, MUST/MUST NOT, file references, §4.1–§4.8, **§6.4** page vs drawer, **§6.5** no toast, §7.1 command palette, §13 checklist). **Before** adding **new shared UI** not covered by existing **`components/`** patterns, read **`exxat-reuse-before-custom.mdc`**.
13
+
14
+ ## Non‑negotiables (if anything conflicts, open AGENTS.md §12–§13)
15
+
16
+ 1. **Product data lists** → `DataTable` + search + shared filters + `TablePropertiesDrawer` — not raw `<table>` / ui `Table` alone / ad-hoc grids. With **`ListPageTemplate`** view tabs, pass **`currentView`** + **`onViewChange`** into **`TablePropertiesDrawer`** (**`AGENTS.md` §4.2**, **`.cursor/rules/exxat-table-properties-drawer.mdc`**).
17
+ 2. **Main `DataTable` surface** → wrapped in **`ListPageTemplate`** (view tabs). All tab view types share **`useTableState`**; list/board/dashboard read **`tableState.rows`**. Reference: `PlacementsClient`, `TeamClient`, `TeamTable`, `ComplianceClient`.
18
+ 3. **Do not double-indent** the toolbar/table — avoid extra `px`/`mx` wrappers around `DataTable` when it already applies horizontal inset.
19
+ 4. **Primary hub + large/complex data** → same composition as Placements/Team: `ListPageTemplate` + metrics/export pattern as in `PlacementsClient` / `TeamClient`, not `PageHeader`-only. **Do not** ship empty or "replace later" placeholder pages for nav-linked hubs (**`AGENTS.md` §4.1**).
20
+ 5. **Exportable pages** → filled primary CTA; **⋯** menu with Export → `ExportDrawer` pattern (see `PlacementsPageHeader`).
21
+ 6. **Keyboard hints** → `.cursor/rules/exxat-kbd-shortcuts.mdc`; pair hints with behavior.
22
+ 7. **Accessibility** → `.cursor/rules/exxat-accessibility.mdc` + **`apps/web/AGENTS.md` §8** + `.cursor/skills/exxat-accessibility/SKILL.md`.
23
+ 8. **Data view dashboard charts** → **`apps/web/AGENTS.md` §4.3** + **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`** (centralized storage, `chart-keyboard-selection`, `ChartFigure`).
24
+ 9. **Board (kanban) cards** → **`apps/web/AGENTS.md` §4.4** + **`exxat-board-cards.mdc`** + **`.cursor/skills/exxat-board-cards/SKILL.md`** (`ListPageBoardCard`, **`ListHubStatusBadge`** + **`lib/list-status-badges.ts`**, primitives).
25
+ 10. **List-page view shells** (folder / panel / centered non-table bodies) → **`apps/web/AGENTS.md` §4.5** + **`exxat-list-page-view-shells.mdc`** + **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`** (`ListPageViewFrame`, **`components/data-views/`**).
26
+ 11. **Centralized hub dataset + presentation** — **`apps/web/AGENTS.md` §4.1** / **§4.5** + **`.cursor/rules/exxat-centralized-list-dataset.mdc`** + **`.cursor/skills/exxat-centralized-list-dataset/SKILL.md`** — one **`useTableState`** row bag for **all** views + **`TablePropertiesDrawer`**; **`ListPageViewFrame`** + **`data-views/`** for shared chrome; **no** parallel mock arrays per **`DataListViewType`**.
27
+ 12. **Font Awesome (product icons)** — **`.cursor/rules/exxat-fontawesome-icons.mdc`** — Kit in **`app/layout.tsx`**, **`fa-light` / `fa-solid`**, subset audit, **`aria-hidden`** on decorative **`<i>`**; pair with **`exxat-accessibility.mdc`** for icon-only controls.
28
+ 13. **Monospace system IDs** — **`apps/web/AGENTS.md` §1 (item 9)** + **`.cursor/rules/exxat-mono-ids.mdc`** + **`.cursor/skills/exxat-mono-ids/SKILL.md`** — **`font-mono tabular-nums`** on question/record keys; mono **only** the ID token in mixed lines.
29
+ 14. **Primary nav → secondary panel** (Question bank) — **`apps/web/AGENTS.md` §4.6** + **`.cursor/rules/exxat-primary-nav-secondary-panel.mdc`** — **`secondaryPanel`** + **`PANELS`** + **`useAutoPanel`**; **`--secondary-panel-bg`** brand elevation (**`apps/web/docs/shell-surface-elevation-pattern.md`**); **folder URL scope** → **`exxat-question-bank-hub-header.mdc`** + **`apps/web/docs/question-bank-hub-header-pattern.md`**.
30
+ 15. **Collaboration & access** (shared hubs) — **`apps/web/AGENTS.md` §4.7** + **`.cursor/rules/exxat-collaboration-access.mdc`** + **`.cursor/skills/exxat-collaboration-access/SKILL.md`** — face rail, **`InviteCollaboratorsDrawer`**, **`lib/collaborator-access.ts`**.
31
+ 16. **Dedicated search** (landing vs results, `DedicatedSearch*`) — **`apps/web/AGENTS.md` §4.8** + **`.cursor/rules/exxat-dedicated-search-surfaces.mdc`** + **`.cursor/skills/exxat-dedicated-search-surfaces/SKILL.md`**.
32
+ 17. **No toast** → **`apps/web/AGENTS.md` §6.5** + **`exxat-no-toast.mdc`** — do not use **`toast()`** / Sonner / snackbars for product messaging; use banners, inline status, or dialogs.
33
+ 18. **KPI trend polarity** (`KeyMetrics`, `*-kpi.ts`, chart mini-metrics) — **`docs/kpi-trend-pattern.md`** + **`.cursor/rules/exxat-kpi-trends.mdc`** + **`.cursor/skills/exxat-kpi-trends/SKILL.md`** — **`trend`** follows the data; set **`trendPolarity`** when “up” is not good news (e.g. defect counts, **low PBI flags**).
34
+ 19. **Drawer vs dialog** (same-route overlays) — **`docs/drawer-vs-dialog-pattern.md`** + **`.cursor/rules/exxat-drawer-vs-dialog.mdc`** + **`.cursor/skills/exxat-drawer-vs-dialog/SKILL.md`** — drawers preserve hub context; dialogs for **blocking** short confirms.
35
+ 20. **Cards vs table rows** — **`docs/card-vs-rows-pattern.md`** + **`.cursor/rules/exxat-card-vs-list-rows.mdc`** + **`.cursor/skills/exxat-card-vs-list-rows/SKILL.md`** — **`DataTable`** for dense comparable hubs; cards for kanban / visual browse (**`ListPageBoardCard`**).
36
+ 21. **KPI strip max four** — **`docs/kpi-strip-max-four-pattern.md`** + **`.cursor/rules/exxat-kpi-max-four.mdc`** + **`.cursor/skills/exxat-kpi-max-four/SKILL.md`** — **≤ 4** `MetricItem` per primary **`KeyMetrics`** strip / Data-tab key-metrics card (**`KEY_METRICS_KPI_COUNT_MAX`**).
37
+ 22. **KPI flat band** — **`docs/kpi-flat-band-pattern.md`** + **`.cursor/rules/exxat-kpi-flat-band.mdc`** + **`.cursor/skills/exxat-kpi-flat-band/SKILL.md`** — **`variant="flat"`**: transparent cells, OKLCH brand glow only, border hairlines (no grey panel).
38
+ 23. **Reuse before custom** — **`exxat-reuse-before-custom.mdc`** — compose from **`components/`** + **`AGENTS.md` §9**; **ask the user** before new shared primitives or bespoke widgets unless the task already approved greenfield.
39
+ 24. **Token discipline** — **`docs/token-taxonomy.md`** + **`.cursor/rules/exxat-token-discipline.mdc`** + **`packages/ui/tokens/hooks-index.json`** (163 tokens · 36 namespaces) — no hex literals in app code; no deprecated tokens; **prefer Exxat L0** (`--exxat-color-*`, `--exxat-radius-*`, `--exxat-spacing-*`) for new code (taxonomy §2.0 · rollout `docs/migrations/0002-exxat-token-namespace.md`); legacy L1 shadcn names stay as aliases. ESLint enforces via `exxat-ds/no-hex-color` + `exxat-ds/no-deprecated-tokens` in **`@exxatdesignux/eslint-plugin`** (workspace: **`packages/eslint-plugin-exxat-ds/`**).
40
+ 25. **No SLDS leakage** — **`.cursor/rules/exxat-no-slds-leakage.mdc`** — no `slds-*` classes, no `<lightning-*>` markup, no SLDS token names, no synthetic-shadow assumptions. ESLint catches via `exxat-ds/no-slds-classes` + `exxat-ds/no-lightning-elements` (from **`@exxatdesignux/eslint-plugin`**).
41
+ 26. **Blueprints + selection guide** — **`apps/web/docs/blueprints/`** + **`apps/web/docs/component-selection-guide.md`** — framework-agnostic specs + decision tree across the whole DS. Start there before composing a new hub.
42
+ 27. **Migrations** — **`apps/web/docs/migrations/`** — every deprecation gets a numbered entry (`NNNN-<slug>.md`). Token deprecations surface in `tokens/hooks-index.json` as `deprecated: true` and are lint-flagged.
43
+
44
+ ## Also read
45
+
46
+ - **`apps/web/docs/data-views-pattern.md`** — architecture narrative for list hubs. Includes **Page vs drawer** (§6.4 in `AGENTS.md`), **board UI** (§4.4), and **KPI trend polarity** → **`apps/web/docs/kpi-trend-pattern.md`**.
47
+ - **`apps/web/docs/command-menu-pattern.md`** — global ⌘K palette (search + quick AI vs Ask Leo).
48
+ - **`apps/web/docs/token-taxonomy.md`** — naming + deprecation policy for every CSS custom property the DS ships (semantic shadcn + brand / chip / chart / interactive / sidebar / control / radius / shadow / transition families).
49
+ - **`apps/web/docs/component-selection-guide.md`** — top-of-funnel decision tree for picking the right composition.
50
+ - **`apps/web/docs/blueprints/`** — framework-agnostic specs (start: `page-header.md`, `data-table.md`).
51
+ - **`apps/web/docs/migrations/`** — token rename + removal history.
52
+ - **`packages/ui/tokens/hooks-index.json`** — machine-readable token index (regenerate via `pnpm --filter @exxatdesignux/ui tokens:index`).
53
+ - `.cursor/rules/exxat-data-tables.mdc`, `exxat-list-page-connected-views.mdc`, **`exxat-centralized-list-dataset.mdc`**, **`exxat-list-page-view-shells.mdc`**, **`exxat-fontawesome-icons.mdc`**, **`exxat-mono-ids.mdc`**, **`exxat-primary-nav-secondary-panel.mdc`**, **`exxat-question-bank-hub-header.mdc`**, **`exxat-collaboration-access.mdc`**, **`exxat-dedicated-search-surfaces.mdc`**, **`exxat-kpi-trends.mdc`**, **`exxat-kpi-flat-band.mdc`**, **`exxat-drawer-vs-dialog.mdc`**, **`exxat-card-vs-list-rows.mdc`**, **`exxat-kpi-max-four.mdc`**, **`exxat-reuse-before-custom.mdc`**, `exxat-table-properties-drawer.mdc`, **`exxat-board-cards.mdc`**, **`exxat-page-vs-drawer.mdc`**, **`exxat-no-toast.mdc`**, **`exxat-command-menu.mdc`**, `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc` at repo root; **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`** for Data tab charts.
54
+ - **`apps/web/docs/kpi-flat-band-pattern.md`**, **`apps/web/docs/shell-surface-elevation-pattern.md`** — flat KPI strip + sidebar/secondary/page OKLCH stack.
55
+ - **`apps/web/docs/question-bank-hub-header-pattern.md`** — folder-scoped question bank header **Customize folder**.
56
+ - **`apps/web/docs/collaboration-access-pattern.md`** — shared hub face rail + invite sheet.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Font Awesome Pro icons — kit, weights, markup, subset audit, accessibility pairing
3
+ globs: apps/web/**/*.tsx
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Exxat DS — Font Awesome icons
8
+
9
+ Product UI uses **Font Awesome 6 Pro** via the **Kit script** in **`apps/web/app/layout.tsx`** (not per-page ad-hoc CDNs). **Authoritative accessibility pairing** for decorative vs informational vs icon-only controls: **`.cursor/rules/exxat-accessibility.mdc`** (Case A/B/C).
10
+
11
+ ## MUST
12
+
13
+ 1. **Markup** — Use **`<i className="…" />`** with **`fa-*`** weight + icon classes (e.g. **`fa-light fa-folder`**, **`fa-solid fa-check`**). Put **`aria-hidden="true"`** on the **`<i>`** when the **accessible name** lives on a parent (**`Button` `aria-label`**, adjacent text, **`Tip`** on interactive controls).
14
+ 2. **Weights** — Default inactive/ambient icons to **`fa-light`**; use **`fa-solid`** for **selected / active / strong emphasis** when the pattern already exists (e.g. sidebar rows, view tabs). Stay consistent within a surface.
15
+ 3. **Class strings** — Prefer **static** `className` strings so **`pnpm --filter web fa:subset-audit`** (see **`apps/web/scripts/fontawesome-subset-audit.mjs`**) can discover glyphs for **Kit subsetting** (`fontawesome-subset.manifest.json` → [fontawesome.com/kits](https://fontawesome.com/kits) Icon Selection).
16
+ 4. **Props APIs** — When a component accepts an icon, document **suffix only** (`fa-folder`) or **full classes** consistently with nearby code (**`lib/data-list-view.ts`**, **`lib/list-status-badges.ts`**, **`os-folder-glyph.tsx`**).
17
+
18
+ ## SHOULD
19
+
20
+ - After adding **new** Font Awesome glyph names, run **`fa:subset-audit`** and refresh the **Kit** subset so production does not 404 missing icons.
21
+ - Reuse **shared** maps (**`DATA_LIST_VIEW_TILES`**, **`lib/list-status-badges.ts`**) instead of one-off **`fa-*`** strings for the same semantic concept.
22
+
23
+ ## MUST NOT
24
+
25
+ - Add **second** icon systems for **product chrome** (duplicate Lucide/Phosphor/Heroicons for the same nav, table toolbar, or hub cards) when Font Awesome is already the standard for that surface.
26
+ - Put **meaningful** accessible names **only** on **`<i>`** without **`role`** / parent labelling — follow **Case B/C** in **`exxat-accessibility.mdc`**.
27
+
28
+ ## See also
29
+
30
+ - **`apps/web/AGENTS.md`** — handbook; **§8** accessibility.
31
+ - **`.cursor/rules/exxat-accessibility.mdc`** — tooltips + **`aria-label`** for icon-only buttons.
@@ -0,0 +1,100 @@
1
+ ---
2
+ description: Exxat DS — show Kbd hints on primary/secondary actions, search, Ask Leo; avoid browser-reserved chords.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — keyboard shortcuts (`Kbd`)
7
+
8
+ ## When to show `Kbd`
9
+
10
+ Use `@/components/ui/kbd` (`Kbd` + `KbdGroup`) anywhere users discover actions by hovering or reading tooltips:
11
+
12
+ - **Primary actions** — main page CTAs (e.g. “New …”, “Save”, “Submit”).
13
+ - **Secondary actions** — overflow menus, “More”, outline companions to a primary button.
14
+ - **Global affordances** — **Search** (table toolbar), **Ask Leo**, **Toggle sidebar**.
15
+
16
+ ## Rules
17
+
18
+ 0. **`Kbd` variant MUST match its host surface** (this is the #1 recurring mistake):
19
+
20
+ | Where the `Kbd` renders | Required variant |
21
+ |-------------------------|------------------|
22
+ | Inside a `Button` (primary, secondary, wizard Next/Back/Submit, full-width CTAs in popovers) | **`variant="bare"`** — no bg/border, inherits `currentColor` @ 70 % |
23
+ | Inside a `TooltipContent` | **default `tile`** (no prop) |
24
+ | Inside a `DropdownMenuItem` via `shortcut=` | menu handles it — pass the chord string |
25
+ | Standalone helper text on a surface | **default `tile`** |
26
+
27
+ Glue multi-key chords into **one** bare kbd (`<Kbd variant="bare">⌘⌥K</Kbd>`), not one tile per key. See `new-placement-form.tsx` (Next = `{mod}⏎`, Back = `{mod}{alt}←`) and the primary "Ask Leo" button inside chart insight popovers.
28
+
29
+ 1. **Pair hint with behavior** — If `Kbd` shows a chord, implement the same shortcut. **Preferred:** the shared primitives from `@/components/ui/dropdown-menu`:
30
+
31
+ ```tsx
32
+ import { DropdownMenuItem, Shortcut } from "@/components/ui/dropdown-menu"
33
+
34
+ // Visual hint in a menu item:
35
+ <DropdownMenuItem shortcut="⌘⇧E" onSelect={onExport}>Export</DropdownMenuItem>
36
+
37
+ // Global binding — render in a parent that stays mounted (menu items unmount on close):
38
+ <Shortcut keys="⌘⇧E" onInvoke={onExport} />
39
+ ```
40
+
41
+ The hook skips input/textarea/contenteditable targets and any open dialog. Accepts symbols (`⌘⇧⌥⌃⌫⌦⏎↑↓`) and words (`Cmd+Shift+D`, `Alt+P`). Avoid ad-hoc `document.addEventListener("keydown", …)` + `isEditableTarget` — use `<Shortcut>` instead.
42
+ 2. **Modifier labels** — Use `useModKeyLabel()` (**⌘** / **Ctrl**) and `useAltKeyLabel()` (**⌥** / **Alt**) from `@/hooks/use-mod-key-label` for tooltips.
43
+ 3. **Avoid browser-reserved chords** — Do **not** use combinations that match common browser defaults, including:
44
+ - **⌘⇧N / Ctrl+Shift+N** — private/incognito window
45
+ - **⌘⇧T / Ctrl+Shift+T** — reopen closed tab
46
+ - **⌘⇧O / Ctrl+Shift+O** — bookmark manager (Chromium)
47
+ - **⌘⇧B / Ctrl+Shift+B** — bookmarks bar
48
+ - **⌘L / Ctrl+L** — focus address bar (avoid plain **L** with only mod unless scoped)
49
+ - **⌃⌥L / Ctrl+Alt+L** — screen lock on many Linux desktops (avoid for in-app actions)
50
+ 4. **Preferred pattern for app shortcuts** — Use **⌘⌥** / **Ctrl+Alt** + letter (e.g. **⌘⌥N** for “New”, **⌘⌥M** for “More”, **⌘⌥K** for Ask Leo). Table search stays **⌘K** / **Ctrl+K** **without** Alt so **⌘⌥K** does not collide.
51
+ 5. **Tooltips** — `Tip` supports `label` as `React.ReactNode` so you can compose text + `KbdGroup`.
52
+ 6. **Do not** decorate every control — skip dense tables, icon-only row actions that already have `aria-label`, and third-party widgets.
53
+
54
+ ## Reference shortcuts (app)
55
+
56
+ | Action | Shortcut |
57
+ |--------|----------|
58
+ | Toggle main sidebar | ⌘/Ctrl + **B** (`components/ui/sidebar.tsx`) |
59
+ | Table search | ⌘/Ctrl + **K** (no Alt — `DataTable`) |
60
+ | Ask Leo | ⌘/Ctrl + **⌥/Alt** + **K** |
61
+ | New placement (Placements header) | ⌘/Ctrl + **⌥/Alt** + **N** |
62
+ | Placements overflow menu | ⌘/Ctrl + **⌥/Alt** + **M** |
63
+ | Export | ⌘/Ctrl + **⇧/Shift** + **E** |
64
+ | Hide/Show metric section | ⌘/Ctrl + **⌥/Alt** + **H** |
65
+ | Rename (view, tab) | **F2** |
66
+ | Duplicate | ⌘/Ctrl + **D** |
67
+ | Review / Info | ⌘/Ctrl + **I** |
68
+ | Remove / Delete | ⌘/Ctrl + **⌫** |
69
+ | Add view (1..n) | **1..9** (plain digit; skipped in inputs / open dialogs) |
70
+ | **Submit a workflow** (Create, Save, Export, Apply) | **Enter** (⏎) — scoped to the form/drawer/dialog |
71
+ | **Cancel / dismiss** a workflow | **Esc** (Radix handles for Dialog/Sheet) |
72
+ | **Advance a multi-step wizard** | ⌘/Ctrl + **Enter** (plain Enter stays in the input) |
73
+ | **Back** in a wizard | ⌘/Ctrl + **⌥/Alt** + **←** |
74
+
75
+ ## Every workflow primary/secondary action MUST carry shortcuts
76
+
77
+ Every **workflow surface** (form, dialog, drawer, sheet, multi-step wizard final step) MUST bind:
78
+
79
+ 1. **Primary action (submit/commit)** — **Enter** (⏎). Render the `<Kbd>⏎</Kbd>` **inline inside the button** (after the label, inside a `<KbdGroup className="ml-1.5">`) — NOT inside a hover `Tip`. Primary/secondary workflow buttons must expose the shortcut at rest so it is discoverable without hovering. Pair with a `<Shortcut keys="Enter" onInvoke={...}>` mounted while the surface is open. The shared `useShortcut` hook skips events from inputs/textarea/contenteditable, so Enter inside a text field still types normally — it only fires when focus is on the surface chrome.
80
+ 2. **Secondary action (Cancel/Dismiss)** — **Esc**. Inline `<Kbd>Esc</Kbd>` inside the Cancel button (same `ml-1.5` pattern). Radix `Dialog` / `Sheet` / `AlertDialog` already bind Esc natively.
81
+
82
+ > Tip-on-hover Kbd hints remain correct for **page-level** actions (e.g. "New placement", ⋯ overflow triggers) where the button is part of dense page chrome and a persistent Kbd would crowd the layout. Workflow buttons inside a form/drawer/dialog are spacious enough to render the Kbd inline.
83
+
84
+ **Variant inside a button:** always use `<Kbd variant="bare">` — no background, no border, inherits `currentColor` at 70% opacity. The default tile variant looks like a pasted-on patch on filled primary buttons. Glue multi-key chords into one `<Kbd variant="bare">⌘⌥←</Kbd>` rather than one tile per key.
85
+ 3. **Multi-step wizards** — plain **Enter** must NOT submit on intermediate steps (it would auto-close the review/final step when users hit Enter inside an input). Either:
86
+ - Gate `form.onSubmit` on `step === lastStep` (`if (step !== N) { e.preventDefault(); return }`), **or**
87
+ - Remove `type="submit"` on intermediate Next buttons and bind **⌘Enter** to "Next" via `<Shortcut>`.
88
+ On the final step, plain **Enter** submits and the Kbd hint shows **⏎**.
89
+ 4. Examples in-app: `new-placement-form.tsx` (Create placement = Enter on step 5, Back = ⌘⌥←), `export-drawer.tsx` (Export = Enter, Cancel = Esc).
90
+
91
+ ## Every action menu MUST carry shortcuts
92
+
93
+ All dropdown action menus (⋯ overflow, view-settings chevron, Add view, row actions) should declare a `shortcut=` on each `DropdownMenuItem` AND pair it with a `<Shortcut>` in a parent that stays mounted. This covers both discoverability (visual hint) and operability (global key binding).
94
+
95
+ Adjust this table when adding new global shortcuts.
96
+
97
+ ## See also
98
+
99
+ - **`apps/web/AGENTS.md`** §7 — keyboard rules in project context.
100
+ - **`apps/web/AGENTS.md`** §7.1 — global command palette (⌘K) vs **Ask Leo** (**⌘⌥K**); **`apps/web/docs/command-menu-pattern.md`**.
@@ -0,0 +1,28 @@
1
+ ---
2
+ description: KeyMetrics variant flat — transparent band, brand glow only, OKLCH hairlines
3
+ globs: apps/web/components/**/*key-metrics*,apps/web/app/globals.css,apps/web/docs/kpi*.md
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Exxat DS — KPI flat band (`variant="flat"`)
8
+
9
+ **Authoritative detail:** **`apps/web/docs/kpi-flat-band-pattern.md`**, **`.cursor/skills/exxat-kpi-flat-band/SKILL.md`**.
10
+
11
+ ## MUST
12
+
13
+ 1. **`KeyMetrics variant="flat"`** on list hubs / dashboard mix — **no** opaque band surface; section background is **only** `--key-metrics-flat-band-radial` (brand glow).
14
+ 2. **Cells** — **`bg-transparent`**; hairlines via **`flatMetricsHairlineClass`** (cell **borders**, not `gap-px` grid fill).
15
+ 3. **Four tiles** — default **4-across** verticals between columns; **2×2** hairlines only when `@container` is narrow (`@[max-width:29.99rem]`). **No** horizontal rule in 4-across layout.
16
+ 4. **OKLCH** — `--key-metrics-flat-divider`, glow stops via `color-mix(in oklch, var(--brand-color) …)`; divider uses `var(--sidebar-border)` mix. **Do not** hardcode rose/indigo on one product for all themes.
17
+ 5. **`--key-metrics-flat-band-shadow: none`** on flat band. **≤ 4** tiles — **`exxat-kpi-max-four.mdc`**.
18
+
19
+ ## MUST NOT
20
+
21
+ - Stack linear gradients, `bg-background` on cells, or `gap-px` + tinted grid background on flat KPI (reads as a grey/lavender **box**).
22
+ - Use **`variant="card"`** for **`ListPageTemplate`** metrics when the strip should sit on the page canvas.
23
+ - Reintroduce **`lg:border-l`** on insight column when `variant="flat"` (insight card ring is enough).
24
+
25
+ ## See also
26
+
27
+ - **`exxat-kpi-max-four.mdc`**, **`exxat-kpi-trends.mdc`**, **`exxat-list-page-connected-views.mdc`**
28
+ - **`exxat-primary-nav-secondary-panel.mdc`** — shell elevation (separate from KPI band)
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: Exxat DS — at most four KPI tiles on primary hub strips and key-metrics dashboard cards.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — KPI strip (max four)
7
+
8
+ ## MUST
9
+
10
+ 1. **Cap visible KPIs at four** on **`ListPageTemplate`** metric strips and on **Data tab** **`key-metrics`** dashboard cards — align with **`KEY_METRICS_KPI_COUNT_MAX`** in **`lib/dashboard-layout-merge.ts`** and **`clampKeyMetricsKpiCount`** when persisting layout.
11
+ 2. **KPI helpers** (`*-kpi.ts`) return **≤ 4** `MetricItem` entries for those surfaces, or **`.slice(0, 4)`** after prioritization.
12
+ 3. **Overflow narrative** — Push secondary stats into **`MetricInsight`**, charts, or another section — not a fifth headline tile.
13
+
14
+ ## MUST NOT
15
+
16
+ - Render **five or more** KPI tiles in a single **`KeyMetrics`** row/band meant as the **primary** summary for a hub or the **key-metrics** card.
17
+ - Raise **`KEY_METRICS_KPI_COUNT_MAX`** without design-system review.
18
+
19
+ ## See also
20
+
21
+ - **`docs/kpi-strip-max-four-pattern.md`** · **`docs/kpi-trend-pattern.md`** · **`docs/kpi-flat-band-pattern.md`** · **`.cursor/skills/exxat-kpi-max-four/SKILL.md`**
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Exxat DS — KPI deltas and trend arrows must be contextual; use trendPolarity when “up” is not good news.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — KPI trends (`KeyMetrics` + chart mini-metrics)
7
+
8
+ ## MUST
9
+
10
+ 1. **`trend` matches reality** — `up` / `down` / `neutral` reflects the **signed change** in the metric; arrows are not “spin for optimism”.
11
+ 2. **Set `trendPolarity` on `MetricItem`** when an increase is **not** favorable:
12
+ - **`lower_is_better`** — defect / error / overdue / **low PBI or quality-flag counts**, cost or time when the product goal is to **reduce**.
13
+ - **`informational`** — volume or mix where **direction is not** inherently good or bad (library size, % split between categories); tints stay **muted**, arrows still show direction.
14
+ 3. **Default** — Omitting `trendPolarity` means **`higher_is_better`** (legacy): up = positive tint, down = negative tint.
15
+ 4. **`delta` is a count, `description` is a caption.** **`delta`** (next to the arrow) is a **numeric change** like `"+5"`, `"-3"`, `"+12%"`. Contextual prose like `"left + right"`, `"vs last week"`, `"across 4 sites"` goes in **`MetricItem.description`** which renders **below** the value row (muted, small). **MUST NOT** stuff prose into **`delta`**.
16
+ 5. **Hide the trend chip when there is nothing to say.** If **`trend === "neutral"`** **and** **`delta`** is empty (`""` / `0` / unset), `KeyMetrics` suppresses the chip entirely — no `—` placeholder. Use **`description`** for the supporting caption instead. Only show the chip when the metric has a real direction (`up` / `down`) or a real count to surface.
17
+ 6. **Contextual copy** — `label` + `value` + (`delta` when present) + period header should read as one sentence; avoid orphan deltas.
18
+ 7. **Accessibility** — Do not rely on colour alone; keep delta text + icon; chip `aria-label` comes from **`metricTrendAriaQualifier`** in **`components/key-metrics.tsx`**.
19
+
20
+ ## MUST NOT
21
+
22
+ - Paint an **up** arrow with the “good” tint when the metric is **worse** when it goes up (unless **`trendPolarity: "lower_is_better"`** is set so “up” correctly tints **destructive**).
23
+ - Use **`ResizeObserver`** or JS layout measurement **only** to pick trend colours — polarity is a **product** decision, not a layout one.
24
+ - Render an **empty `—`** trend chip just to keep the layout symmetric. If a metric has no comparison this period, leave **`delta`** empty and let **`KeyMetrics`** hide the chip.
25
+ - Put words like **"left + right"**, **"hidden"**, **"shown"**, **"vs last week"** in **`delta`** — they are not deltas. Put them in **`description`**.
26
+
27
+ ## See also
28
+
29
+ - **`docs/kpi-trend-pattern.md`** (app) — narrative + table of examples.
30
+ - **`.cursor/skills/exxat-kpi-trends/SKILL.md`** — checklist for new hubs.
31
+ - **`components/key-metrics.tsx`** — `MetricTrendPolarity`, `metricTrendTone`, `metricTrendAriaQualifier`.
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: ListPageTemplate — shared table state across views, mock + KPI helpers, dashboard tab
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — list page connected views
7
+
8
+ **Authoritative detail:** **`apps/web/AGENTS.md` §4.1** and **`apps/web/docs/data-views-pattern.md`** (mock data, connected views, dashboard view).
9
+
10
+ ## When building `ListPageTemplate` + data client
11
+
12
+ 1. **One `useTableState` per tab’s table** — Pass full mock/API rows into a single table component; **`list` / `board` / `dashboard`** surfaces consume **`tableState.rows`** (same filters/search/sort as the grid).
13
+ 2. **`renderContent`** — Always pass **`view={tab.viewType}`**; use **`key={tab.id}`** (not `viewType`) so switching views does not reset table state. Pass **`onViewChange`** into the table component so **`TablePropertiesDrawer`** stays aligned (**`currentView`** + **`updateTab({ viewType, icon: dataListViewIcon(viewType) })`** — see **`apps/web/AGENTS.md` §4.2** and **`.cursor/rules/exxat-table-properties-drawer.mdc`**).
14
+ 3. **Mock data** — Typed arrays in **`lib/mock/<entity>.ts`**; KPI builders in **`lib/mock/<entity>-kpi.ts`** returning **`MetricItem[]`** / **`MetricInsight`** from **`@/components/key-metrics`**.
15
+ 4. **Dashboard view tab** — Use **`KeyMetrics`** (`variant="flat"` or `"card"`) and the **same** KPI functions with **`tableState.rows`**. Do **not** add standalone `Card` metric grids that duplicate those numbers. For chart-heavy dashboards reuse **`ChartsOverview`** / **`DashboardTabs`** patterns from the main dashboard route when appropriate.
16
+ 5. **List hub metrics strip** — Prefer **`KeyMetrics variant="flat"`** on **`ListPageTemplate`** **`metrics`** slot (transparent band, brand glow only) — **`docs/kpi-flat-band-pattern.md`**, **`.cursor/rules/exxat-kpi-flat-band.mdc`**.
17
+ 6. **MUST NOT** ship “not wired” / “switch to table” placeholders for list/board/dashboard when the stack supports those views.
18
+ 7. **MUST NOT** add a **primary nav** destination that is only placeholder copy with no **`ListPageTemplate`** hub, mock rows, and wired views — see **`apps/web/AGENTS.md` §4.1** (no empty hubs).
19
+
20
+ ## See also
21
+
22
+ - **`.cursor/rules/exxat-centralized-list-dataset.mdc`** — single **`tableState.rows`** source for every hub view, inspectors, and **`TablePropertiesDrawer`** on the same **`DataTable`**.
23
+ - **Centered view bodies + reusable shells:** **`apps/web/AGENTS.md` §4.5**, **`.cursor/rules/exxat-list-page-view-shells.mdc`**, **`ListPageViewFrame`** in **`components/data-views/list-page-view-frame.tsx`**.
24
+ - **Flat KPI band:** **`docs/kpi-flat-band-pattern.md`**, **`.cursor/rules/exxat-kpi-flat-band.mdc`**.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Exxat DS — centered reusable shells for list-page views (not page-specific markup)
3
+ globs: apps/web/components/**/*.tsx
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Exxat DS — list-page view shells (centered, reusable)
8
+
9
+ ## Intent
10
+
11
+ **View bodies** under `ListPageTemplate` (table, list, board, dashboard, **folder**, **panel**, and future view types) **MUST** share one **layout primitive** for horizontal gutter and optional **centered max-width** on wide viewports. **MUST NOT** copy `mx-4 lg:mx-6` + `mx-auto max-w-*` per feature file or bake view-only layout into a single route.
12
+
13
+ Domain logic (columns, tiles, folder trees) stays in **`*-table.tsx` / `*-client.tsx`**; **chrome and rhythm** use **`ListPageViewFrame`** from **`@/components/data-views/list-page-view-frame`** (re-exported from **`@/components/data-views`**). **Data** for those branches still comes from the **same** **`tableState.rows`** / hub state as the grid — see **`.cursor/rules/exxat-centralized-list-dataset.mdc`**.
14
+
15
+ ## MUST
16
+
17
+ 1. Wrap **non-`DataTable`** view branches (icon folder grid, OS-style explorer, empty folder states, comparable dashboard **sections** that are not the main grid) in **`ListPageViewFrame`**, passing **`maxWidthClassName`** when the design calls for a centered cap (defaults: **`LIST_PAGE_VIEW_FRAME_MAX_ICON_GRID`** (`max-w-6xl`), **`LIST_PAGE_VIEW_FRAME_MAX_WIDE`** (`max-w-7xl`)).
18
+ 2. Add **new reusable view surfaces** under **`components/data-views/`** with **generic props** (`rows`, `renderTile`, `getRowId`, etc.) — same pattern as **`FolderGridView`**, **`FinderPanelView`**, **`ListPageBoardTemplate`**. Page files **compose** them; they **MUST NOT** own grid/folder markup.
19
+ 3. When extracting an entity-specific view (e.g. question OS folders), plan a **generic** `*View` in **`data-views/`** plus a thin adapter if the product still needs typed mock wiring.
20
+
21
+ ## MUST NOT
22
+
23
+ - Wrap **`DataTable`** (or its outer toolbar shell) in **`ListPageViewFrame`** if that **duplicates** horizontal inset already applied by **`DataTable`** / **`DataTableToolbar`** — see **`AGENTS.md` §5** (double indent).
24
+ - Ship **view-only** layout classes only inside **`app/(app)/.../page.tsx`** for a hub that other entities will mirror — belong in **`data-views/`** or **`templates/`**.
25
+
26
+ ## See also
27
+
28
+ - **`apps/web/AGENTS.md` §4.5** — handbook table + constants.
29
+ - **`apps/web/docs/data-views-pattern.md`** — “View layout frame”.
30
+ - **`.cursor/rules/exxat-centralized-list-dataset.mdc`** — **`tableState.rows`** into every view branch.
31
+ - **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`** — step-by-step for agents.
@@ -0,0 +1,30 @@
1
+ ---
2
+ description: Exxat DS — monospace typography for record IDs, question IDs, and other system identifiers
3
+ globs: apps/web/**/*.tsx
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Exxat DS — monospace IDs
8
+
9
+ Use this when rendering **system identifiers** — values a user copies, searches, or matches in APIs and tables (not human-readable names or prose).
10
+
11
+ ## MUST
12
+
13
+ 1. **Class** — Wrap identifier text in **`font-mono tabular-nums`**. Add size/color from context: typically **`text-xs text-muted-foreground`** (secondary line, table meta) or **`text-sm`** when the ID is the primary label in a narrow cell.
14
+ 2. **What counts as an ID** — Question IDs (`questionId`, `Q-YYMM-XXXX`), record/entity keys shown in UI, folder/surface technical keys when displayed as identifiers, hex tokens in pickers, audit/log principals, site/row **`id`** columns meant for lookup.
15
+ 3. **Mixed lines** — When an ID sits beside prose (e.g. page subtitle), only the ID segment is mono; keep separators and labels in the default sans stack.
16
+
17
+ ## SHOULD
18
+
19
+ - Match existing hubs: **`question-bank-table.tsx`**, **`question-bank-list-view.tsx`**, **`new-question-composer.tsx`** (header subtitle), **`sites-table.tsx`** (`row.id`).
20
+ - Prefer **`truncate`** / **`min-w-0`** on mono IDs in tight layouts so long tokens do not blow out columns.
21
+
22
+ ## MUST NOT
23
+
24
+ - Apply **`font-mono`** to **person names**, **folder display names**, **status labels**, **dates**, **counts**, **currency**, or **body copy** — only the identifier token.
25
+ - Use mono for **option letters** (A/B/C) or **step numbers** unless they are literal system IDs.
26
+
27
+ ## See also
28
+
29
+ - **`.cursor/skills/exxat-mono-ids/SKILL.md`**
30
+ - **`apps/web/AGENTS.md`** — §1 item on IDs, §13 checklist
@@ -0,0 +1,78 @@
1
+ # Exxat DS — no SLDS leakage
2
+
3
+ **Context:** Some agents have access to other repos, including the **Salesforce
4
+ `design-system-2-starter-kit`** (LWC + SLDS 2 / Cosmos). Patterns there look
5
+ similar at a glance (`page-header`, `data-table`, `card`) but the
6
+ **implementations are not portable** — they assume LWC, synthetic shadow,
7
+ SLDS class systems, and the Salesforce platform.
8
+
9
+ This rule prevents accidental cross-pollination from any **Salesforce / SLDS**
10
+ codebase into **`apps/web`** or **`packages/ui`**.
11
+
12
+ ## MUST NOT
13
+
14
+ 1. **CSS class strings** — Do **not** introduce **`slds-*`** classes
15
+ (`slds-page-header`, `slds-m-around_*`, `slds-grid`, `slds-button`,
16
+ `slds-text-*`, etc.) anywhere in `apps/web/**` or `packages/ui/**`. The
17
+ Exxat stack is **Tailwind v4** + the token system documented in
18
+ [`apps/web/docs/token-taxonomy.md`](mdc:apps/web/docs/token-taxonomy.md).
19
+ 2. **LWC markup** — Do **not** render `<lightning-*>` tags
20
+ (`<lightning-button>`, `<lightning-datatable>`, `<lightning-card>`,
21
+ `<lightning-icon>`, etc.) or import from `lightning/*` modules. Use the
22
+ shadcn-style primitives in `packages/ui/src/components/ui/` and the
23
+ Exxat compositions in `apps/web/components/`.
24
+ 3. **Synthetic-shadow assumptions** — Do **not** call `template.querySelector`,
25
+ `slds-color-scheme_dark`, `shadowRoot === null` checks, or anything that
26
+ only makes sense under Salesforce synthetic shadow. The Next.js app uses
27
+ the real DOM + Radix portals.
28
+ 4. **SLDS styling-hook vars** — Do **not** use SLDS custom properties
29
+ (`--slds-g-color-surface-*`, `--slds-g-color-on-surface-*`,
30
+ `--slds-g-color-border-*`, `--slds-g-color-accent-*`, etc.). The Exxat
31
+ equivalents are documented in
32
+ [`apps/web/docs/token-taxonomy.md`](mdc:apps/web/docs/token-taxonomy.md):
33
+ surface → `--background` / `--card` / `--secondary-panel-bg`; ink →
34
+ `--foreground` / `--muted-foreground`; border → `--border` /
35
+ `--border-control` family; brand → `--brand-color` family.
36
+ 5. **SLDS theme switching** — Do **not** add UI for selecting "SLDS 1" vs
37
+ "SLDS 2". Exxat ships **Exxat One** (lavender) and **Exxat Prism** (rose)
38
+ themes via `.theme-one` / `.theme-prism` classes — see
39
+ `docs/shell-surface-elevation-pattern.md`.
40
+ 6. **Slot-vs-prop confusion** — Do **not** import LWC slot conventions
41
+ (`slot="actions"`, `<slot name="…">`) into React components. React uses
42
+ `children` + named props (`actions={…}`, `header={…}`).
43
+ 7. **`lightning-base-components` patterns inside React** — Do **not** add
44
+ per-page form-input wrappers like `lightning-input` clones. Use shadcn
45
+ `Input` / `Select` / `Combobox` from `packages/ui`.
46
+
47
+ ## SHOULD
48
+
49
+ - If you're comparing SLDS patterns to gain inspiration (e.g. the
50
+ `object-home` / `record-home` / `related-list` variant model from
51
+ `ui-page-header`), **document the idea** as a blueprint under
52
+ [`apps/web/docs/blueprints/`](mdc:apps/web/docs/blueprints) — do **not**
53
+ copy SLDS markup verbatim.
54
+ - For any "but SLDS does it this way" thought, check
55
+ [`apps/web/docs/component-selection-guide.md`](mdc:apps/web/docs/component-selection-guide.md)
56
+ first to see what Exxat ships for that pattern.
57
+
58
+ ## Why this rule exists
59
+
60
+ Salesforce's design system is excellent — but it is **built for a different
61
+ runtime** (LWC + synthetic shadow + classic SLDS layered with SLDS 2 /
62
+ Cosmos). Mixing its CSS class system into a Tailwind v4 + OKLCH token app
63
+ silently breaks:
64
+
65
+ - **Theming** — `slds-*` classes don't react to `.theme-prism` / `.dark` /
66
+ `[data-contrast="high"]`.
67
+ - **Accessibility** — SLDS 1 contrast ratios differ from Exxat's WCAG 2.1 AA
68
+ targets; mixing them produces unverifiable composites.
69
+ - **Bundling** — Importing `@salesforce-ux/design-system` would balloon the
70
+ Next.js bundle and pull in classic SLDS that we explicitly chose not to use.
71
+
72
+ ## See also
73
+
74
+ - [`apps/web/docs/token-taxonomy.md`](mdc:apps/web/docs/token-taxonomy.md) — Exxat tokens
75
+ - [`apps/web/docs/blueprints/`](mdc:apps/web/docs/blueprints) — framework-agnostic specs
76
+ - [`apps/web/docs/component-selection-guide.md`](mdc:apps/web/docs/component-selection-guide.md) — what to reach for
77
+ - [`.cursor/rules/exxat-token-discipline.mdc`](mdc:.cursor/rules/exxat-token-discipline.mdc) — token-level enforcement
78
+ - [`.cursor/rules/exxat-reuse-before-custom.mdc`](mdc:.cursor/rules/exxat-reuse-before-custom.mdc) — ask before adding new primitives
@@ -0,0 +1,25 @@
1
+ ---
2
+ description: Exxat DS — do not use toast / sonner / transient snackbars for product messaging.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — no toast
7
+
8
+ ## MUST NOT
9
+
10
+ - Do **not** use **`toast()`** (e.g. **Sonner**), **snackbar**, or other **transient corner notifications** for product feedback in this app.
11
+ - Do **not** add new imports from **`sonner`** or wire **`Toaster`** for feature surfaces.
12
+
13
+ ## Use instead
14
+
15
+ - **`LocalBanner`** / **`SystemBanner`** for persistent, readable messaging.
16
+ - **Inline status** next to the action (e.g. button label change, subtle text under the control, row-level state).
17
+ - **Dialog / drawer** confirmations when the user must acknowledge an outcome.
18
+
19
+ ## Why
20
+
21
+ Toasts are easy to miss, stack poorly with complex layouts, and behave inconsistently with screen readers and focus. This product standardizes on **banners + inline + dialogs**.
22
+
23
+ ## Authoritative detail
24
+
25
+ - **`apps/web/AGENTS.md` §6.5**
@@ -0,0 +1,23 @@
1
+ ---
2
+ description: Exxat DS — when to use a drawer vs a new page for actions and auxiliary UI.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — page vs drawer
7
+
8
+ ## Rule
9
+
10
+ - **Drawer / sheet** — Use when the user needs **the current page’s context** *and* a **quick view**, **quick actions**, or a **short auxiliary flow** (parent list or hub stays meaningful behind the panel).
11
+ - **Dialog (modal)** — Use for **blocking** short confirms/alerts on the **same route** when the hub must not stay interactable — see **`docs/drawer-vs-dialog-pattern.md`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
12
+ - **New page (route)** — Use **otherwise**: primary tasks, long-form or multi-step work, or anything that should have its **own URL** / history without the parent page visible.
13
+
14
+ ## Product examples (this repo)
15
+
16
+ - **Drawer-appropriate:** `TablePropertiesDrawer`, `ExportDrawer`, lightweight panels that supplement a hub.
17
+ - **Page-appropriate:** Full placement or settings flows that are the main task, multi-screen wizards.
18
+
19
+ ## Authoritative detail
20
+
21
+ - **`apps/web/AGENTS.md` §6.4**
22
+ - **`apps/web/docs/data-views-pattern.md`** (Page vs drawer)
23
+ - **`apps/web/docs/drawer-vs-dialog-pattern.md`** (drawer vs modal dialog)