@crisp-ui-kit/crisp 0.5.0 → 0.7.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 (472) hide show
  1. package/README.md +14 -0
  2. package/dist/accordion.css +9 -1
  3. package/dist/appshell.css +12 -4
  4. package/dist/authshell.css +57 -0
  5. package/dist/authshell.d.ts +7 -0
  6. package/dist/avatargroup.css +2 -2
  7. package/dist/badge.css +4 -4
  8. package/dist/barchart.css +13 -5
  9. package/dist/board.css +9 -1
  10. package/dist/bulkbar.css +11 -3
  11. package/dist/button.css +15 -1
  12. package/dist/button.d.ts +2 -1
  13. package/dist/card.css +8 -0
  14. package/dist/checkbox.css +17 -1
  15. package/dist/cjs/components/accordion/accordion.js +69 -0
  16. package/dist/cjs/components/accordion/accordion.recipe.js +26 -0
  17. package/dist/cjs/components/accordion/index.js +7 -0
  18. package/dist/cjs/components/avatar/avatar.js +44 -0
  19. package/dist/cjs/components/avatar/avatar.recipe.js +42 -0
  20. package/dist/cjs/components/avatar/index.js +7 -0
  21. package/dist/cjs/components/avatargroup/avatargroup.js +52 -0
  22. package/dist/cjs/components/avatargroup/avatargroup.recipe.js +18 -0
  23. package/dist/cjs/components/avatargroup/index.js +7 -0
  24. package/dist/cjs/components/badge/badge.js +44 -0
  25. package/dist/cjs/components/badge/badge.recipe.js +68 -0
  26. package/dist/cjs/components/badge/index.js +7 -0
  27. package/dist/cjs/components/barchart/barchart.js +45 -0
  28. package/dist/cjs/components/barchart/barchart.recipe.js +34 -0
  29. package/dist/cjs/components/barchart/index.js +7 -0
  30. package/dist/cjs/components/breadcrumb/breadcrumb.js +53 -0
  31. package/dist/cjs/components/breadcrumb/breadcrumb.recipe.js +21 -0
  32. package/dist/cjs/components/breadcrumb/index.js +7 -0
  33. package/dist/cjs/components/bulkbar/bulkbar.js +53 -0
  34. package/dist/cjs/components/bulkbar/bulkbar.recipe.js +31 -0
  35. package/dist/cjs/components/bulkbar/index.js +8 -0
  36. package/dist/cjs/components/button/button.js +62 -0
  37. package/dist/cjs/components/button/button.recipe.js +58 -0
  38. package/dist/cjs/components/button/index.js +7 -0
  39. package/dist/cjs/components/callout/callout.js +25 -0
  40. package/dist/cjs/components/callout/callout.recipe.js +29 -0
  41. package/dist/cjs/components/callout/index.js +7 -0
  42. package/dist/cjs/components/card/card.js +54 -0
  43. package/dist/cjs/components/card/card.recipe.js +31 -0
  44. package/dist/cjs/components/card/index.js +10 -0
  45. package/dist/cjs/components/checkbox/checkbox.js +56 -0
  46. package/dist/cjs/components/checkbox/checkbox.recipe.js +34 -0
  47. package/dist/cjs/components/checkbox/index.js +7 -0
  48. package/dist/cjs/components/columncalc/columncalc.js +139 -0
  49. package/dist/cjs/components/columncalc/columncalc.recipe.js +33 -0
  50. package/dist/cjs/components/columncalc/index.js +10 -0
  51. package/dist/cjs/components/contextmenu/contextmenu.js +78 -0
  52. package/dist/cjs/components/contextmenu/contextmenu.recipe.js +24 -0
  53. package/dist/cjs/components/contextmenu/index.js +7 -0
  54. package/dist/cjs/components/datatable/datatable.js +508 -0
  55. package/dist/cjs/components/datatable/datatable.recipe.js +113 -0
  56. package/dist/cjs/components/datatable/index.js +7 -0
  57. package/dist/cjs/components/datepicker/datepicker.js +153 -0
  58. package/dist/cjs/components/datepicker/datepicker.recipe.js +180 -0
  59. package/dist/cjs/components/datepicker/index.js +19 -0
  60. package/dist/cjs/components/datepickerfield/datepickerfield.js +85 -0
  61. package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +44 -0
  62. package/dist/cjs/components/datepickerfield/index.js +7 -0
  63. package/dist/cjs/components/dialog/dialog.js +86 -0
  64. package/dist/cjs/components/dialog/dialog.recipe.js +35 -0
  65. package/dist/cjs/components/dialog/index.js +9 -0
  66. package/dist/cjs/components/divider/divider.js +10 -0
  67. package/dist/cjs/components/divider/divider.recipe.js +17 -0
  68. package/dist/cjs/components/divider/index.js +7 -0
  69. package/dist/cjs/components/donutchart/donutchart.js +41 -0
  70. package/dist/cjs/components/donutchart/donutchart.recipe.js +30 -0
  71. package/dist/cjs/components/donutchart/index.js +7 -0
  72. package/dist/cjs/components/drawer/drawer.js +80 -0
  73. package/dist/cjs/components/drawer/drawer.recipe.js +30 -0
  74. package/dist/cjs/components/drawer/index.js +9 -0
  75. package/dist/cjs/components/emptystate/emptystate.js +10 -0
  76. package/dist/cjs/components/emptystate/emptystate.recipe.js +34 -0
  77. package/dist/cjs/components/emptystate/index.js +7 -0
  78. package/dist/cjs/components/formfield/formfield.js +50 -0
  79. package/dist/cjs/components/formfield/formfield.recipe.js +22 -0
  80. package/dist/cjs/components/formfield/index.js +7 -0
  81. package/dist/cjs/components/input/index.js +7 -0
  82. package/dist/cjs/components/input/input.js +47 -0
  83. package/dist/cjs/components/input/input.recipe.js +59 -0
  84. package/dist/cjs/components/kbd/index.js +7 -0
  85. package/dist/cjs/components/kbd/kbd.js +44 -0
  86. package/dist/cjs/components/kbd/kbd.recipe.js +23 -0
  87. package/dist/cjs/components/linechart/index.js +7 -0
  88. package/dist/cjs/components/linechart/linechart.js +57 -0
  89. package/dist/cjs/components/linechart/linechart.recipe.js +35 -0
  90. package/dist/cjs/components/menu/index.js +14 -0
  91. package/dist/cjs/components/menu/menu-keyboard.js +117 -0
  92. package/dist/cjs/components/menu/menu.js +144 -0
  93. package/dist/cjs/components/menu/menu.recipe.js +54 -0
  94. package/dist/cjs/components/multiselect/index.js +7 -0
  95. package/dist/cjs/components/multiselect/multiselect.js +161 -0
  96. package/dist/cjs/components/multiselect/multiselect.recipe.js +71 -0
  97. package/dist/cjs/components/popover/index.js +7 -0
  98. package/dist/cjs/components/popover/popover.js +106 -0
  99. package/dist/cjs/components/popover/popover.recipe.js +21 -0
  100. package/dist/cjs/components/progress/index.js +7 -0
  101. package/dist/cjs/components/progress/progress.js +26 -0
  102. package/dist/cjs/components/progress/progress.recipe.js +20 -0
  103. package/dist/cjs/components/radiogroup/index.js +8 -0
  104. package/dist/cjs/components/radiogroup/radiogroup.js +83 -0
  105. package/dist/cjs/components/radiogroup/radiogroup.recipe.js +40 -0
  106. package/dist/cjs/components/resizablepanel/index.js +12 -0
  107. package/dist/cjs/components/resizablepanel/resizablepanel.js +176 -0
  108. package/dist/cjs/components/resizablepanel/resizablepanel.recipe.js +69 -0
  109. package/dist/cjs/components/segmented/index.js +7 -0
  110. package/dist/cjs/components/segmented/segmented.js +95 -0
  111. package/dist/cjs/components/segmented/segmented.recipe.js +23 -0
  112. package/dist/cjs/components/select/index.js +7 -0
  113. package/dist/cjs/components/select/select.js +180 -0
  114. package/dist/cjs/components/select/select.recipe.js +79 -0
  115. package/dist/cjs/components/skeleton/index.js +7 -0
  116. package/dist/cjs/components/skeleton/skeleton.js +13 -0
  117. package/dist/cjs/components/skeleton/skeleton.recipe.js +17 -0
  118. package/dist/cjs/components/spinner/index.js +7 -0
  119. package/dist/cjs/components/spinner/spinner.js +15 -0
  120. package/dist/cjs/components/spinner/spinner.recipe.js +16 -0
  121. package/dist/cjs/components/stagebar/index.js +7 -0
  122. package/dist/cjs/components/stagebar/stagebar.js +26 -0
  123. package/dist/cjs/components/stagebar/stagebar.recipe.js +17 -0
  124. package/dist/cjs/components/statcard/index.js +7 -0
  125. package/dist/cjs/components/statcard/statcard.js +15 -0
  126. package/dist/cjs/components/statcard/statcard.recipe.js +37 -0
  127. package/dist/cjs/components/switch/index.js +7 -0
  128. package/dist/cjs/components/switch/switch.js +58 -0
  129. package/dist/cjs/components/switch/switch.recipe.js +29 -0
  130. package/dist/cjs/components/table/index.js +14 -0
  131. package/dist/cjs/components/table/table.js +66 -0
  132. package/dist/cjs/components/table/table.recipe.js +43 -0
  133. package/dist/cjs/components/tabletoolbar/index.js +20 -0
  134. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +84 -0
  135. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +237 -0
  136. package/dist/cjs/components/tabletoolbar/tabletoolbar.recipe.js +26 -0
  137. package/dist/cjs/components/tabs/index.js +7 -0
  138. package/dist/cjs/components/tabs/tabs.js +106 -0
  139. package/dist/cjs/components/tabs/tabs.recipe.js +36 -0
  140. package/dist/cjs/components/textarea/index.js +7 -0
  141. package/dist/cjs/components/textarea/textarea.js +56 -0
  142. package/dist/cjs/components/textarea/textarea.recipe.js +46 -0
  143. package/dist/cjs/components/toast/index.js +8 -0
  144. package/dist/cjs/components/toast/toast.js +95 -0
  145. package/dist/cjs/components/toast/toast.recipe.js +31 -0
  146. package/dist/cjs/components/tooltip/index.js +7 -0
  147. package/dist/cjs/components/tooltip/tooltip.js +95 -0
  148. package/dist/cjs/components/tooltip/tooltip.recipe.js +16 -0
  149. package/dist/cjs/components/wheelpicker/index.js +7 -0
  150. package/dist/cjs/components/wheelpicker/wheelpicker.js +134 -0
  151. package/dist/cjs/components/wheelpicker/wheelpicker.recipe.js +95 -0
  152. package/dist/cjs/core/cx.js +8 -0
  153. package/dist/cjs/core/define.js +6 -0
  154. package/dist/cjs/core/index.js +11 -0
  155. package/dist/cjs/core/primitive.js +49 -0
  156. package/dist/cjs/core/resolve.js +44 -0
  157. package/dist/cjs/core/types.js +2 -0
  158. package/dist/cjs/index.js +92 -0
  159. package/dist/cjs/package.json +3 -0
  160. package/dist/cjs/product/appshell/appshell.js +104 -0
  161. package/dist/cjs/product/appshell/appshell.recipe.js +30 -0
  162. package/dist/cjs/product/appshell/index.js +7 -0
  163. package/dist/cjs/product/authshell/authshell.js +21 -0
  164. package/dist/cjs/product/authshell/authshell.recipe.js +67 -0
  165. package/dist/cjs/product/authshell/index.js +7 -0
  166. package/dist/cjs/product/board/board.js +78 -0
  167. package/dist/cjs/product/board/board.recipe.js +31 -0
  168. package/dist/cjs/product/board/index.js +7 -0
  169. package/dist/cjs/product/command/command.js +238 -0
  170. package/dist/cjs/product/command/command.recipe.js +47 -0
  171. package/dist/cjs/product/command/index.js +8 -0
  172. package/dist/cjs/product/entitycard/entitycard.js +14 -0
  173. package/dist/cjs/product/entitycard/entitycard.recipe.js +32 -0
  174. package/dist/cjs/product/entitycard/index.js +7 -0
  175. package/dist/cjs/product/flowcanvas/flowcanvas.js +121 -0
  176. package/dist/cjs/product/flowcanvas/flowcanvas.recipe.js +28 -0
  177. package/dist/cjs/product/flowcanvas/index.js +7 -0
  178. package/dist/cjs/product/inbox/inbox.js +16 -0
  179. package/dist/cjs/product/inbox/inbox.recipe.js +46 -0
  180. package/dist/cjs/product/inbox/index.js +7 -0
  181. package/dist/cjs/product/listpage/index.js +8 -0
  182. package/dist/cjs/product/listpage/listpage.js +25 -0
  183. package/dist/cjs/product/listpage/listpage.recipe.js +46 -0
  184. package/dist/cjs/product/navitem/index.js +5 -0
  185. package/dist/cjs/product/navitem/navitem.js +44 -0
  186. package/dist/cjs/product/navitem/navitem.recipe.js +36 -0
  187. package/dist/cjs/product/onboarding/index.js +7 -0
  188. package/dist/cjs/product/onboarding/onboarding.js +17 -0
  189. package/dist/cjs/product/onboarding/onboarding.recipe.js +44 -0
  190. package/dist/cjs/product/recordpage/index.js +7 -0
  191. package/dist/cjs/product/recordpage/recordpage.js +409 -0
  192. package/dist/cjs/product/recordpage/recordpage.recipe.js +162 -0
  193. package/dist/cjs/product/recordpanel/index.js +7 -0
  194. package/dist/cjs/product/recordpanel/recordpanel.js +83 -0
  195. package/dist/cjs/product/recordpanel/recordpanel.recipe.js +51 -0
  196. package/dist/cjs/product/recordstable/company-logos.js +29 -0
  197. package/dist/cjs/product/recordstable/index.js +10 -0
  198. package/dist/cjs/product/recordstable/recordstable.js +1092 -0
  199. package/dist/cjs/product/recordstable/recordstable.recipe.js +152 -0
  200. package/dist/cjs/product/recordstable/recordstable.tag.js +21 -0
  201. package/dist/cjs/product/richtext/index.js +7 -0
  202. package/dist/cjs/product/richtext/richtext.js +147 -0
  203. package/dist/cjs/product/richtext/richtext.recipe.js +43 -0
  204. package/dist/cjs/product/settingssection/index.js +7 -0
  205. package/dist/cjs/product/settingssection/settingssection.js +14 -0
  206. package/dist/cjs/product/settingssection/settingssection.recipe.js +23 -0
  207. package/dist/cjs/product/settingsshell/index.js +7 -0
  208. package/dist/cjs/product/settingsshell/settingsshell.js +59 -0
  209. package/dist/cjs/product/settingsshell/settingsshell.recipe.js +46 -0
  210. package/dist/cjs/product/sidebar/index.js +13 -0
  211. package/dist/cjs/product/sidebar/sidebar.js +148 -0
  212. package/dist/cjs/product/sidebar/sidebar.recipe.js +46 -0
  213. package/dist/cjs/product/tasklist/index.js +7 -0
  214. package/dist/cjs/product/tasklist/tasklist.js +19 -0
  215. package/dist/cjs/product/tasklist/tasklist.recipe.js +38 -0
  216. package/dist/cjs/product/trialbanner/index.js +7 -0
  217. package/dist/cjs/product/trialbanner/trialbanner.js +13 -0
  218. package/dist/cjs/product/trialbanner/trialbanner.recipe.js +32 -0
  219. package/dist/cjs/product/viewtoggle/index.js +7 -0
  220. package/dist/cjs/product/viewtoggle/viewtoggle.js +55 -0
  221. package/dist/cjs/product/viewtoggle/viewtoggle.recipe.js +27 -0
  222. package/dist/cjs/tokens/contract.js +21 -0
  223. package/dist/cjs/tokens/elevation.js +47 -0
  224. package/dist/cjs/tokens/index.js +18 -0
  225. package/dist/cjs/tokens/palette.js +63 -0
  226. package/dist/cjs/tokens/scale.js +70 -0
  227. package/dist/cjs/tokens/semantic.js +57 -0
  228. package/dist/columncalc.css +26 -0
  229. package/dist/columncalc.d.ts +7 -0
  230. package/dist/command.css +34 -1
  231. package/dist/contextmenu.css +10 -2
  232. package/dist/datatable.css +60 -14
  233. package/dist/datepicker.css +165 -19
  234. package/dist/datepicker.d.ts +2 -2
  235. package/dist/datepickerfield.css +27 -0
  236. package/dist/datepickerfield.d.ts +7 -0
  237. package/dist/dialog.css +10 -2
  238. package/dist/donutchart.css +8 -0
  239. package/dist/drawer.css +13 -5
  240. package/dist/entitycard.css +10 -2
  241. package/dist/esm/components/accordion/accordion.js +17 -16
  242. package/dist/esm/components/accordion/accordion.recipe.js +1 -1
  243. package/dist/esm/components/avatargroup/avatargroup.js +2 -2
  244. package/dist/esm/components/avatargroup/avatargroup.recipe.js +2 -2
  245. package/dist/esm/components/badge/badge.recipe.js +4 -4
  246. package/dist/esm/components/barchart/barchart.js +15 -2
  247. package/dist/esm/components/barchart/barchart.recipe.js +10 -5
  248. package/dist/esm/components/breadcrumb/breadcrumb.js +2 -2
  249. package/dist/esm/components/bulkbar/bulkbar.js +2 -2
  250. package/dist/esm/components/bulkbar/bulkbar.recipe.js +4 -4
  251. package/dist/esm/components/button/button.js +13 -2
  252. package/dist/esm/components/button/button.recipe.js +20 -4
  253. package/dist/esm/components/callout/callout.js +2 -2
  254. package/dist/esm/components/checkbox/checkbox.recipe.js +9 -1
  255. package/dist/esm/components/columncalc/columncalc.js +100 -0
  256. package/dist/esm/components/columncalc/columncalc.recipe.js +30 -0
  257. package/dist/esm/components/columncalc/index.js +1 -0
  258. package/dist/esm/components/contextmenu/contextmenu.recipe.js +4 -4
  259. package/dist/esm/components/datatable/datatable.js +276 -49
  260. package/dist/esm/components/datatable/datatable.recipe.js +54 -16
  261. package/dist/esm/components/datepicker/datepicker.js +104 -53
  262. package/dist/esm/components/datepicker/datepicker.recipe.js +170 -25
  263. package/dist/esm/components/datepicker/index.js +1 -1
  264. package/dist/esm/components/datepickerfield/datepickerfield.js +49 -0
  265. package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +41 -0
  266. package/dist/esm/components/datepickerfield/index.js +2 -0
  267. package/dist/esm/components/dialog/dialog.js +2 -2
  268. package/dist/esm/components/dialog/dialog.recipe.js +4 -4
  269. package/dist/esm/components/divider/divider.js +2 -2
  270. package/dist/esm/components/donutchart/donutchart.js +2 -2
  271. package/dist/esm/components/drawer/drawer.js +2 -2
  272. package/dist/esm/components/drawer/drawer.recipe.js +6 -6
  273. package/dist/esm/components/emptystate/emptystate.js +2 -2
  274. package/dist/esm/components/formfield/formfield.js +2 -2
  275. package/dist/esm/components/input/input.js +6 -3
  276. package/dist/esm/components/input/input.recipe.js +38 -5
  277. package/dist/esm/components/linechart/linechart.js +15 -2
  278. package/dist/esm/components/linechart/linechart.recipe.js +10 -5
  279. package/dist/esm/components/menu/index.js +1 -0
  280. package/dist/esm/components/menu/menu-keyboard.js +80 -0
  281. package/dist/esm/components/menu/menu.js +27 -60
  282. package/dist/esm/components/menu/menu.recipe.js +5 -5
  283. package/dist/esm/components/multiselect/multiselect.js +10 -3
  284. package/dist/esm/components/multiselect/multiselect.recipe.js +8 -8
  285. package/dist/esm/components/popover/popover.js +2 -2
  286. package/dist/esm/components/popover/popover.recipe.js +2 -2
  287. package/dist/esm/components/progress/progress.js +3 -3
  288. package/dist/esm/components/radiogroup/radiogroup.js +2 -2
  289. package/dist/esm/components/radiogroup/radiogroup.recipe.js +1 -1
  290. package/dist/esm/components/resizablepanel/index.js +2 -0
  291. package/dist/esm/components/resizablepanel/resizablepanel.js +135 -0
  292. package/dist/esm/components/resizablepanel/resizablepanel.recipe.js +66 -0
  293. package/dist/esm/components/segmented/segmented.js +2 -2
  294. package/dist/esm/components/select/select.js +2 -2
  295. package/dist/esm/components/select/select.recipe.js +6 -6
  296. package/dist/esm/components/skeleton/skeleton.js +5 -2
  297. package/dist/esm/components/spinner/spinner.js +3 -2
  298. package/dist/esm/components/stagebar/stagebar.js +2 -2
  299. package/dist/esm/components/statcard/statcard.js +2 -2
  300. package/dist/esm/components/table/table.recipe.js +6 -6
  301. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +3 -3
  302. package/dist/esm/components/tabletoolbar/tabletoolbar.js +21 -13
  303. package/dist/esm/components/tabs/tabs.js +2 -2
  304. package/dist/esm/components/tabs/tabs.recipe.js +4 -4
  305. package/dist/esm/components/textarea/textarea.js +5 -5
  306. package/dist/esm/components/textarea/textarea.recipe.js +16 -4
  307. package/dist/esm/components/toast/toast.js +4 -4
  308. package/dist/esm/components/toast/toast.recipe.js +2 -2
  309. package/dist/esm/components/tooltip/tooltip.js +21 -7
  310. package/dist/esm/components/wheelpicker/index.js +2 -0
  311. package/dist/esm/components/wheelpicker/wheelpicker.js +98 -0
  312. package/dist/esm/components/wheelpicker/wheelpicker.recipe.js +92 -0
  313. package/dist/esm/index.js +5 -0
  314. package/dist/esm/product/appshell/appshell.js +33 -9
  315. package/dist/esm/product/appshell/appshell.recipe.js +4 -4
  316. package/dist/esm/product/authshell/authshell.js +18 -0
  317. package/dist/esm/product/authshell/authshell.recipe.js +64 -0
  318. package/dist/esm/product/authshell/index.js +2 -0
  319. package/dist/esm/product/board/board.js +2 -2
  320. package/dist/esm/product/board/board.recipe.js +1 -1
  321. package/dist/esm/product/command/command.js +19 -6
  322. package/dist/esm/product/command/command.recipe.js +27 -2
  323. package/dist/esm/product/entitycard/entitycard.js +2 -2
  324. package/dist/esm/product/entitycard/entitycard.recipe.js +2 -2
  325. package/dist/esm/product/flowcanvas/flowcanvas.js +4 -4
  326. package/dist/esm/product/inbox/inbox.recipe.js +1 -1
  327. package/dist/esm/product/listpage/listpage.recipe.js +3 -3
  328. package/dist/esm/product/navitem/navitem.recipe.js +13 -1
  329. package/dist/esm/product/onboarding/onboarding.js +2 -2
  330. package/dist/esm/product/onboarding/onboarding.recipe.js +2 -2
  331. package/dist/esm/product/recordpage/recordpage.js +133 -47
  332. package/dist/esm/product/recordpage/recordpage.recipe.js +19 -17
  333. package/dist/esm/product/recordpanel/recordpanel.js +4 -4
  334. package/dist/esm/product/recordpanel/recordpanel.recipe.js +12 -16
  335. package/dist/esm/product/recordstable/recordstable.js +157 -66
  336. package/dist/esm/product/recordstable/recordstable.recipe.js +23 -23
  337. package/dist/esm/product/recordstable/recordstable.tag.js +18 -0
  338. package/dist/esm/product/richtext/richtext.js +3 -3
  339. package/dist/esm/product/richtext/richtext.recipe.js +3 -3
  340. package/dist/esm/product/settingssection/settingssection.js +2 -2
  341. package/dist/esm/product/settingsshell/settingsshell.js +2 -2
  342. package/dist/esm/product/settingsshell/settingsshell.recipe.js +7 -2
  343. package/dist/esm/product/sidebar/sidebar.js +2 -2
  344. package/dist/esm/product/sidebar/sidebar.recipe.js +27 -2
  345. package/dist/esm/product/tasklist/tasklist.js +4 -4
  346. package/dist/esm/product/trialbanner/trialbanner.js +2 -2
  347. package/dist/esm/product/trialbanner/trialbanner.recipe.js +2 -2
  348. package/dist/esm/product/viewtoggle/viewtoggle.js +10 -2
  349. package/dist/esm/product/viewtoggle/viewtoggle.recipe.js +1 -1
  350. package/dist/esm/tokens/elevation.js +44 -0
  351. package/dist/esm/tokens/index.js +1 -0
  352. package/dist/esm/tokens/palette.js +30 -0
  353. package/dist/esm/tokens/scale.js +7 -0
  354. package/dist/esm/tokens/semantic.js +24 -0
  355. package/dist/inbox.css +9 -1
  356. package/dist/input.css +32 -4
  357. package/dist/linechart.css +5 -5
  358. package/dist/listpage.css +11 -3
  359. package/dist/menu.css +11 -3
  360. package/dist/multiselect.css +14 -6
  361. package/dist/native/tokens.d.ts +16 -0
  362. package/dist/native/tokens.js +221 -0
  363. package/dist/navitem.css +21 -1
  364. package/dist/onboarding.css +10 -2
  365. package/dist/popover.css +8 -0
  366. package/dist/progress.css +8 -0
  367. package/dist/radiogroup.css +9 -1
  368. package/dist/recordpage.css +22 -12
  369. package/dist/recordpanel.css +25 -15
  370. package/dist/recordstable.css +37 -23
  371. package/dist/resizablepanel.css +53 -0
  372. package/dist/resizablepanel.d.ts +7 -0
  373. package/dist/richtext.css +11 -3
  374. package/dist/segmented.css +8 -0
  375. package/dist/select.css +12 -4
  376. package/dist/settingsshell.css +15 -2
  377. package/dist/sidebar.css +34 -1
  378. package/dist/skeleton.css +8 -0
  379. package/dist/spinner.css +8 -0
  380. package/dist/stagebar.css +8 -0
  381. package/dist/styles.css +2051 -1111
  382. package/dist/switch.css +8 -0
  383. package/dist/table.css +14 -6
  384. package/dist/tabletoolbar.css +8 -0
  385. package/dist/tabs.css +12 -4
  386. package/dist/tasklist.css +8 -0
  387. package/dist/textarea.css +23 -3
  388. package/dist/toast.css +10 -2
  389. package/dist/tokens.css +29 -0
  390. package/dist/tokens.json +217 -0
  391. package/dist/tooltip.css +8 -0
  392. package/dist/trialbanner.css +8 -0
  393. package/dist/types/components/accordion/accordion.d.ts +10 -8
  394. package/dist/types/components/avatargroup/avatargroup.d.ts +2 -2
  395. package/dist/types/components/barchart/barchart.d.ts +4 -2
  396. package/dist/types/components/breadcrumb/breadcrumb.d.ts +2 -2
  397. package/dist/types/components/bulkbar/bulkbar.d.ts +4 -2
  398. package/dist/types/components/button/button.d.ts +8 -0
  399. package/dist/types/components/button/button.recipe.d.ts +12 -0
  400. package/dist/types/components/callout/callout.d.ts +2 -2
  401. package/dist/types/components/columncalc/columncalc.d.ts +49 -0
  402. package/dist/types/components/columncalc/columncalc.recipe.d.ts +3 -0
  403. package/dist/types/components/columncalc/index.d.ts +1 -0
  404. package/dist/types/components/datatable/datatable.d.ts +58 -3
  405. package/dist/types/components/datepicker/datepicker.d.ts +41 -18
  406. package/dist/types/components/datepicker/datepicker.recipe.d.ts +25 -2
  407. package/dist/types/components/datepicker/index.d.ts +1 -1
  408. package/dist/types/components/datepickerfield/datepickerfield.d.ts +35 -0
  409. package/dist/types/components/datepickerfield/datepickerfield.recipe.d.ts +5 -0
  410. package/dist/types/components/datepickerfield/index.d.ts +2 -0
  411. package/dist/types/components/dialog/dialog.d.ts +3 -1
  412. package/dist/types/components/divider/divider.d.ts +2 -2
  413. package/dist/types/components/donutchart/donutchart.d.ts +2 -2
  414. package/dist/types/components/drawer/drawer.d.ts +3 -1
  415. package/dist/types/components/emptystate/emptystate.d.ts +2 -2
  416. package/dist/types/components/formfield/formfield.d.ts +7 -4
  417. package/dist/types/components/input/input.d.ts +8 -2
  418. package/dist/types/components/linechart/linechart.d.ts +4 -2
  419. package/dist/types/components/menu/index.d.ts +1 -0
  420. package/dist/types/components/menu/menu-keyboard.d.ts +33 -0
  421. package/dist/types/components/menu/menu.d.ts +7 -1
  422. package/dist/types/components/multiselect/multiselect.d.ts +8 -4
  423. package/dist/types/components/popover/popover.d.ts +4 -1
  424. package/dist/types/components/progress/progress.d.ts +2 -2
  425. package/dist/types/components/radiogroup/radiogroup.d.ts +2 -2
  426. package/dist/types/components/resizablepanel/index.d.ts +2 -0
  427. package/dist/types/components/resizablepanel/resizablepanel.d.ts +75 -0
  428. package/dist/types/components/resizablepanel/resizablepanel.recipe.d.ts +3 -0
  429. package/dist/types/components/segmented/segmented.d.ts +2 -2
  430. package/dist/types/components/select/select.d.ts +2 -2
  431. package/dist/types/components/skeleton/skeleton.d.ts +2 -2
  432. package/dist/types/components/spinner/spinner.d.ts +2 -2
  433. package/dist/types/components/stagebar/stagebar.d.ts +2 -2
  434. package/dist/types/components/statcard/statcard.d.ts +2 -2
  435. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +28 -2
  436. package/dist/types/components/tabs/tabs.d.ts +2 -2
  437. package/dist/types/components/toast/toast.d.ts +7 -1
  438. package/dist/types/components/tooltip/tooltip.d.ts +8 -1
  439. package/dist/types/components/wheelpicker/index.d.ts +2 -0
  440. package/dist/types/components/wheelpicker/wheelpicker.d.ts +37 -0
  441. package/dist/types/components/wheelpicker/wheelpicker.recipe.d.ts +26 -0
  442. package/dist/types/index.d.ts +5 -0
  443. package/dist/types/product/appshell/appshell.d.ts +16 -2
  444. package/dist/types/product/authshell/authshell.d.ts +28 -0
  445. package/dist/types/product/authshell/authshell.recipe.d.ts +3 -0
  446. package/dist/types/product/authshell/index.d.ts +2 -0
  447. package/dist/types/product/board/board.d.ts +2 -2
  448. package/dist/types/product/command/command.d.ts +25 -1
  449. package/dist/types/product/entitycard/entitycard.d.ts +2 -2
  450. package/dist/types/product/flowcanvas/flowcanvas.d.ts +9 -1
  451. package/dist/types/product/onboarding/onboarding.d.ts +7 -1
  452. package/dist/types/product/recordpage/recordpage.d.ts +65 -1
  453. package/dist/types/product/recordpanel/recordpanel.d.ts +8 -2
  454. package/dist/types/product/recordstable/recordstable.d.ts +90 -1
  455. package/dist/types/product/recordstable/recordstable.tag.d.ts +10 -0
  456. package/dist/types/product/richtext/richtext.d.ts +5 -1
  457. package/dist/types/product/settingssection/settingssection.d.ts +2 -2
  458. package/dist/types/product/settingsshell/settingsshell.d.ts +6 -2
  459. package/dist/types/product/sidebar/sidebar.d.ts +8 -0
  460. package/dist/types/product/tasklist/tasklist.d.ts +5 -1
  461. package/dist/types/product/trialbanner/trialbanner.d.ts +2 -2
  462. package/dist/types/product/viewtoggle/viewtoggle.d.ts +11 -5
  463. package/dist/types/tokens/contract.d.ts +14 -3
  464. package/dist/types/tokens/elevation.d.ts +44 -0
  465. package/dist/types/tokens/index.d.ts +1 -0
  466. package/dist/types/tokens/palette.d.ts +40 -0
  467. package/dist/types/tokens/scale.d.ts +7 -0
  468. package/dist/types/tokens/semantic.d.ts +19 -0
  469. package/dist/viewtoggle.css +9 -1
  470. package/dist/wheelpicker.css +68 -0
  471. package/dist/wheelpicker.d.ts +7 -0
  472. package/package.json +160 -68
@@ -1,9 +1,23 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ArrowDown, ArrowUp, ChevronsUpDown, Plus, Search } from "lucide-react";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ArrowDown, ArrowUp, Check, ChevronsUpDown, GripVertical, Plus, Search, SlidersHorizontal, } from "lucide-react";
3
3
  import * as React from "react";
4
4
  import { Checkbox } from "../checkbox/index.js";
5
+ import { Menu, MenuItem } from "../menu/index.js";
5
6
  import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow, } from "../table/index.js";
6
7
  import { datatableRecipe } from "./datatable.recipe.js";
8
+ /** A `date` input needs `yyyy-mm-dd`; cells may hold a Date, an ISO string or
9
+ * a display string. Returns "" when it cannot be parsed, so the field opens
10
+ * empty rather than showing an invalid value. */
11
+ function toDateInputValue(v) {
12
+ if (v instanceof Date && !Number.isNaN(v.getTime()))
13
+ return v.toISOString().slice(0, 10);
14
+ if (typeof v === "string" || typeof v === "number") {
15
+ const d = new Date(v);
16
+ if (!Number.isNaN(d.getTime()))
17
+ return d.toISOString().slice(0, 10);
18
+ }
19
+ return "";
20
+ }
7
21
  function cellValue(col, row) {
8
22
  if (col.accessor)
9
23
  return col.accessor(row);
@@ -88,15 +102,78 @@ function renderTyped(col, value, avatarTone) {
88
102
  }
89
103
  }
90
104
  const CHECK_W = 40;
91
- export function DataTable({ columns, data, selectable = false, selectedIds, onSelectionChange, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder = "Search…", onEdit, stickyFirst = true, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", empty = "No results.", showCount = true, toolbar, className, }) {
105
+ export function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel = "Select all rows", selectRowLabel = (row) => `Select row ${row.id}`, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder = "Search…", searchLabel = "Search table", onEdit, stickyFirst = true, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", empty = "No results.", showCount = true, countLabel = (shown, total) => shown === total
106
+ ? `${total} ${total === 1 ? "row" : "rows"}`
107
+ : `${shown} of ${total}`, toolbar, className, reorderRowLabel = "Reorder row", ...rest }) {
92
108
  const [query, setQuery] = React.useState("");
93
109
  const [internalSort, setInternalSort] = React.useState(defaultSort ?? null);
110
+ // Column list the table actually renders. Seeded from `columns`; the header
111
+ // menu mutates this copy and reports upward via `onColumnsChange`.
112
+ const [internalCols, setInternalCols] = React.useState(columnsProp);
113
+ React.useEffect(() => setInternalCols(columnsProp), [columnsProp]);
114
+ /** Every column, hidden ones included — what the column manager lists. */
115
+ const allColumns = internalCols;
116
+ /** What the grid actually renders. */
117
+ const columns = React.useMemo(() => internalCols.filter((c) => !c.hidden), [internalCols]);
118
+ const applyColumns = React.useCallback((next) => {
119
+ setInternalCols(next);
120
+ onColumnsChange?.(next);
121
+ }, [onColumnsChange]);
122
+ const moveColumn = React.useCallback((key, dir) => {
123
+ const i = allColumns.findIndex((c) => c.key === key);
124
+ const j = i + dir;
125
+ if (i < 0 || j < 0 || j >= allColumns.length)
126
+ return;
127
+ const next = [...allColumns];
128
+ [next[i], next[j]] = [next[j], next[i]];
129
+ applyColumns(next);
130
+ }, [allColumns, applyColumns]);
131
+ const hideColumn = React.useCallback((key) => applyColumns(allColumns.map((c) => (c.key === key ? { ...c, hidden: true } : c))), [allColumns, applyColumns]);
132
+ const renameColumn = React.useCallback((key, header) => applyColumns(allColumns.map((c) => (c.key === key ? { ...c, header } : c))), [allColumns, applyColumns]);
133
+ const [renaming, setRenaming] = React.useState(null);
134
+ const showColumn = React.useCallback((key) => applyColumns(allColumns.map((c) => (c.key === key ? { ...c, hidden: false } : c))), [allColumns, applyColumns]);
135
+ const [selCell, setSelCell] = React.useState(null);
136
+ const gridRef = React.useRef(null);
94
137
  const sort = sortProp !== undefined ? sortProp : internalSort;
138
+ // One shape downstream: [] when unsorted, ordered by precedence otherwise.
139
+ const sorts = React.useMemo(() => (sort == null ? [] : Array.isArray(sort) ? sort : [sort]), [sort]);
140
+ const sortDirByKey = React.useMemo(() => new Map(sorts.map((s) => [s.key, s.dir])), [sorts]);
95
141
  const setSort = React.useCallback((next) => {
96
142
  onSortChange?.(next);
97
143
  if (sortProp === undefined)
98
144
  setInternalSort(next);
99
145
  }, [onSortChange, sortProp]);
146
+ // Row drag-to-reorder is meaningless once a sort or grouping decides row
147
+ // order — the grip would let the user drag a row the comparator/group
148
+ // would immediately put it back to. Hide the affordance rather than let it
149
+ // lie.
150
+ const showGrip = Boolean(onRowsReorder) && sorts.length === 0 && !groupBy;
151
+ const GRIP_W = 20;
152
+ // key of the row currently being dragged, and the row currently hovered as
153
+ // the drop target — mirrors RecordsTable's `dragCol`/`dragSort` state.
154
+ const [dragRowId, setDragRowId] = React.useState(null);
155
+ const [dropRowId, setDropRowId] = React.useState(null);
156
+ // Drop the dragged row immediately before `toId`. Operates on the full
157
+ // `data` prop (not the filtered/sorted `rows`) so the callback always gets
158
+ // the complete array in its new order, and a filtered-out row keeps its
159
+ // relative position. Splice-then-re-find-index (same shape as
160
+ // RecordsTable's reorderColumn) so dropping above vs. below the dragged
161
+ // row's origin both land in the right slot.
162
+ function reorderRows(fromId, toId) {
163
+ setDragRowId(null);
164
+ setDropRowId(null);
165
+ if (!onRowsReorder || fromId === toId)
166
+ return;
167
+ const from = data.findIndex((r) => r.id === fromId);
168
+ let to = data.findIndex((r) => r.id === toId);
169
+ if (from < 0 || to < 0)
170
+ return;
171
+ const next = [...data];
172
+ const [moved] = next.splice(from, 1);
173
+ to = next.findIndex((r) => r.id === toId);
174
+ next.splice(to, 0, moved);
175
+ onRowsReorder(next);
176
+ }
100
177
  const [internalSel, setInternalSel] = React.useState(new Set());
101
178
  const selected = React.useMemo(() => (selectedIds ? new Set(selectedIds) : internalSel), [selectedIds, internalSel]);
102
179
  const setSelected = React.useCallback((next) => {
@@ -111,7 +188,8 @@ export function DataTable({ columns, data, selectable = false, selectedIds, onSe
111
188
  const [resizingKey, setResizingKey] = React.useState(null);
112
189
  const resizeRef = React.useRef(null);
113
190
  const colWidth = (col) => widths[col.key] ?? col.width ?? (col.type === "entity" ? 220 : 160);
114
- const minWidth = (selectable ? CHECK_W : 0) +
191
+ const minWidth = (showGrip ? GRIP_W : 0) +
192
+ (selectable ? CHECK_W : 0) +
115
193
  columns.reduce((sum, col) => sum + colWidth(col), 0);
116
194
  const colByKey = React.useMemo(() => {
117
195
  const m = new Map();
@@ -127,20 +205,46 @@ export function DataTable({ columns, data, selectable = false, selectedIds, onSe
127
205
  return data.filter((row) => cols.some((c) => asText(cellValue(c, row)).toLowerCase().includes(q)));
128
206
  }, [data, columns, query]);
129
207
  const rows = React.useMemo(() => {
130
- if (!sort)
131
- return filtered;
132
- const col = colByKey.get(sort.key);
133
- if (!col)
208
+ const active = sorts
209
+ .map((s) => ({ col: colByKey.get(s.key), dir: s.dir === "asc" ? 1 : -1 }))
210
+ .filter((s) => Boolean(s.col));
211
+ if (active.length === 0)
134
212
  return filtered;
135
- const dir = sort.dir === "asc" ? 1 : -1;
136
213
  return [...filtered].sort((a, b) => {
137
- const av = cellValue(col, a);
138
- const bv = cellValue(col, b);
139
- if (typeof av === "number" && typeof bv === "number")
140
- return (av - bv) * dir;
141
- return asText(av).localeCompare(asText(bv)) * dir;
214
+ for (const { col, dir } of active) {
215
+ const av = cellValue(col, a);
216
+ const bv = cellValue(col, b);
217
+ const cmp = typeof av === "number" && typeof bv === "number"
218
+ ? av - bv
219
+ : asText(av).localeCompare(asText(bv));
220
+ if (cmp !== 0)
221
+ return cmp * dir;
222
+ }
223
+ return 0;
142
224
  });
143
- }, [filtered, sort, colByKey]);
225
+ }, [filtered, sorts, colByKey]);
226
+ /**
227
+ * Rows bucketed under a heading, preserving first-seen group order (Attio
228
+ * groups a view without reordering within a group). One bucket with a null
229
+ * group when `groupBy` is absent, so the render path is identical either way.
230
+ */
231
+ const groupedRows = React.useMemo(() => {
232
+ if (!groupBy)
233
+ return [{ group: null, rows }];
234
+ const buckets = new Map();
235
+ for (const row of rows) {
236
+ const g = groupBy(row);
237
+ const bucket = buckets.get(g);
238
+ if (bucket)
239
+ bucket.push(row);
240
+ else
241
+ buckets.set(g, [row]);
242
+ }
243
+ return [...buckets].map(([group, groupRows]) => ({
244
+ group,
245
+ rows: groupRows,
246
+ }));
247
+ }, [rows, groupBy]);
144
248
  const allSelected = rows.length > 0 && rows.every((r) => selected.has(r.id));
145
249
  const someSelected = selected.size > 0 && !allSelected;
146
250
  function toggleAll() {
@@ -152,30 +256,106 @@ export function DataTable({ columns, data, selectable = false, selectedIds, onSe
152
256
  setSelected(next);
153
257
  }
154
258
  function cycleSort(key) {
155
- if (!sort || sort.key !== key)
259
+ // Clicking a header drives a single sort, as before. Multi-sort is supplied
260
+ // by the caller through the `sort` prop (Attio builds it in its sort popover).
261
+ const dir = sortDirByKey.get(key);
262
+ if (!dir)
156
263
  setSort({ key, dir: "asc" });
157
- else if (sort.dir === "asc")
264
+ else if (dir === "asc")
158
265
  setSort({ key, dir: "desc" });
159
266
  else
160
267
  setSort(null);
161
268
  }
269
+ /**
270
+ * Which editor a column gets. Mirrors RecordsTable — the Attio-measured
271
+ * sibling — rather than giving every type the same text box:
272
+ * number/currency numeric, with a decimal keypad on touch
273
+ * date a native date field
274
+ * text/entity a plain text field
275
+ * `status`, `reference` and `tags` are pickers in RecordsTable, not
276
+ * double-click editors, so they are not editable here either.
277
+ */
278
+ function editorFor(col) {
279
+ switch (col.type) {
280
+ case "number":
281
+ case "currency":
282
+ return { type: "number", inputMode: "decimal", step: "any" };
283
+ case "date":
284
+ return { type: "date" };
285
+ default:
286
+ return { type: "text", inputMode: "text" };
287
+ }
288
+ }
289
+ /**
290
+ * Spreadsheet keyboard model, ported from RecordsTable: arrows move the
291
+ * selected cell, Enter opens its editor, Escape clears, and Cmd/Ctrl+C
292
+ * copies the cell's RENDERED text (what the user sees, not the raw value).
293
+ */
294
+ function onGridKeyDown(e) {
295
+ if (!selCell || editing)
296
+ return;
297
+ if ((e.metaKey || e.ctrlKey) && (e.key === "c" || e.key === "C")) {
298
+ const row = rows.find((rw) => rw.id === selCell.id);
299
+ const col = columns.find((cc) => cc.key === selCell.key);
300
+ if (row && col)
301
+ navigator.clipboard?.writeText(formatCell(col.type, cellValue(col, row), col.symbol));
302
+ e.preventDefault();
303
+ return;
304
+ }
305
+ const r = rows.findIndex((row) => row.id === selCell.id);
306
+ const c = columns.findIndex((col) => col.key === selCell.key);
307
+ if (r < 0 || c < 0)
308
+ return;
309
+ let nr = r;
310
+ let nc = c;
311
+ if (e.key === "ArrowUp")
312
+ nr = Math.max(0, r - 1);
313
+ else if (e.key === "ArrowDown")
314
+ nr = Math.min(rows.length - 1, r + 1);
315
+ else if (e.key === "ArrowLeft")
316
+ nc = Math.max(0, c - 1);
317
+ else if (e.key === "ArrowRight")
318
+ nc = Math.min(columns.length - 1, c + 1);
319
+ else if (e.key === "Escape") {
320
+ setSelCell(null);
321
+ return;
322
+ }
323
+ else if (e.key === "Enter") {
324
+ if (columns[c]?.editable) {
325
+ e.preventDefault();
326
+ setEditing({ id: selCell.id, key: selCell.key });
327
+ }
328
+ return;
329
+ }
330
+ else
331
+ return;
332
+ e.preventDefault();
333
+ setSelCell({ id: rows[nr].id, key: columns[nc].key });
334
+ }
162
335
  function commitEdit(id, key, value) {
163
336
  onEdit?.(id, key, value);
164
337
  setEditing(null);
165
338
  }
166
- const totalCols = columns.length + (selectable ? 1 : 0);
339
+ const totalCols = columns.length + (selectable ? 1 : 0) + (showGrip ? 1 : 0);
167
340
  const hasSummary = columns.some((c) => c.summary);
168
- // sticky attrs for the leading column(s): selection col + first data column
341
+ // sticky attrs for the leading column(s): grip col (index -2) + selection
342
+ // col (-1) + first data column (0). Each offsets by whatever leading
343
+ // columns come before it, so the group stays contiguous when scrolled.
169
344
  const stickyCol = (index) => {
170
345
  if (!stickyFirst)
171
346
  return {};
172
- if (selectable && index === -1)
347
+ if (showGrip && index === -2)
173
348
  return { "data-sticky": "", style: { left: 0 } };
349
+ if (selectable && index === -1)
350
+ return {
351
+ "data-sticky": "",
352
+ style: { left: showGrip ? GRIP_W : 0 },
353
+ };
174
354
  if (index === 0)
175
355
  return {
176
356
  "data-sticky": "",
177
357
  "data-sticky-edge": "",
178
- style: { left: selectable ? CHECK_W : 0 },
358
+ style: { left: (showGrip ? GRIP_W : 0) + (selectable ? CHECK_W : 0) },
179
359
  };
180
360
  return {};
181
361
  };
@@ -205,41 +385,88 @@ export function DataTable({ columns, data, selectable = false, selectedIds, onSe
205
385
  e.target.releasePointerCapture(e.pointerId);
206
386
  }
207
387
  function ChevronFor({ colKey }) {
208
- if (sort?.key === colKey)
209
- return sort.dir === "asc" ? (_jsx(ArrowUp, { className: "datatable-chevron", size: 13, strokeWidth: 2 })) : (_jsx(ArrowDown, { className: "datatable-chevron", size: 13, strokeWidth: 2 }));
388
+ const dir = sortDirByKey.get(colKey);
389
+ if (dir)
390
+ return dir === "asc" ? (_jsx(ArrowUp, { className: "datatable-chevron", size: 13, strokeWidth: 2 })) : (_jsx(ArrowDown, { className: "datatable-chevron", size: 13, strokeWidth: 2 }));
210
391
  return (_jsx(ChevronsUpDown, { className: "datatable-chevron", size: 13, strokeWidth: 2 }));
211
392
  }
212
- return (_jsxs("div", { className: datatableRecipe({ className }), children: [(filterable || showCount || toolbar) && (_jsxs("div", { className: "datatable-toolbar", children: [filterable && (_jsxs("span", { className: "datatable-search", children: [_jsx(Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), _jsx("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": "Search table" })] })), showCount && (_jsx("span", { className: "datatable-count", children: rows.length === data.length
213
- ? `${data.length} ${data.length === 1 ? "row" : "rows"}`
214
- : `${rows.length} of ${data.length}` })), toolbar] })), _jsxs(Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
393
+ return (_jsxs("div", { ref: gridRef, className: datatableRecipe({ className }), tabIndex: -1, onKeyDown: onGridKeyDown, ...rest, children: [(filterable || showCount || toolbar || columnMenu) && (_jsxs("div", { className: "datatable-toolbar", children: [columnMenu && (_jsxs(Menu, { align: "start", trigger: _jsxs("button", { type: "button", className: "datatable-viewsettings", children: [_jsx(SlidersHorizontal, { size: 14, strokeWidth: 1.75 }), "View settings"] }), children: [_jsx("div", { className: "datatable-group-label", children: "Columns" }), allColumns.map((c) => (_jsxs(MenuItem, { onSelect: () => c.hidden ? showColumn(c.key) : hideColumn(c.key), children: [_jsx(Check, { size: 14, strokeWidth: 2, style: { opacity: c.hidden ? 0 : 1 } }), typeof c.header === "string" ? c.header : c.key] }, c.key)))] })), filterable && (_jsxs("span", { className: "datatable-search", children: [_jsx(Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), _jsx("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": searchLabel })] })), showCount && (_jsx("span", { className: "datatable-count", children: countLabel(rows.length, data.length) })), toolbar] })), _jsxs(Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
215
394
  onScroll: (e) => setScrolledX(e.currentTarget.scrollLeft > 0),
216
395
  ...(scrolledX ? { "data-scrolled-x": "" } : {}),
217
- }, children: [_jsxs("colgroup", { children: [selectable && _jsx("col", { style: { width: CHECK_W } }), columns.map((col) => (_jsx("col", { style: { width: colWidth(col) } }, col.key)))] }), _jsx(TableHeader, { children: _jsxs(TableRow, { children: [selectable && (_jsx(TableHead, { className: "datatable-col-check", ...stickyCol(-1), children: _jsx("span", { className: "datatable-check", children: _jsx(Checkbox, { "aria-label": "Select all rows", checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) })), columns.map((col, i) => {
396
+ }, children: [_jsxs("colgroup", { children: [showGrip && _jsx("col", { style: { width: GRIP_W } }), selectable && _jsx("col", { style: { width: CHECK_W } }), columns.map((col) => (_jsx("col", { style: { width: colWidth(col) } }, col.key)))] }), _jsx(TableHeader, { children: _jsxs(TableRow, { children: [showGrip && (_jsx(TableHead, { className: "datatable-col-grip", ...stickyCol(-2) })), selectable && (_jsx(TableHead, { className: "datatable-col-check", ...stickyCol(-1), children: _jsx("span", { className: "datatable-check", children: _jsx(Checkbox, { "aria-label": selectAllLabel, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) })), columns.map((col, i) => {
218
397
  const Icon = col.icon;
219
398
  const inner = (_jsxs("span", { className: "datatable-th-inner", children: [Icon ? _jsx(Icon, { size: 14, strokeWidth: 1.75 }) : null, _jsx("span", { className: "datatable-th-label", children: col.header }), col.sortable ? _jsx(ChevronFor, { colKey: col.key }) : null] }));
220
- return (_jsxs(TableHead, { align: alignFor(col), ...stickyCol(i), children: [col.sortable ? (_jsx("button", { type: "button", className: "datatable-sort", "data-sorted": sort?.key === col.key ? sort.dir : undefined, onClick: () => cycleSort(col.key), children: inner })) : (inner), col.resizable !== false && (_jsx("span", { className: "datatable-resize", "data-resizing": resizingKey === col.key ? "" : undefined, onPointerDown: (e) => startResize(col, e), onPointerMove: moveResize, onPointerUp: endResize }))] }, col.key));
221
- })] }) }), _jsx(TableBody, { children: rows.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: totalCols, children: _jsx("div", { className: "datatable-empty", children: empty }) }) })) : (rows.map((row) => (_jsxs(TableRow, { "data-selected": selected.has(row.id) ? "" : undefined, onClick: onRowClick ? () => onRowClick(row) : undefined, style: onRowClick ? { cursor: "pointer" } : undefined, children: [selectable && (_jsx(TableCell, { className: "datatable-col-check", ...stickyCol(-1), onClick: (e) => e.stopPropagation(), children: _jsx("span", { className: "datatable-check", children: _jsx(Checkbox, { "aria-label": `Select row ${row.id}`, checked: selected.has(row.id), onChange: () => toggleRow(row.id) }) }) })), columns.map((col, i) => {
222
- const isEditing = editing?.id === row.id && editing?.key === col.key;
223
- const value = cellValue(col, row);
224
- const sticky = stickyCol(i);
225
- if (isEditing) {
226
- return (_jsx(TableCell, { align: alignFor(col), ...sticky, onClick: (e) => e.stopPropagation(), children: _jsx("input", { className: "datatable-edit",
227
- // biome-ignore lint/a11y/noAutofocus: focus the field the moment it opens
228
- autoFocus: true, defaultValue: asText(value), "aria-label": `Edit ${col.key}`, onKeyDown: (e) => {
229
- if (e.key === "Enter")
230
- commitEdit(row.id, col.key, e.currentTarget.value);
399
+ return (_jsxs(TableHead, { align: alignFor(col), ...stickyCol(i), children: [renaming === col.key ? (_jsx("input", {
400
+ // biome-ignore lint/a11y/noAutofocus: the rename item opens this field
401
+ autoFocus: true, className: "datatable-th-rename", defaultValue: typeof col.header === "string" ? col.header : "", "aria-label": `Rename column`, onBlur: (e) => {
402
+ renameColumn(col.key, e.currentTarget.value);
403
+ setRenaming(null);
404
+ }, onKeyDown: (e) => {
405
+ if (e.key === "Enter") {
406
+ renameColumn(col.key, e.currentTarget.value);
407
+ setRenaming(null);
408
+ }
231
409
  else if (e.key === "Escape")
232
- setEditing(null);
233
- }, onBlur: (e) => commitEdit(row.id, col.key, e.currentTarget.value) }) }, col.key));
234
- }
235
- return (_jsx(TableCell, { align: alignFor(col), ...sticky, className: col.editable ? "datatable-editable" : undefined, onClick: col.editable
236
- ? (e) => {
237
- e.stopPropagation();
238
- setEditing({ id: row.id, key: col.key });
410
+ setRenaming(null);
411
+ } })) : columnMenu ? (_jsxs(Menu, { align: "start", trigger: _jsx("button", { type: "button", className: "datatable-sort", "data-sorted": sortDirByKey.get(col.key), "aria-label": `${typeof col.header === "string"
412
+ ? col.header
413
+ : col.key} column options`, children: inner }), children: [_jsx(MenuItem, { onSelect: () => setSort({ key: col.key, dir: "asc" }), children: "Sort ascending" }), _jsx(MenuItem, { onSelect: () => setSort({ key: col.key, dir: "desc" }), children: "Sort descending" }), col.managed === false ? null : (_jsxs(_Fragment, { children: [_jsx(MenuItem, { onSelect: () => moveColumn(col.key, -1), children: "Move left" }), _jsx(MenuItem, { onSelect: () => moveColumn(col.key, 1), children: "Move right" }), _jsx(MenuItem, { onSelect: () => setRenaming(col.key), children: "Edit column label" }), _jsx(MenuItem, { onSelect: () => hideColumn(col.key), children: "Hide from view" })] }))] })) : col.sortable ? (_jsx("button", { type: "button", className: "datatable-sort", "data-sorted": sortDirByKey.get(col.key), onClick: () => cycleSort(col.key), children: inner })) : (inner), col.resizable !== false && (_jsx("span", { className: "datatable-resize", "data-resizing": resizingKey === col.key ? "" : undefined, onPointerDown: (e) => startResize(col, e), onPointerMove: moveResize, onPointerUp: endResize }))] }, col.key));
414
+ })] }) }), _jsx(TableBody, { children: error ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: totalCols, children: _jsx("div", { className: "datatable-empty", children: error }) }) })) : rows.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: totalCols, children: _jsx("div", { className: "datatable-empty", children: empty }) }) })) : (groupedRows.map(({ group, rows: groupRows }) => (_jsxs(React.Fragment, { children: [group !== null && (_jsx(TableRow, { children: _jsxs(TableCell, { colSpan: totalCols, className: "datatable-group", children: [_jsx("span", { className: "datatable-group-label", children: group }), _jsx("span", { className: "datatable-group-count", children: groupRows.length })] }) })), groupRows.map((row) => (_jsxs(TableRow, { "data-selected": selected.has(row.id) ? "" : undefined, "data-drop-target": showGrip &&
415
+ dragRowId &&
416
+ dragRowId !== row.id &&
417
+ dropRowId === row.id
418
+ ? ""
419
+ : undefined, onClick: onRowClick ? () => onRowClick(row) : undefined, style: onRowClick ? { cursor: "pointer" } : undefined, onDragOver: showGrip && dragRowId
420
+ ? (e) => {
421
+ e.preventDefault();
422
+ if (dropRowId !== row.id)
423
+ setDropRowId(row.id);
424
+ }
425
+ : undefined, onDrop: showGrip && dragRowId
426
+ ? (e) => {
427
+ e.preventDefault();
428
+ reorderRows(dragRowId, row.id);
429
+ }
430
+ : undefined, children: [showGrip && (_jsx(TableCell, { className: "datatable-col-grip", ...stickyCol(-2), onClick: (e) => e.stopPropagation(), children: _jsx("button", { type: "button", className: "datatable-grip", "aria-label": reorderRowLabel, draggable: true, onDragStart: (e) => {
431
+ setDragRowId(row.id);
432
+ e.dataTransfer.effectAllowed = "move";
433
+ }, onDragEnd: () => {
434
+ setDragRowId(null);
435
+ setDropRowId(null);
436
+ }, children: _jsx(GripVertical, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }) })), selectable && (_jsx(TableCell, { className: "datatable-col-check", ...stickyCol(-1), onClick: (e) => e.stopPropagation(), children: _jsx("span", { className: "datatable-check", children: _jsx(Checkbox, { "aria-label": selectRowLabel(row), checked: selected.has(row.id), onChange: () => toggleRow(row.id) }) }) })), columns.map((col, i) => {
437
+ const isEditing = editing?.id === row.id && editing?.key === col.key;
438
+ const value = cellValue(col, row);
439
+ const sticky = stickyCol(i);
440
+ if (isEditing) {
441
+ return (_jsx(TableCell, { align: alignFor(col), ...sticky, onClick: (e) => e.stopPropagation(), children: _jsx("input", { className: "datatable-edit",
442
+ // biome-ignore lint/a11y/noAutofocus: focus the field the moment it opens
443
+ autoFocus: true, ...editorFor(col), "data-editor": editorFor(col).type, defaultValue: col.type === "date"
444
+ ? toDateInputValue(value)
445
+ : asText(value), "aria-label": `Edit ${col.key}`, onKeyDown: (e) => {
446
+ if (e.key === "Enter")
447
+ commitEdit(row.id, col.key, e.currentTarget.value);
448
+ else if (e.key === "Escape")
449
+ setEditing(null);
450
+ }, onBlur: (e) => commitEdit(row.id, col.key, e.currentTarget.value) }) }, col.key));
239
451
  }
240
- : undefined, children: col.render
241
- ? col.render(value, row)
242
- : renderTyped(col, col.format ? col.format(value, row) : value, avatarTone) }, col.key));
243
- })] }, row.id)))) }), (hasSummary || onAddRow) && (_jsxs(TableFooter, { children: [hasSummary && (_jsxs(TableRow, { children: [selectable && _jsx(TableCell, { ...stickyCol(-1) }), columns.map((col, i) => (_jsx(TableCell, { align: alignFor(col), ...stickyCol(i), children: col.summary ? col.summary(rows) : null }, col.key)))] })), onAddRow && (_jsx(TableRow, { children: _jsx(TableCell, { className: "datatable-addcell", colSpan: totalCols, children: _jsxs("button", { type: "button", className: "datatable-addrow", onClick: onAddRow, children: [_jsx(Plus, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), addRowLabel] }) }) }))] }))] })] }));
452
+ return (_jsx(TableCell, { align: alignFor(col), ...sticky, className: col.editable ? "datatable-editable" : undefined, "data-selected": selCell?.id === row.id && selCell?.key === col.key
453
+ ? ""
454
+ : undefined, onClick: (e) => {
455
+ // the keyboard model's anchor; also opens the
456
+ // editor when the column allows it
457
+ setSelCell({ id: row.id, key: col.key });
458
+ gridRef.current?.focus({ preventScroll: true });
459
+ if (col.editable) {
460
+ // Opening the inline editor must not also fire
461
+ // the row's onRowClick and navigate away. Every
462
+ // other cell click has to keep bubbling, or
463
+ // onRowClick never fires at all.
464
+ e.stopPropagation();
465
+ setEditing({ id: row.id, key: col.key });
466
+ }
467
+ }, children: col.render
468
+ ? col.render(value, row)
469
+ : renderTyped(col, col.format ? col.format(value, row) : value, avatarTone) }, col.key));
470
+ })] }, row.id)))] }, group ?? "__ungrouped")))) }), (hasSummary || onAddRow) && (_jsxs(TableFooter, { children: [hasSummary && (_jsxs(TableRow, { children: [showGrip && _jsx(TableCell, { ...stickyCol(-2) }), selectable && _jsx(TableCell, { ...stickyCol(-1) }), columns.map((col, i) => (_jsx(TableCell, { align: alignFor(col), ...stickyCol(i), children: col.summary ? col.summary(rows) : null }, col.key)))] })), onAddRow && (_jsx(TableRow, { children: _jsx(TableCell, { className: "datatable-addcell", colSpan: totalCols, children: _jsxs("button", { type: "button", className: "datatable-addrow", onClick: onAddRow, children: [_jsx(Plus, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), addRowLabel] }) }) }))] }))] })] }));
244
471
  }
245
472
  DataTable.displayName = "DataTable";
@@ -1,5 +1,5 @@
1
1
  import { defineRecipe, resolveRecipe } from "../../core/index.js";
2
- import { contract as c } from "../../tokens/index.js";
2
+ import { contract as c, elevation as e } from "../../tokens/index.js";
3
3
  // The feature-rich, config-driven data grid (sort / filter / selection /
4
4
  // inline edit) built on the composable `Table` primitives. This recipe adds the
5
5
  // toolbar, sortable header buttons, selection cells, selected-row tint, and the
@@ -9,26 +9,51 @@ const config = defineRecipe({
9
9
  base: `display: flex; flex-direction: column; gap: ${c.space["2.5"]}; font-family: ${c.font.sans};
10
10
  & .datatable-toolbar { display: flex; align-items: center; gap: ${c.space["2"]}; }
11
11
  & .datatable-search { position: relative; flex: 1; max-width: 280px; display: inline-flex; align-items: center; }
12
- & .datatable-search svg { position: absolute; left: ${c.space["2"]}; color: ${c.fgMuted}; pointer-events: none; }
13
- & .datatable-search input { width: 100%; height: 32px; padding: 0 ${c.space["2"]} 0 ${c.space["6"]}; border: none; border-radius: ${c.radius.md}; background: ${c.bgSurface}; box-shadow: 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); font-family: inherit; font-size: ${c.text.lg}; color: ${c.fgPrimary}; outline: none; transition: box-shadow .15s; }
12
+ & .datatable-search svg { position: absolute; inset-inline-start: ${c.space["2"]}; color: ${c.fgMuted}; pointer-events: none; }
13
+ & .datatable-search input { width: 100%; height: 32px; padding: 0 ${c.space["2"]} 0 ${c.space["6"]}; border: none; border-radius: ${c.radius.md}; background: ${c.bgSurface}; box-shadow: ${e.field}; font-family: inherit; font-size: ${c.text.lg}; color: ${c.fgPrimary}; outline: none; transition: box-shadow .15s; }
14
14
  & .datatable-search input::placeholder { color: ${c.fgMuted}; }
15
15
  & .datatable-search input:focus { box-shadow: inset 0 0 0 1px ${c.bgBrandSolid}; }
16
- & .datatable-count { margin-left: auto; font-size: ${c.text.md}; color: ${c.fgMuted}; }
17
- & .datatable-th-inner { display: inline-flex; align-items: center; gap: ${c.space["1.5"]}; width: 100%; height: 100%; }
16
+ & .datatable-count { margin-inline-start: auto; font-size: ${c.text.md}; color: ${c.fgMuted}; }
17
+ /* Attio's header cell has no padding of its own -- the button owns the
18
+ full cell so the whole header is clickable (its own inset is 12px).
19
+ Mirrors the summary-row fix. */
20
+ & th { padding: 0; }
21
+ /* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger):
22
+ Menu wraps its trigger in a flex div that sizes to its content, so a
23
+ long header grew past the column instead of filling it -- with nothing
24
+ left to squeeze, the label's own ellipsis CSS (below) had no properly
25
+ -sized box to truncate against, and the th's own overflow hard-clipped
26
+ it with no "...". Fill the wrapper, scoped to th so Menu's default
27
+ (correct everywhere else) is untouched. */
28
+ & th .menu { width: 100%; height: 100%; }
29
+ & .datatable-th-inner { display: inline-flex; align-items: center; gap: ${c.space["1.5"]}; width: 100%; min-width: 0; height: 100%; }
18
30
  & .datatable-th-inner > svg { flex-shrink: 0; color: ${c.fgMuted}; }
19
- & .datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
20
- & .datatable-sort { display: inline-flex; align-items: center; gap: ${c.space["1.5"]}; width: 100%; height: 100%; margin: 0; padding: 0; border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: left; cursor: pointer; }
31
+ /* Attio's summary cell has NO padding of its own -- the calculation trigger
32
+ owns the whole 246x37 area so a click anywhere in the cell opens the
33
+ menu. Zero the cell's inset and let ColumnCalc supply the 12px. */
34
+ & tfoot td { padding: 0; }
35
+ /* Group heading row -- Attio groups a view under a subtle label with the
36
+ bucket's count beside it. */
37
+ & .datatable-viewsettings { display: inline-flex; align-items: center; gap: ${c.space["1.5"]}; height: ${c.size.row}; margin: 0; padding: 0 ${c.space["2"]}; border: none; border-radius: ${c.radius.md}; background: transparent; color: ${c.fgMuted}; font-family: inherit; font-size: ${c.text.md}; font-weight: ${c.weight.medium}; white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
38
+ & .datatable-viewsettings:hover { background: color-mix(in srgb, ${c.fgPrimary} 4%, transparent); color: ${c.fgPrimary}; }
39
+ & .datatable-group-label { padding: ${c.space["1.5"]} ${c.space["2"]} ${c.space["1"]}; font-size: ${c.text.sm}; font-weight: ${c.weight.medium}; color: ${c.fgMuted}; }
40
+ & .datatable-group { height: ${c.size.menuRow}; padding: 0 ${c.space["3"]}; background: ${c.bgSubtle}; border-bottom: 1px solid ${c.borderSubtle}; font-size: ${c.text.md}; font-weight: ${c.weight.medium}; color: color-mix(in srgb, ${c.fgPrimary} 63%, transparent); }
41
+ & .datatable-group-count { margin-inline-start: ${c.space["1.5"]}; color: ${c.fgMuted}; font-variant-numeric: tabular-nums; }
42
+ & .datatable-th-rename { width: 100%; min-width: 0; height: ${c.size.row}; margin: 0; padding: 0 ${c.space["1"]}; border: none; border-radius: ${c.radius.md}; background: ${c.bgSurface}; box-shadow: inset 0 0 0 1px ${c.bgBrandSolid}; font-family: inherit; font-size: ${c.text.lg}; font-weight: ${c.weight.medium}; color: ${c.fgPrimary}; outline: none; }
43
+ & .datatable-th-rename:focus { box-shadow: inset 0 0 0 1px ${c.bgBrandSolid}; }
44
+ & .datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
45
+ & .datatable-sort { display: flex; align-items: center; gap: ${c.space["1.5"]}; width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 ${c.space["2"]}; border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
21
46
  & th[data-align="right"] .datatable-sort { justify-content: flex-end; }
22
- & .datatable-chevron { margin-left: auto; flex-shrink: 0; color: ${c.fgMuted}; opacity: 0; transition: opacity .12s; }
23
- & th[data-align="right"] .datatable-chevron { margin-left: 0; }
47
+ & .datatable-chevron { margin-inline-start: auto; flex-shrink: 0; color: ${c.fgMuted}; opacity: 0; transition: opacity .12s; }
48
+ & th[data-align="right"] .datatable-chevron { margin-inline-start: 0; }
24
49
  & .datatable-sort:hover .datatable-chevron { opacity: 0.6; }
25
50
  & .datatable-sort[data-sorted] .datatable-chevron { opacity: 1; color: ${c.fgPrimary}; }
26
51
  /* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
27
52
  & th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: ${c.bgSurface}; }
28
53
  & th[data-sticky] { z-index: 3; }
29
- & tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, ${c.bgBrandSolid} 6%, ${c.bgSurface}); }
30
- & tbody tr:hover td[data-sticky] { background: color-mix(in srgb, ${c.fgPrimary} 3%, ${c.bgSurface}); }
31
- & .table-scroll[data-scrolled-x] [data-sticky-edge] { clip-path: inset(0 -14px 0 0); box-shadow: 8px 0 12px -8px rgba(28,40,64,0.22); }
54
+ & tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, ${c.bgBrandSolid} 10%, ${c.bgSurface}); }
55
+ & tbody tr:hover td[data-sticky] { background: color-mix(in srgb, ${c.fgPrimary} 4%, ${c.bgSurface}); }
56
+ & .table-scroll[data-scrolled-x] [data-sticky-edge] { clip-path: inset(0 -38px 0 0); box-shadow: 6px 0 16px 4px rgba(0,0,0,0.12); }
32
57
  /* add-row + summary footer */
33
58
  & .datatable-addcell { padding: 0; border-top: none; }
34
59
  & .datatable-addrow { display: flex; align-items: center; gap: ${c.space["2"]}; width: 100%; height: ${c.size.tableRow}; padding: 0 ${c.space["2"]}; border: none; border-top: 1px solid ${c.borderSubtle}; background: ${c.bgSurface}; color: ${c.fgMuted}; font-family: inherit; font-size: ${c.text.lg}; cursor: pointer; transition: background-color .12s; }
@@ -36,10 +61,11 @@ const config = defineRecipe({
36
61
  & .datatable-addrow svg { flex-shrink: 0; }
37
62
  & .datatable-check { display: flex; align-items: center; justify-content: center; }
38
63
  & .datatable-col-check { width: 40px; padding: 0; text-align: center; }
39
- & tbody tr[data-selected] td { background: color-mix(in srgb, ${c.bgBrandSolid} 6%, ${c.bgSurface}); }
40
- & tbody tr[data-selected]:hover td { background: color-mix(in srgb, ${c.bgBrandSolid} 10%, ${c.bgSurface}); }
64
+ & tbody tr[data-selected] td { background: color-mix(in srgb, ${c.bgBrandSolid} 10%, ${c.bgSurface}); }
65
+ & tbody tr[data-selected]:hover td { background: color-mix(in srgb, ${c.fgPrimary} 4%, color-mix(in srgb, ${c.bgBrandSolid} 10%, ${c.bgSurface})); }
41
66
  & .datatable-editable:hover { background: color-mix(in srgb, ${c.fgPrimary} 4%, ${c.bgSurface}); cursor: text; }
42
67
  & .datatable-edit { width: 100%; height: 28px; margin: 0; padding: 0 ${c.space["1.5"]}; border: none; border-radius: ${c.radius.sm}; background: ${c.bgSurface}; box-shadow: inset 0 0 0 1px ${c.bgBrandSolid}; font-family: inherit; font-size: ${c.text.lg}; color: ${c.fgPrimary}; outline: none; vertical-align: middle; }
68
+ & .datatable-edit:focus { box-shadow: inset 0 0 0 1px ${c.bgBrandSolid}; }
43
69
  & .datatable-empty { padding: ${c.space["8"]} ${c.space["3"]}; text-align: center; color: ${c.fgMuted}; font-size: ${c.text.lg}; }
44
70
  /* fixed layout so column widths (and resize) are exact — like RecordsTable */
45
71
  & table { table-layout: fixed; }
@@ -54,7 +80,7 @@ const config = defineRecipe({
54
80
  & .datatable-avatar[data-tone="success"] { background: ${c.bgSuccess}; } & .datatable-avatar[data-tone="warning"] { background: ${c.bgWarning}; } & .datatable-avatar[data-tone="danger"] { background: ${c.bgDanger}; } & .datatable-avatar[data-tone="purple"] { background: ${c.bgPurple}; } & .datatable-avatar[data-tone="cyan"] { background: ${c.bgCyan}; } & .datatable-avatar[data-tone="orange"] { background: ${c.bgOrange}; }
55
81
  & .datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
56
82
  & .datatable-tags { display: flex; align-items: center; gap: ${c.space["1"]}; overflow: hidden; }
57
- & .datatable-tag { display: inline-flex; align-items: center; height: 22px; padding: 0 ${c.space["1"]}; border-radius: 7px; font-size: ${c.text.lg}; line-height: 20px; font-weight: ${c.weight.medium}; white-space: nowrap; background: color-mix(in srgb, ${c.fgPrimary} 6%, transparent); color: color-mix(in srgb, ${c.fgPrimary} 82%, transparent); }
83
+ & .datatable-tag { display: inline-flex; align-items: center; height: ${c.size.chip}; padding: 0 ${c.space["1"]}; border-radius: ${c.radius.chip}; font-size: ${c.text.lg}; line-height: 20px; font-weight: ${c.weight.medium}; white-space: nowrap; background: color-mix(in srgb, ${c.fgPrimary} 6%, transparent); color: color-mix(in srgb, ${c.fgPrimary} 82%, transparent); }
58
84
  & .datatable-tag[data-tone="brand"] { background: color-mix(in srgb, ${c.bgBrandSolid} 14%, transparent); color: color-mix(in srgb, ${c.bgBrandSolid} 82%, ${c.fgPrimary}); }
59
85
  & .datatable-tag[data-tone="success"] { background: color-mix(in srgb, ${c.bgSuccess} 16%, transparent); color: color-mix(in srgb, ${c.bgSuccess} 78%, ${c.fgPrimary}); }
60
86
  & .datatable-tag[data-tone="warning"] { background: color-mix(in srgb, ${c.bgWarning} 18%, transparent); color: color-mix(in srgb, ${c.bgWarning} 82%, ${c.fgPrimary}); }
@@ -63,7 +89,19 @@ const config = defineRecipe({
63
89
  & .datatable-tag[data-tone="cyan"] { background: color-mix(in srgb, ${c.bgCyan} 18%, transparent); color: color-mix(in srgb, ${c.bgCyan} 82%, ${c.fgPrimary}); }
64
90
  & .datatable-tag[data-tone="orange"] { background: color-mix(in srgb, ${c.bgOrange} 16%, transparent); color: color-mix(in srgb, ${c.bgOrange} 82%, ${c.fgPrimary}); }
65
91
  & .datatable-num { font-variant-numeric: tabular-nums; }
66
- & .datatable-muted { color: ${c.fgMuted}; }`,
92
+ & .datatable-muted { color: ${c.fgMuted}; }
93
+ /* row drag-to-reorder -- Attio's Settings > Objects > Attributes measures
94
+ a leading 20px grip column, a 16px grip icon, and the row's own
95
+ hairline doubling as the drop indicator (it tints toward the brand
96
+ colour as the active drop target). The affordance + geometry are
97
+ measured; the drag MECHANISM is crisp's existing house idiom -- HTML5
98
+ draggable + dataTransfer, the same one column reorder already uses
99
+ (RecordsTable's reorderColumn) -- not Attio's own proprietary
100
+ pointer-events implementation. */
101
+ & .datatable-col-grip { width: 20px; padding: 0; text-align: center; }
102
+ & .datatable-grip { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 0; border: none; border-radius: 0; background: none; font-family: inherit; color: ${c.fgMuted}; cursor: grab; }
103
+ & .datatable-grip:active { cursor: grabbing; }
104
+ & tbody tr[data-drop-target] td, & tbody tr[data-drop-target] th { box-shadow: inset 0 2px 0 0 ${c.bgBrandSolid}; transition: box-shadow .12s; }`,
67
105
  variants: {},
68
106
  defaultVariants: {},
69
107
  compoundVariants: [],