@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,183 @@
1
+ "use client"
2
+
3
+ /**
4
+ * DotPattern — dot grid revealed by a soft drifting "cloud" mask.
5
+ *
6
+ * Inspiration: Google/Apple AI loading states — a diffuse dot field that
7
+ * softly fades in, drifts diagonally across the surface, then fades out.
8
+ * No bright glow cores, no particles — just one or two large soft halos
9
+ * sliding across the grid so the dots appear as an ambient cloud.
10
+ */
11
+
12
+ import * as React from "react"
13
+ import { motion } from "motion/react"
14
+ import { cn } from "../../lib/utils"
15
+
16
+ interface DotPatternProps extends React.SVGProps<SVGSVGElement> {
17
+ width?: number
18
+ height?: number
19
+ x?: number
20
+ y?: number
21
+ cx?: number
22
+ cy?: number
23
+ cr?: number
24
+ className?: string
25
+ glow?: boolean
26
+ /** Number of drifting soft clouds (keep small: 1–2). */
27
+ glowCount?: number
28
+ /** Cloud radius — large values produce a wide, diffuse reveal. */
29
+ glowRadius?: number
30
+ }
31
+
32
+ type Cloud = {
33
+ key: number
34
+ xs: string[]
35
+ ys: string[]
36
+ duration: number
37
+ delay: number
38
+ }
39
+
40
+ /**
41
+ * Tiny deterministic PRNG (mulberry32). We use a seeded RNG instead of
42
+ * `Math.random()` so the SVG attributes emitted on the server match the
43
+ * client's first paint — otherwise React reports a hydration mismatch and
44
+ * has to re-paint every drifting `<motion.circle>` on mount, which is both
45
+ * a perf cost and a visible jump.
46
+ */
47
+ function mulberry32(seed: number): () => number {
48
+ let s = seed >>> 0
49
+ return () => {
50
+ s = (s + 0x6d2b79f5) >>> 0
51
+ let t = s
52
+ t = Math.imul(t ^ (t >>> 15), t | 1)
53
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
54
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296
55
+ }
56
+ }
57
+
58
+ function hashString(str: string): number {
59
+ // Cheap FNV-1a-style hash. Stable across SSR + CSR for the same input.
60
+ let h = 2166136261
61
+ for (let i = 0; i < str.length; i++) {
62
+ h ^= str.charCodeAt(i)
63
+ h = Math.imul(h, 16777619)
64
+ }
65
+ return h >>> 0
66
+ }
67
+
68
+ export function DotPattern({
69
+ width = 14,
70
+ height = 14,
71
+ x = 0,
72
+ y = 0,
73
+ cx = 1,
74
+ cy = 1,
75
+ cr = 0.8,
76
+ className,
77
+ glow = false,
78
+ glowCount = 2,
79
+ glowRadius = 240,
80
+ ...props
81
+ }: DotPatternProps) {
82
+ const id = React.useId()
83
+ const maskId = `${id}-mask`
84
+ const gradId = `${id}-grad`
85
+
86
+ const clouds = React.useMemo<Cloud[]>(() => {
87
+ const rng = mulberry32(hashString(`${id}|${glowCount}`))
88
+ const rand = (min: number, max: number) => min + rng() * (max - min)
89
+ return Array.from({ length: glowCount }).map((_, i) => {
90
+ // Drift diagonally: bottom-right → top-left. Start/end partly off-canvas
91
+ // so the cloud enters and exits softly without a visible edge.
92
+ const startX = rand(85, 120)
93
+ const endX = rand(-20, 15)
94
+ const midX = (startX + endX) / 2 + rand(-6, 6)
95
+
96
+ const startY = rand(85, 115)
97
+ const endY = rand(-15, 10)
98
+ const midY = (startY + endY) / 2 + rand(-4, 4)
99
+
100
+ const duration = rand(8, 12)
101
+ // Offset clouds by half a cycle so one is arriving as the other leaves.
102
+ const delay = -(i / glowCount) * duration
103
+
104
+ return {
105
+ key: i,
106
+ xs: [`${startX}%`, `${midX}%`, `${endX}%`],
107
+ ys: [`${startY}%`, `${midY}%`, `${endY}%`],
108
+ duration,
109
+ delay,
110
+ }
111
+ })
112
+ }, [glowCount, id])
113
+
114
+ return (
115
+ <svg
116
+ aria-hidden="true"
117
+ className={cn(
118
+ "pointer-events-none absolute inset-0 h-full w-full fill-neutral-400/80",
119
+ className,
120
+ )}
121
+ {...props}
122
+ >
123
+ <defs>
124
+ <pattern
125
+ id={id}
126
+ width={width}
127
+ height={height}
128
+ patternUnits="userSpaceOnUse"
129
+ patternContentUnits="userSpaceOnUse"
130
+ x={x}
131
+ y={y}
132
+ >
133
+ <circle cx={cx} cy={cy} r={cr} />
134
+ </pattern>
135
+
136
+ {glow ? (
137
+ <>
138
+ {/* Very soft falloff — no visible ring edge, dots dissolve gradually. */}
139
+ <radialGradient id={gradId}>
140
+ <stop offset="0%" stopColor="white" stopOpacity="0.9" />
141
+ <stop offset="40%" stopColor="white" stopOpacity="0.55" />
142
+ <stop offset="75%" stopColor="white" stopOpacity="0.18" />
143
+ <stop offset="100%" stopColor="white" stopOpacity="0" />
144
+ </radialGradient>
145
+
146
+ <mask id={maskId}>
147
+ {clouds.map((c) => (
148
+ <motion.circle
149
+ key={`cloud-${c.key}`}
150
+ r={glowRadius}
151
+ fill={`url(#${gradId})`}
152
+ initial={{ cx: c.xs[0], cy: c.ys[0], opacity: 0 }}
153
+ animate={{
154
+ cx: c.xs,
155
+ cy: c.ys,
156
+ // Long hold with soft fade at both ends.
157
+ opacity: [0, 1, 1, 0],
158
+ }}
159
+ transition={{
160
+ duration: c.duration,
161
+ delay: c.delay,
162
+ repeat: Infinity,
163
+ ease: "linear",
164
+ times: [0, 0.3, 0.7, 1],
165
+ }}
166
+ />
167
+ ))}
168
+ </mask>
169
+ </>
170
+ ) : null}
171
+ </defs>
172
+
173
+ {/* Dot grid — only visible inside the drifting soft clouds when glow is on. */}
174
+ <rect
175
+ width="100%"
176
+ height="100%"
177
+ strokeWidth={0}
178
+ fill={`url(#${id})`}
179
+ mask={glow ? `url(#${maskId})` : undefined}
180
+ />
181
+ </svg>
182
+ )
183
+ }
@@ -0,0 +1,375 @@
1
+ "use client"
2
+
3
+ /**
4
+ * ExportDrawer — floating right-side drawer with export form.
5
+ *
6
+ * Uses the same Sheet pattern as TablePropertiesDrawer:
7
+ * - showCloseButton={false}, showOverlay={false}
8
+ * - Rounded, floating, inset from viewport edges
9
+ * - Button + Tip from our own component library
10
+ *
11
+ * Form fields (shadcn Form + react-hook-form + zod):
12
+ * • File format CSV · Excel · PDF (SelectionTileGrid radio)
13
+ * • Date range From / To (FilterTextValueInput dateMDY — same as Settings / table filters)
14
+ * • Columns All · Visible only (radio)
15
+ * • Apply active filters (checkbox)
16
+ *
17
+ * WCAG 2.1 AA:
18
+ * ✓ All inputs labelled via FormLabel linked to control id (1.3.1)
19
+ * ✓ Error messages linked via aria-describedby (3.3.1)
20
+ * ✓ Focus returns to trigger on close (2.4.3)
21
+ */
22
+
23
+ import * as React from "react"
24
+ import { useForm } from "react-hook-form"
25
+ import { z } from "zod"
26
+ import { zodResolver } from "@hookform/resolvers/zod"
27
+
28
+ import { devLog } from "../../lib/dev-log"
29
+ import { Button } from "./button"
30
+ import { Checkbox } from "./checkbox"
31
+ import { Label } from "./label"
32
+ import { Tip } from "./tip"
33
+ import { Kbd, KbdGroup } from "./kbd"
34
+ import { Shortcut } from "./dropdown-menu"
35
+ import { RadioGroup, RadioGroupItem, RadioGroupLabel } from "./radio-group"
36
+ import { SelectionTileGrid } from "./selection-tile-grid"
37
+ import { FilterTextValueInput } from "../data-table/filter-text-value-input"
38
+ import type { SelectionTileOption } from "./selection-tile-grid"
39
+ import {
40
+ Sheet,
41
+ SheetContent,
42
+ SheetTitle,
43
+ } from "./sheet"
44
+ import {
45
+ Form,
46
+ FormControl,
47
+ FormDescription,
48
+ FormField,
49
+ FormItem,
50
+ FormLabel,
51
+ FormMessage,
52
+ } from "./form"
53
+
54
+ /** Parse full MM/DD/YYYY from masked input; partial/invalid → undefined. */
55
+ function parseMdyToDate(raw: string | undefined): Date | undefined {
56
+ if (!raw?.trim()) return undefined
57
+ const m = raw.trim().match(/^(\d{2})\/(\d{2})\/(\d{4})$/)
58
+ if (!m) return undefined
59
+ const month = Number(m[1])
60
+ const day = Number(m[2])
61
+ const year = Number(m[3])
62
+ if (month < 1 || month > 12 || day < 1 || day > 31) return undefined
63
+ const d = new Date(year, month - 1, day, 12, 0, 0, 0)
64
+ if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) return undefined
65
+ return d
66
+ }
67
+
68
+ // ── Validation schema ─────────────────────────────────────────────────────────
69
+
70
+ const EXPORT_FORMAT_OPTIONS: SelectionTileOption<"csv" | "excel" | "pdf">[] = [
71
+ { value: "csv", label: "CSV", icon: "fa-file-csv" },
72
+ { value: "excel", label: "Excel", icon: "fa-file-excel" },
73
+ { value: "pdf", label: "PDF", icon: "fa-file-pdf" },
74
+ ]
75
+
76
+ const exportSchema = z
77
+ .object({
78
+ format: z.enum(["csv", "excel", "pdf"]),
79
+ columns: z.enum(["all", "visible"]),
80
+ dateFrom: z.string().optional(),
81
+ dateTo: z.string().optional(),
82
+ includeFilters: z.boolean(),
83
+ })
84
+ .superRefine((data, ctx) => {
85
+ const from = parseMdyToDate(data.dateFrom)
86
+ const to = parseMdyToDate(data.dateTo)
87
+ if (data.dateFrom?.trim() && !from) {
88
+ ctx.addIssue({ code: "custom", message: "Enter a valid from date", path: ["dateFrom"] })
89
+ }
90
+ if (data.dateTo?.trim() && !to) {
91
+ ctx.addIssue({ code: "custom", message: "Enter a valid to date", path: ["dateTo"] })
92
+ }
93
+ if (from && to && to < from) {
94
+ ctx.addIssue({ code: "custom", message: "End date must be after start date", path: ["dateTo"] })
95
+ }
96
+ })
97
+
98
+ type ExportForm = z.infer<typeof exportSchema>
99
+
100
+ // ── Component ─────────────────────────────────────────────────────────────────
101
+
102
+ export interface ExportDrawerProps {
103
+ open: boolean
104
+ onOpenChange: (open: boolean) => void
105
+ totalRows?: number
106
+ visibleColumns?: number
107
+ }
108
+
109
+ export function ExportDrawer({
110
+ open,
111
+ onOpenChange,
112
+ totalRows = 0,
113
+ visibleColumns,
114
+ }: ExportDrawerProps) {
115
+ const form = useForm<ExportForm>({
116
+ resolver: zodResolver(exportSchema),
117
+ defaultValues: {
118
+ format: "csv",
119
+ columns: "visible",
120
+ dateFrom: "",
121
+ dateTo: "",
122
+ includeFilters: true,
123
+ },
124
+ })
125
+
126
+ const [isExporting, setIsExporting] = React.useState(false)
127
+
128
+ async function onSubmit(values: ExportForm) {
129
+ setIsExporting(true)
130
+ await new Promise(r => setTimeout(r, 1200))
131
+ devLog("Export:", {
132
+ ...values,
133
+ dateFrom: parseMdyToDate(values.dateFrom)?.toISOString(),
134
+ dateTo: parseMdyToDate(values.dateTo)?.toISOString(),
135
+ })
136
+ setIsExporting(false)
137
+ onOpenChange(false)
138
+ form.reset()
139
+ }
140
+
141
+ return (
142
+ <Sheet open={open} onOpenChange={onOpenChange}>
143
+ <SheetContent
144
+ data-slot="export-drawer"
145
+ side="right"
146
+ showCloseButton={false}
147
+ showOverlay={false}
148
+ className="z-[80] w-80 sm:max-w-80 p-0 gap-0 flex flex-col border border-border shadow-xl rounded-xl overflow-hidden"
149
+ style={{ top: "0.5rem", bottom: "0.5rem", right: "0.5rem", height: "calc(100vh - 1rem)" }}
150
+ >
151
+ {/* Header */}
152
+ <div className="flex items-center justify-between gap-3 px-4 pt-5 pb-3">
153
+ <SheetTitle className="text-base font-semibold leading-tight">Export data</SheetTitle>
154
+ <Tip label="Close" side="bottom">
155
+ <Button
156
+ type="button"
157
+ variant="ghost"
158
+ size="icon-sm"
159
+ aria-label="Close"
160
+ onClick={() => onOpenChange(false)}
161
+ >
162
+ <i className="fa-light fa-xmark text-[13px]" aria-hidden="true" />
163
+ </Button>
164
+ </Tip>
165
+ </div>
166
+
167
+ {/* Record count */}
168
+ <p className="px-4 pb-3 text-sm text-muted-foreground -mt-1">
169
+ {totalRows} record{totalRows !== 1 ? "s" : ""} available for export.
170
+ </p>
171
+
172
+ {/* Form body */}
173
+ <Form {...form}>
174
+ <form
175
+ id="export-form"
176
+ onSubmit={form.handleSubmit(onSubmit)}
177
+ className="flex-1 overflow-y-auto"
178
+ >
179
+ <div className="px-4 pb-4 space-y-5">
180
+
181
+ {/* File format */}
182
+ <FormField
183
+ control={form.control}
184
+ name="format"
185
+ render={({ field }) => (
186
+ <FormItem>
187
+ <FormControl>
188
+ <SelectionTileGrid
189
+ sectionLabel="File format"
190
+ options={EXPORT_FORMAT_OPTIONS}
191
+ columns={3}
192
+ value={field.value}
193
+ onValueChange={field.onChange}
194
+ interaction="radio"
195
+ idPrefix="export-fmt"
196
+ itemVariant="outline"
197
+ itemMotion="pop"
198
+ />
199
+ </FormControl>
200
+ <FormMessage />
201
+ </FormItem>
202
+ )}
203
+ />
204
+
205
+ {/* Date range */}
206
+ <fieldset className="space-y-2">
207
+ <legend className="text-sm font-medium leading-none mb-2">
208
+ Date range{" "}
209
+ <span className="text-muted-foreground font-normal">(optional)</span>
210
+ </legend>
211
+ <div className="grid grid-cols-2 gap-3">
212
+ <FormField
213
+ control={form.control}
214
+ name="dateFrom"
215
+ render={({ field }) => (
216
+ <FormItem className="gap-1">
217
+ <FormLabel htmlFor="export-date-from" className="text-xs text-muted-foreground">
218
+ From
219
+ </FormLabel>
220
+ <FormControl>
221
+ <FilterTextValueInput
222
+ id="export-date-from"
223
+ mask="dateMDY"
224
+ aria-label="Export from date (optional)"
225
+ placeholder="MM/DD/YYYY"
226
+ value={field.value ?? ""}
227
+ onValueChange={field.onChange}
228
+ className="h-8 text-sm"
229
+ />
230
+ </FormControl>
231
+ <FormDescription className="text-[11px]">MM/DD/YYYY</FormDescription>
232
+ <FormMessage />
233
+ </FormItem>
234
+ )}
235
+ />
236
+ <FormField
237
+ control={form.control}
238
+ name="dateTo"
239
+ render={({ field }) => (
240
+ <FormItem className="gap-1">
241
+ <FormLabel htmlFor="export-date-to" className="text-xs text-muted-foreground">
242
+ To
243
+ </FormLabel>
244
+ <FormControl>
245
+ <FilterTextValueInput
246
+ id="export-date-to"
247
+ mask="dateMDY"
248
+ aria-label="Export to date (optional)"
249
+ placeholder="MM/DD/YYYY"
250
+ value={field.value ?? ""}
251
+ onValueChange={field.onChange}
252
+ className="h-8 text-sm"
253
+ />
254
+ </FormControl>
255
+ <FormDescription className="text-[11px]">MM/DD/YYYY</FormDescription>
256
+ <FormMessage />
257
+ </FormItem>
258
+ )}
259
+ />
260
+ </div>
261
+ </fieldset>
262
+
263
+ {/* Columns */}
264
+ <FormField
265
+ control={form.control}
266
+ name="columns"
267
+ render={({ field }) => (
268
+ <FormItem>
269
+ <FormLabel className="text-sm font-medium">Columns</FormLabel>
270
+ <FormControl>
271
+ <RadioGroup
272
+ value={field.value}
273
+ onValueChange={field.onChange}
274
+ className="space-y-1.5 mt-1"
275
+ itemVariant="outline"
276
+ itemMotion="pop"
277
+ >
278
+ {([
279
+ { value: "all", label: "All columns", sub: null },
280
+ { value: "visible", label: "Visible columns only", sub: visibleColumns !== undefined ? `${visibleColumns} columns` : null },
281
+ ] as const).map(opt => (
282
+ <div
283
+ key={opt.value}
284
+ className="flex items-center gap-2.5 rounded-lg border border-border px-3 py-2.5 transition-colors hover:bg-interactive-hover has-[[data-state=checked]]:border-brand has-[[data-state=checked]]:bg-brand/10 cursor-pointer"
285
+ >
286
+ <RadioGroupItem value={opt.value} id={`col-${opt.value}`} />
287
+ <RadioGroupLabel
288
+ htmlFor={`col-${opt.value}`}
289
+ className="min-h-0 flex-1 cursor-pointer py-0 text-sm font-normal leading-none"
290
+ >
291
+ {opt.label}
292
+ {opt.sub && (
293
+ <span className="text-muted-foreground ms-1.5 font-normal">({opt.sub})</span>
294
+ )}
295
+ </RadioGroupLabel>
296
+ </div>
297
+ ))}
298
+ </RadioGroup>
299
+ </FormControl>
300
+ <FormMessage />
301
+ </FormItem>
302
+ )}
303
+ />
304
+
305
+ {/* Include filters */}
306
+ <FormField
307
+ control={form.control}
308
+ name="includeFilters"
309
+ render={({ field }) => (
310
+ <FormItem>
311
+ <div className="flex items-start gap-3 rounded-lg border border-border px-3 py-2.5 transition-colors hover:bg-interactive-hover has-[[data-state=checked]]:border-primary">
312
+ <FormControl>
313
+ <Checkbox
314
+ id="include-filters"
315
+ checked={field.value}
316
+ onCheckedChange={field.onChange}
317
+ className="mt-0.5 shrink-0"
318
+ />
319
+ </FormControl>
320
+ <div className="min-w-0">
321
+ <Label htmlFor="include-filters" className="text-sm cursor-pointer font-medium leading-none">
322
+ Apply active filters
323
+ </Label>
324
+ <p className="text-xs text-muted-foreground mt-1">
325
+ Export only rows matching current filters
326
+ </p>
327
+ </div>
328
+ </div>
329
+ <FormMessage />
330
+ </FormItem>
331
+ )}
332
+ />
333
+
334
+ </div>
335
+ </form>
336
+ </Form>
337
+
338
+ {/* Global bindings — only active while the drawer is open (Sheet unmounts content on close) */}
339
+ <Shortcut keys="Enter" disabled={isExporting} onInvoke={() => form.handleSubmit(onSubmit)()} />
340
+
341
+ {/* Footer */}
342
+ <div className="flex items-center gap-2 px-4 py-3 border-t border-border">
343
+ <Button
344
+ type="button"
345
+ variant="outline"
346
+ className="flex-1"
347
+ onClick={() => onOpenChange(false)}
348
+ >
349
+ Cancel
350
+ <KbdGroup className="ms-1.5"><Kbd variant="bare">Esc</Kbd></KbdGroup>
351
+ </Button>
352
+ <Button
353
+ type="submit"
354
+ form="export-form"
355
+ className="flex-1"
356
+ disabled={isExporting}
357
+ >
358
+ {isExporting ? (
359
+ <>
360
+ <i className="fa-light fa-spinner-third fa-spin text-[13px]" aria-hidden="true" />
361
+ Exporting…
362
+ </>
363
+ ) : (
364
+ <>
365
+ <i className="fa-light fa-arrow-down-to-line text-[13px]" aria-hidden="true" />
366
+ Export
367
+ <KbdGroup className="ms-1.5"><Kbd variant="bare">⏎</Kbd></KbdGroup>
368
+ </>
369
+ )}
370
+ </Button>
371
+ </div>
372
+ </SheetContent>
373
+ </Sheet>
374
+ )
375
+ }
@@ -0,0 +1,66 @@
1
+ "use client"
2
+
3
+ /**
4
+ * HoverCard — richer, persistent hover surface for content too large or
5
+ * interactive for a `Tooltip` (avatars, link previews, user cards, glossary
6
+ * entries).
7
+ *
8
+ * When to choose `HoverCard` vs `Tooltip` vs `Popover`:
9
+ * - **`Tooltip`** — short text label, no interaction, auto-dismiss on
10
+ * mouseout / blur. Pairs with `Tip` for icon-only buttons.
11
+ * - **`HoverCard`** — small interactive content (links, copy buttons,
12
+ * avatars) shown on intentional hover; closes when the pointer leaves.
13
+ * Not focusable / not announced by screen readers — pair with an
14
+ * accessible alternative for keyboard users (visit profile link, etc.).
15
+ * - **`Popover`** — keyboard- and screen-reader-accessible, opens on
16
+ * explicit click. Use this when the surface holds primary content.
17
+ *
18
+ * Accessibility (per Radix):
19
+ * - HoverCard is NOT exposed to screen readers — Radix intentionally
20
+ * treats it as a sighted-mouse-user affordance. The trigger MUST also
21
+ * convey its meaning through its own accessible name and behaviour
22
+ * (e.g. a focusable `<a>` that links to the same content).
23
+ */
24
+
25
+ import * as React from "react"
26
+ import { HoverCard as HoverCardPrimitive } from "radix-ui"
27
+
28
+ import { cn } from "../../lib/utils"
29
+
30
+ function HoverCard({
31
+ ...props
32
+ }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
33
+ return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
34
+ }
35
+
36
+ function HoverCardTrigger({
37
+ ...props
38
+ }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
39
+ return (
40
+ <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
41
+ )
42
+ }
43
+
44
+ function HoverCardContent({
45
+ className,
46
+ align = "center",
47
+ sideOffset = 4,
48
+ ...props
49
+ }: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
50
+ return (
51
+ <HoverCardPrimitive.Portal data-slot="hover-card-portal">
52
+ <HoverCardPrimitive.Content
53
+ data-slot="hover-card-content"
54
+ align={align}
55
+ sideOffset={sideOffset}
56
+ className={cn(
57
+ "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-lg bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
58
+ className,
59
+ )}
60
+ {...props}
61
+ />
62
+ </HoverCardPrimitive.Portal>
63
+ )
64
+ }
65
+
66
+ export { HoverCard, HoverCardTrigger, HoverCardContent }