@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,659 @@
1
+ "use client"
2
+
3
+ /**
4
+ * NewFocusTemplate — focused, single-task "New X" workflow shell.
5
+ *
6
+ * One template, three variants — pick the one that matches your task shape:
7
+ *
8
+ * 1. `variant="shell"` empty body slot — caller renders anything inside the
9
+ * hero header (title + description + Back link).
10
+ *
11
+ * 2. `variant="workflow"` multi-step wizard like New placement — `StepIndicator`,
12
+ * step content render-prop, sticky footer with progress
13
+ * dots + Back / Next / Submit buttons (Kbd hints + bound
14
+ * ⌘Enter / ⌘⌥← shortcuts).
15
+ *
16
+ * 3. `variant="form-inspector"` two-column layout (form left, sticky inspector right
17
+ * on lg+; stacks on mobile) — like New question composer.
18
+ * Inspector is collapsible via the caller's controlled
19
+ * open state.
20
+ *
21
+ * The template does NOT own form state. Callers wrap `<NewFocusTemplate>` in a
22
+ * `<form>` (or `<Form>` from `react-hook-form`) and pass step validators / submit
23
+ * handlers — this keeps the template framework-agnostic.
24
+ *
25
+ * IMPORTANT — `<form>` MUST flex inside the app shell row.
26
+ * `NewFocusTemplate` renders a `PrimaryPageTemplate` which renders a `SidebarInset`.
27
+ * The `SidebarInset` itself sits as a flex child of the `(app)/layout` row alongside
28
+ * the primary sidebar + secondary panel + Ask Leo rail and uses `w-full flex-1` to
29
+ * fill the remaining space. If the caller wraps `NewFocusTemplate` in a `<form>` (which
30
+ * is the canonical pattern for `react-hook-form`), the `<form>` itself becomes the flex
31
+ * child and `SidebarInset`'s `flex-1` no longer reaches the row. The page then
32
+ * collapses to its intrinsic content width and renders as a thin column with the rest
33
+ * of the viewport empty. ALWAYS apply `flex min-h-0 min-w-0 flex-1 flex-col` to the
34
+ * wrapping `<form>` so it behaves like a normal flex column host:
35
+ *
36
+ * ```tsx
37
+ * <form className="flex min-h-0 min-w-0 flex-1 flex-col" onSubmit={…}>
38
+ * <NewFocusTemplate variant="form-inspector" …>…</NewFocusTemplate>
39
+ * </form>
40
+ * ```
41
+ *
42
+ * See `new-placement-form.tsx` and `new-question-composer.tsx` for canonical usage.
43
+ *
44
+ * The template owns:
45
+ * • Page chrome (`PrimaryPageTemplate` underneath: `SidebarInset`, `SiteHeader`).
46
+ * • The hero `<h1>` + description + Back link.
47
+ * • For `workflow`: `StepIndicator`, step content render slot, sticky footer with
48
+ * keyboard-shortcut Kbd hints + bound `<Shortcut>` handlers (⌘Enter advance,
49
+ * ⌘⌥← back, plain Enter submit on final step).
50
+ * • For `form-inspector`: 2-column scaffold with sticky inspector rail.
51
+ *
52
+ * WCAG 2.1 AA — same rules as `new-placement-form` / `new-question-composer`:
53
+ * ✓ Hero `<h1>` carries the page title (only one h1 per route).
54
+ * ✓ Step indicator uses `aria-current="step"` and visible labels (1.3.1).
55
+ * ✓ Focus moves to step content when step changes (2.4.3).
56
+ * ✓ Submit/Cancel/Back/Next buttons carry inline Kbd hints + Shortcut bindings.
57
+ * ✓ Footer is sticky and contained within `<form>` so Enter on step 1..n-1 is no-op.
58
+ */
59
+
60
+ import * as React from "react"
61
+ import Link from "next/link"
62
+
63
+ import { cn } from "@/lib/utils"
64
+ import { Button } from "@/components/ui/button"
65
+ import { Kbd, KbdGroup } from "@/components/ui/kbd"
66
+ import { Shortcut } from "@/components/ui/dropdown-menu"
67
+ import { Tip } from "@/components/ui/tip"
68
+ import { useModKeyLabel, useAltKeyLabel } from "@/hooks/use-mod-key-label"
69
+ import { SidebarAutoCollapse } from "@/components/sidebar"
70
+ import {
71
+ PrimaryPageTemplate,
72
+ type PrimaryPageTemplateProps,
73
+ } from "@/components/templates/primary-page-template"
74
+
75
+ // ─── Shared types ────────────────────────────────────────────────────────────
76
+
77
+ interface BackLink {
78
+ href: string
79
+ label?: string
80
+ ariaLabel?: string
81
+ }
82
+
83
+ interface NewFocusBaseProps {
84
+ /** Page `<h1>` text. */
85
+ title: string
86
+ /** Subhead below the title — short sentence describing the task. */
87
+ description?: React.ReactNode
88
+ /** Back link rendered above the hero (and as `siteHeader.back` if `useSiteHeaderBack`). */
89
+ back: BackLink
90
+ /**
91
+ * When `true`, the parent route's `SiteHeader` carries the back-icon (parent-link only;
92
+ * no hero back link rendered). Mirrors `NewQuestionPage` which passes `back` to `SiteHeader`.
93
+ * Default `false` — Back link is rendered inline above the hero (matches `new-record/page`).
94
+ */
95
+ useSiteHeaderBack?: boolean
96
+ /**
97
+ * Replace the default hero (Back link + `<h1>` + description) with a fully custom node.
98
+ * Use this when the page needs a `PageHeader`-style chrome (subtitle / actions / row),
99
+ * e.g. New question composer with Save / More actions. Title and description props are
100
+ * ignored when `header` is provided.
101
+ */
102
+ header?: React.ReactNode
103
+ /**
104
+ * Render alongside the default hero `<h1>` as right-aligned actions (filled CTA + overflow).
105
+ * Ignored when `header` is provided.
106
+ */
107
+ headerActions?: React.ReactNode
108
+ /**
109
+ * Optional ID-style subtitle rendered below the `<h1>` in lieu of `description`. Use this
110
+ * for stable record identifiers (e.g. draft question id + version).
111
+ */
112
+ headerSubtitle?: React.ReactNode
113
+ /** Override the `PrimaryPageTemplate` max-width. Default: `max-w-3xl` (workflow / shell), `max-w-[1100px]` (form-inspector). */
114
+ maxWidthClassName?: string
115
+ /** Extra classes for the `PrimaryPageTemplate` body wrapper. Default sets `overflow-y-auto`. */
116
+ bodyClassName?: string
117
+ /** Extra classes for the `PrimaryPageTemplate` content column. */
118
+ contentClassName?: string
119
+ /** Optional extra chrome rendered before `SiteHeader` (e.g. command-menu). `SidebarAutoCollapse` is included by default. */
120
+ beforeSiteHeader?: React.ReactNode
121
+ /** Customize the `siteHeader` props passed to `PrimaryPageTemplate`. */
122
+ siteHeader?: PrimaryPageTemplateProps["siteHeader"]
123
+ }
124
+
125
+ // ─── Variant 1: shell ────────────────────────────────────────────────────────
126
+
127
+ interface ShellVariantProps extends NewFocusBaseProps {
128
+ variant: "shell"
129
+ /** Body content rendered below the hero. */
130
+ children: React.ReactNode
131
+ }
132
+
133
+ // ─── Variant 2: workflow ─────────────────────────────────────────────────────
134
+
135
+ export interface NewFocusStep {
136
+ /** Stable identifier for the step (used as React key + `STEP_FIELDS` map key). */
137
+ id: string
138
+ /** Short label shown under the step circle (e.g. "Student"). */
139
+ label: string
140
+ /** Optional Font Awesome glyph (e.g. `fa-user-graduate`) shown in the section heading. */
141
+ icon?: string
142
+ /** Render the step body. Receives the active step index (0-based). */
143
+ render: (ctx: { stepIndex: number; isActive: boolean }) => React.ReactNode
144
+ }
145
+
146
+ interface WorkflowVariantProps extends NewFocusBaseProps {
147
+ variant: "workflow"
148
+ /** Ordered step list. Length must be ≥ 1. */
149
+ steps: NewFocusStep[]
150
+ /** Active step (0-based). The caller owns this state so a step can be reached via review-section "Edit". */
151
+ step: number
152
+ /** Called when the user clicks a step circle directly (jump). Optional — omit to disable jumps. */
153
+ onStepChange?: (next: number) => void
154
+ /**
155
+ * Called when Next / ⌘Enter is invoked. Caller validates the current step's fields and
156
+ * returns `true` if advance should proceed. Async-friendly for `react-hook-form` triggers.
157
+ */
158
+ onNext: () => boolean | Promise<boolean>
159
+ /** Called when the form is submitted on the final step. */
160
+ onSubmit: () => void | Promise<void>
161
+ /** Label on the final-step submit button (e.g. "Create placement"). */
162
+ submitLabel: string
163
+ /** Optional icon glyph for the submit button (defaults to `fa-check`). */
164
+ submitIcon?: string
165
+ /** Disable inputs / show spinner when `true`. */
166
+ submitting?: boolean
167
+ /** Override the Next button label. Default `"Next"`. */
168
+ nextLabel?: string
169
+ /** Override the Back button label. Default `"Back"`. */
170
+ backLabel?: string
171
+ /** Scroll to top of window when step changes. Default `true`. */
172
+ scrollOnStepChange?: boolean
173
+ }
174
+
175
+ // ─── Variant 3: form-inspector ───────────────────────────────────────────────
176
+
177
+ interface FormInspectorVariantProps extends NewFocusBaseProps {
178
+ variant: "form-inspector"
179
+ /** Form body rendered in the left column. */
180
+ children: React.ReactNode
181
+ /**
182
+ * Inspector body rendered in the right rail (sticky on lg+).
183
+ * Either a static node (template handles open/close by toggling visibility) OR a render
184
+ * function that receives `{ open }` so the caller can render different content in collapsed
185
+ * state (e.g. show a single "Open inspector" button when `!open`). Use the function form
186
+ * when the caller's inspector has its own internal show/hide affordance.
187
+ */
188
+ inspector: React.ReactNode | ((ctx: { open: boolean }) => React.ReactNode)
189
+ /** `true` → inspector expanded; `false` → collapsed to a rail with an "Open" affordance. */
190
+ inspectorOpen: boolean
191
+ /** Called when the toolbar inspector toggle is clicked. */
192
+ onInspectorOpenChange: (open: boolean) => void
193
+ /** Width of the inspector rail when open. Default `"320px"`. */
194
+ inspectorOpenWidth?: string
195
+ /** Width of the inspector rail when collapsed. Default `"3.5rem"` (~56px). */
196
+ inspectorCollapsedWidth?: string
197
+ /** Accessible label on the inspector `<aside>`. Default `"Inspector"`. */
198
+ inspectorAriaLabel?: string
199
+ /**
200
+ * Hide the built-in inspector toggle (sidebar-flip icon). Use this when the caller renders
201
+ * its own toggle in the header actions or inside the inspector body itself
202
+ * (e.g. New question composer routes the toggle through a "More actions" overflow menu).
203
+ */
204
+ hideInspectorToggle?: boolean
205
+ }
206
+
207
+ // ─── Union ───────────────────────────────────────────────────────────────────
208
+
209
+ export type NewFocusTemplateProps =
210
+ | ShellVariantProps
211
+ | WorkflowVariantProps
212
+ | FormInspectorVariantProps
213
+
214
+ // ─── Step indicator (workflow variant) ───────────────────────────────────────
215
+
216
+ function StepIndicator({
217
+ steps,
218
+ current,
219
+ onStepClick,
220
+ }: {
221
+ steps: NewFocusStep[]
222
+ current: number
223
+ onStepClick?: (i: number) => void
224
+ }) {
225
+ return (
226
+ <nav aria-label="Form steps" className="mb-8">
227
+ <ol className="flex items-center">
228
+ {steps.map((step, idx) => {
229
+ const isCompleted = idx < current
230
+ const isActive = idx === current
231
+ const isLast = idx === steps.length - 1
232
+ const Circle = (
233
+ <div
234
+ aria-current={isActive ? "step" : undefined}
235
+ className={cn(
236
+ "flex size-9 items-center justify-center rounded-full border-2 text-xs font-semibold transition-all",
237
+ isCompleted && "border-emerald-600 bg-emerald-600 text-white",
238
+ isActive && "border-brand bg-brand/10 text-brand",
239
+ !isCompleted && !isActive && "border-border bg-muted/40 text-muted-foreground",
240
+ )}
241
+ >
242
+ {isCompleted ? (
243
+ <i className="fa-light fa-check text-xs" aria-hidden="true" />
244
+ ) : (
245
+ <span>{idx + 1}</span>
246
+ )}
247
+ <span className="sr-only">
248
+ Step {idx + 1}: {step.label}
249
+ {isCompleted ? " (completed)" : isActive ? " (current)" : ""}
250
+ </span>
251
+ </div>
252
+ )
253
+ return (
254
+ <React.Fragment key={step.id}>
255
+ <li className="flex flex-col items-center gap-1.5 shrink-0">
256
+ {onStepClick && isCompleted ? (
257
+ <button
258
+ type="button"
259
+ onClick={() => onStepClick(idx)}
260
+ className="cursor-pointer rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
261
+ aria-label={`Go to step ${idx + 1}: ${step.label}`}
262
+ >
263
+ {Circle}
264
+ </button>
265
+ ) : (
266
+ Circle
267
+ )}
268
+ <span
269
+ className={cn(
270
+ "hidden sm:block text-xs whitespace-nowrap",
271
+ isActive && "text-foreground font-medium",
272
+ isCompleted && "text-emerald-600 font-medium",
273
+ !isCompleted && !isActive && "text-muted-foreground",
274
+ )}
275
+ aria-hidden="true"
276
+ >
277
+ {step.label}
278
+ </span>
279
+ </li>
280
+ {!isLast && (
281
+ <div
282
+ aria-hidden="true"
283
+ className={cn(
284
+ "flex-1 h-0.5 mx-2 mb-5 rounded-full transition-colors",
285
+ idx < current ? "bg-emerald-600" : "bg-border",
286
+ )}
287
+ />
288
+ )}
289
+ </React.Fragment>
290
+ )
291
+ })}
292
+ </ol>
293
+ </nav>
294
+ )
295
+ }
296
+
297
+ // ─── Hero block (shared) ─────────────────────────────────────────────────────
298
+
299
+ function NewFocusHero({
300
+ title,
301
+ description,
302
+ back,
303
+ showInlineBack,
304
+ actions,
305
+ subtitle,
306
+ }: {
307
+ title: string
308
+ description?: React.ReactNode
309
+ back: BackLink
310
+ showInlineBack: boolean
311
+ actions?: React.ReactNode
312
+ subtitle?: React.ReactNode
313
+ }) {
314
+ const hasActions = actions != null
315
+ return (
316
+ <>
317
+ {showInlineBack ? (
318
+ <Link
319
+ href={back.href}
320
+ className="inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-interactive-hover-foreground transition-colors mb-5 group"
321
+ aria-label={back.ariaLabel ?? `Back to ${back.label ?? "previous page"}`}
322
+ >
323
+ <i
324
+ className="fa-light fa-arrow-left text-xs transition-transform group-hover:-translate-x-0.5"
325
+ aria-hidden="true"
326
+ />
327
+ {back.label ?? "Back"}
328
+ </Link>
329
+ ) : null}
330
+ <div
331
+ className={cn(
332
+ hasActions
333
+ ? "mb-8 flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between lg:gap-6"
334
+ : "",
335
+ )}
336
+ >
337
+ <div className={cn(hasActions ? "min-w-0" : "")}>
338
+ <h1
339
+ className="text-[2.25rem] font-semibold tracking-tight leading-none text-foreground mb-2"
340
+ style={{ fontFamily: "var(--font-heading)" }}
341
+ >
342
+ {title}
343
+ </h1>
344
+ {subtitle ? (
345
+ <p className="text-sm text-muted-foreground">{subtitle}</p>
346
+ ) : null}
347
+ {description ? (
348
+ <p
349
+ className={cn(
350
+ "text-sm text-muted-foreground",
351
+ hasActions || subtitle ? "" : "mb-8",
352
+ )}
353
+ >
354
+ {description}
355
+ </p>
356
+ ) : null}
357
+ </div>
358
+ {hasActions ? (
359
+ <div className="flex shrink-0 items-center gap-2">{actions}</div>
360
+ ) : null}
361
+ </div>
362
+ </>
363
+ )
364
+ }
365
+
366
+ // ─── Body renderers ──────────────────────────────────────────────────────────
367
+
368
+ function ShellBody({ children }: { children: React.ReactNode }) {
369
+ return <>{children}</>
370
+ }
371
+
372
+ function WorkflowBody(props: WorkflowVariantProps) {
373
+ const {
374
+ steps,
375
+ step,
376
+ onStepChange,
377
+ onNext,
378
+ onSubmit,
379
+ submitLabel,
380
+ submitIcon = "fa-check",
381
+ submitting = false,
382
+ nextLabel = "Next",
383
+ backLabel = "Back",
384
+ scrollOnStepChange = true,
385
+ } = props
386
+
387
+ const lastIndex = steps.length - 1
388
+ const isFinal = step === lastIndex
389
+ const stepHeadingRef = React.useRef<HTMLDivElement>(null)
390
+ const mod = useModKeyLabel()
391
+ const alt = useAltKeyLabel()
392
+
393
+ React.useEffect(() => {
394
+ stepHeadingRef.current?.focus()
395
+ }, [step])
396
+
397
+ const handleNextClick = React.useCallback(async () => {
398
+ const ok = await onNext()
399
+ if (!ok) return
400
+ onStepChange?.(Math.min(step + 1, lastIndex))
401
+ if (scrollOnStepChange) {
402
+ window.scrollTo({ top: 0, behavior: "smooth" })
403
+ }
404
+ }, [onNext, onStepChange, step, lastIndex, scrollOnStepChange])
405
+
406
+ const handleBackClick = React.useCallback(() => {
407
+ onStepChange?.(Math.max(step - 1, 0))
408
+ if (scrollOnStepChange) {
409
+ window.scrollTo({ top: 0, behavior: "smooth" })
410
+ }
411
+ }, [onStepChange, step, scrollOnStepChange])
412
+
413
+ const handleSubmitClick = React.useCallback(() => {
414
+ void onSubmit()
415
+ }, [onSubmit])
416
+
417
+ return (
418
+ <>
419
+ {/*
420
+ Steps 1..n-1: ⌘Enter advances. Final step: ⌘Enter submits — plain Enter is
421
+ intentionally NOT bound globally; a global Enter shortcut would fire when focus
422
+ is on the step container (we focus it after each step for a11y), submitting
423
+ without an explicit submit action ("Review auto-closes" bug). Native Enter on
424
+ the submit button still submits the wrapping `<form>` on the final step.
425
+ */}
426
+ {!isFinal && (
427
+ <Shortcut keys="⌘Enter" disabled={submitting} onInvoke={handleNextClick} />
428
+ )}
429
+ {isFinal && (
430
+ <Shortcut keys="⌘Enter" disabled={submitting} onInvoke={handleSubmitClick} />
431
+ )}
432
+ {step > 0 && (
433
+ <Shortcut keys="⌘⌥←" disabled={submitting} onInvoke={handleBackClick} />
434
+ )}
435
+
436
+ <StepIndicator
437
+ steps={steps}
438
+ current={step}
439
+ onStepClick={onStepChange ? (i) => onStepChange(i) : undefined}
440
+ />
441
+
442
+ <div ref={stepHeadingRef} tabIndex={-1} className="outline-none">
443
+ {steps[step]?.render({ stepIndex: step, isActive: true })}
444
+ </div>
445
+
446
+ <div className="sticky bottom-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-t border-border flex items-center justify-between mt-8 py-4">
447
+ <div className="flex items-center gap-1.5" aria-hidden="true">
448
+ {steps.map((s, i) => (
449
+ <div
450
+ key={s.id}
451
+ className={cn(
452
+ "rounded-full transition-all h-1.5",
453
+ i === step ? "w-6 bg-brand" : i < step ? "w-3 bg-brand/40" : "w-3 bg-border",
454
+ )}
455
+ />
456
+ ))}
457
+ </div>
458
+
459
+ <div className="flex items-center gap-2">
460
+ <Button
461
+ type="button"
462
+ variant="outline"
463
+ onClick={handleBackClick}
464
+ disabled={step === 0 || submitting}
465
+ >
466
+ <i className="fa-light fa-arrow-left text-[13px]" aria-hidden="true" />
467
+ {backLabel}
468
+ <KbdGroup className="ms-1.5">
469
+ <Kbd variant="bare">
470
+ {mod}
471
+ {alt}←
472
+ </Kbd>
473
+ </KbdGroup>
474
+ </Button>
475
+
476
+ {!isFinal ? (
477
+ <Button type="button" onClick={handleNextClick} disabled={submitting}>
478
+ {nextLabel}
479
+ <i className="fa-light fa-arrow-right text-[13px]" aria-hidden="true" />
480
+ <KbdGroup className="ms-1.5">
481
+ <Kbd variant="bare">{mod}⏎</Kbd>
482
+ </KbdGroup>
483
+ </Button>
484
+ ) : (
485
+ <Button type="submit" disabled={submitting} aria-busy={submitting}>
486
+ {submitting ? (
487
+ <>
488
+ <i className="fa-light fa-spinner-third fa-spin text-[13px]" aria-hidden="true" />
489
+ Saving…
490
+ </>
491
+ ) : (
492
+ <>
493
+ <i className={`fa-light ${submitIcon} text-[13px]`} aria-hidden="true" />
494
+ {submitLabel}
495
+ <KbdGroup className="ms-1.5">
496
+ <Kbd variant="bare">{mod}⏎</Kbd>
497
+ </KbdGroup>
498
+ </>
499
+ )}
500
+ </Button>
501
+ )}
502
+ </div>
503
+ </div>
504
+ </>
505
+ )
506
+ }
507
+
508
+ function FormInspectorBody(props: FormInspectorVariantProps) {
509
+ const {
510
+ children,
511
+ inspector,
512
+ inspectorOpen,
513
+ onInspectorOpenChange,
514
+ inspectorOpenWidth = "320px",
515
+ inspectorCollapsedWidth = "3.5rem",
516
+ inspectorAriaLabel = "Inspector",
517
+ hideInspectorToggle = false,
518
+ } = props
519
+
520
+ return (
521
+ <div
522
+ className={cn(
523
+ "grid grid-cols-1 transition-[gap,grid-template-columns] duration-200 lg:grid-cols-[minmax(0,1fr)_var(--inspector-w)]",
524
+ inspectorOpen ? "lg:gap-x-10" : "lg:gap-x-4",
525
+ )}
526
+ style={
527
+ {
528
+ "--inspector-w": inspectorOpen ? inspectorOpenWidth : inspectorCollapsedWidth,
529
+ } as React.CSSProperties
530
+ }
531
+ >
532
+ <div className="min-w-0">{children}</div>
533
+
534
+ <aside
535
+ aria-label={inspectorAriaLabel}
536
+ className="mt-8 lg:mt-0 lg:sticky lg:top-4 lg:self-start lg:h-fit min-w-0"
537
+ >
538
+ {hideInspectorToggle ? null : (
539
+ <div className="mb-3 flex items-center justify-end">
540
+ <Tip
541
+ side="left"
542
+ label={inspectorOpen ? "Hide inspector" : "Show inspector"}
543
+ >
544
+ <Button
545
+ variant="ghost"
546
+ size="icon"
547
+ className="size-7"
548
+ onClick={() => onInspectorOpenChange(!inspectorOpen)}
549
+ aria-label={inspectorOpen ? "Hide inspector" : "Show inspector"}
550
+ aria-expanded={inspectorOpen}
551
+ >
552
+ <i
553
+ className={cn(
554
+ "fa-light text-sm",
555
+ inspectorOpen ? "fa-sidebar-flip" : "fa-sidebar",
556
+ )}
557
+ aria-hidden="true"
558
+ />
559
+ </Button>
560
+ </Tip>
561
+ </div>
562
+ )}
563
+ {typeof inspector === "function"
564
+ ? inspector({ open: inspectorOpen })
565
+ : inspectorOpen
566
+ ? inspector
567
+ : null}
568
+ </aside>
569
+ </div>
570
+ )
571
+ }
572
+
573
+ // ─── Public component ───────────────────────────────────────────────────────
574
+
575
+ function defaultMaxWidth(variant: NewFocusTemplateProps["variant"]): string {
576
+ switch (variant) {
577
+ case "form-inspector":
578
+ return "mx-auto w-full max-w-[1100px]"
579
+ case "workflow":
580
+ return "max-w-3xl"
581
+ case "shell":
582
+ default:
583
+ return "max-w-3xl"
584
+ }
585
+ }
586
+
587
+ function defaultContentClass(variant: NewFocusTemplateProps["variant"]): string {
588
+ switch (variant) {
589
+ case "form-inspector":
590
+ return "px-8 py-4 pb-16"
591
+ case "workflow":
592
+ case "shell":
593
+ default:
594
+ return "px-8 pt-10 pb-32"
595
+ }
596
+ }
597
+
598
+ function defaultBodyClass(variant: NewFocusTemplateProps["variant"]): string {
599
+ switch (variant) {
600
+ case "form-inspector":
601
+ return "min-h-0 flex-1 overflow-y-auto overscroll-y-contain"
602
+ case "workflow":
603
+ case "shell":
604
+ default:
605
+ return "overflow-y-auto"
606
+ }
607
+ }
608
+
609
+ export function NewFocusTemplate(props: NewFocusTemplateProps) {
610
+ const {
611
+ variant,
612
+ title,
613
+ description,
614
+ back,
615
+ useSiteHeaderBack = false,
616
+ header,
617
+ headerActions,
618
+ headerSubtitle,
619
+ maxWidthClassName,
620
+ bodyClassName,
621
+ contentClassName,
622
+ beforeSiteHeader,
623
+ siteHeader,
624
+ } = props
625
+
626
+ const computedSiteHeader = useSiteHeaderBack
627
+ ? { back: { href: back.href, label: back.label ?? "Back", ariaLabel: back.ariaLabel } as const, ...(siteHeader ?? {}) }
628
+ : siteHeader
629
+
630
+ return (
631
+ <PrimaryPageTemplate
632
+ beforeSiteHeader={
633
+ <>
634
+ <SidebarAutoCollapse />
635
+ {beforeSiteHeader}
636
+ </>
637
+ }
638
+ siteHeader={computedSiteHeader}
639
+ maxWidthClassName={maxWidthClassName ?? defaultMaxWidth(variant)}
640
+ bodyClassName={bodyClassName ?? defaultBodyClass(variant)}
641
+ contentClassName={contentClassName ?? defaultContentClass(variant)}
642
+ >
643
+ {header ?? (
644
+ <NewFocusHero
645
+ title={title}
646
+ description={description}
647
+ back={back}
648
+ showInlineBack={!useSiteHeaderBack}
649
+ actions={headerActions}
650
+ subtitle={headerSubtitle}
651
+ />
652
+ )}
653
+
654
+ {variant === "shell" ? <ShellBody>{props.children}</ShellBody> : null}
655
+ {variant === "workflow" ? <WorkflowBody {...props} /> : null}
656
+ {variant === "form-inspector" ? <FormInspectorBody {...props} /> : null}
657
+ </PrimaryPageTemplate>
658
+ )
659
+ }
@@ -1,7 +1,7 @@
1
1
  import * as React from "react"
2
2
 
3
3
  import { PrimaryPageTemplate, type PrimaryPageTemplateProps } from "@/components/templates/primary-page-template"
4
- import { useAutoPanel } from "@/components/secondary-panel"
4
+ import { useAutoPanel } from "@/components/sidebar"
5
5
 
6
6
  export interface SecondaryPanelHubActivatorProps {
7
7
  panelId: string
@@ -0,0 +1 @@
1
+ export * from "@exxatdesignux/ui/components/accordion"
@@ -0,0 +1 @@
1
+ export * from "@exxatdesignux/ui/components/alert-dialog"
@@ -0,0 +1 @@
1
+ export * from "@exxatdesignux/ui/components/context-menu"