@crisp-ui-kit/crisp 0.57.0 → 0.57.2

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 (293) hide show
  1. package/dist/accentpicker.css +5 -0
  2. package/dist/accentpicker.d.ts +7 -0
  3. package/dist/accentpicker.layered.css +7 -0
  4. package/dist/authshell.css +9 -4
  5. package/dist/authshell.layered.css +9 -4
  6. package/dist/avatar.css +1 -1
  7. package/dist/avatar.layered.css +1 -1
  8. package/dist/badge.css +5 -5
  9. package/dist/badge.layered.css +5 -5
  10. package/dist/board.css +28 -8
  11. package/dist/board.layered.css +28 -8
  12. package/dist/bottomsheet.css +26 -0
  13. package/dist/bottomsheet.d.ts +7 -0
  14. package/dist/bottomsheet.layered.css +28 -0
  15. package/dist/button.css +9 -8
  16. package/dist/button.layered.css +9 -8
  17. package/dist/checkbox.css +7 -3
  18. package/dist/checkbox.layered.css +7 -3
  19. package/dist/chip.css +15 -0
  20. package/dist/chip.d.ts +3 -1
  21. package/dist/chip.layered.css +15 -0
  22. package/dist/chipgroup.css +5 -0
  23. package/dist/chipgroup.d.ts +7 -0
  24. package/dist/chipgroup.layered.css +7 -0
  25. package/dist/cjs/components/accentpicker/accentpicker.js +66 -0
  26. package/dist/cjs/components/accentpicker/accentpicker.recipe.js +25 -0
  27. package/dist/cjs/components/accentpicker/index.js +7 -0
  28. package/dist/cjs/components/avatar/avatar.recipe.js +4 -1
  29. package/dist/cjs/components/badge/badge.recipe.js +38 -10
  30. package/dist/cjs/components/bottomsheet/bottomsheet.js +90 -0
  31. package/dist/cjs/components/bottomsheet/bottomsheet.recipe.js +77 -0
  32. package/dist/cjs/components/bottomsheet/index.js +9 -0
  33. package/dist/cjs/components/button/button.recipe.js +55 -21
  34. package/dist/cjs/components/checkbox/checkbox.recipe.js +61 -9
  35. package/dist/cjs/components/chip/chip.js +14 -2
  36. package/dist/cjs/components/chip/chip.recipe.js +69 -1
  37. package/dist/cjs/components/chipgroup/chipgroup.js +51 -0
  38. package/dist/cjs/components/chipgroup/chipgroup.recipe.js +36 -0
  39. package/dist/cjs/components/chipgroup/index.js +7 -0
  40. package/dist/cjs/components/datatable/datatable.js +5 -1
  41. package/dist/cjs/components/datatable/datatable.recipe.js +11 -2
  42. package/dist/cjs/components/dialog/dialog.recipe.js +21 -10
  43. package/dist/cjs/components/emptystate/emptystate.recipe.js +7 -2
  44. package/dist/cjs/components/fileupload/fileupload.js +21 -4
  45. package/dist/cjs/components/input/index.js +2 -1
  46. package/dist/cjs/components/input/input.js +33 -3
  47. package/dist/cjs/components/input/input.recipe.js +22 -7
  48. package/dist/cjs/components/menu/menu.recipe.js +21 -7
  49. package/dist/cjs/components/menusheet/index.js +9 -0
  50. package/dist/cjs/components/menusheet/menusheet.js +133 -0
  51. package/dist/cjs/components/menusheet/menusheet.recipe.js +103 -0
  52. package/dist/cjs/components/multiselect/multiselect.js +2 -2
  53. package/dist/cjs/components/multiselect/multiselect.recipe.js +45 -12
  54. package/dist/cjs/components/progress/progress.js +21 -4
  55. package/dist/cjs/components/progress/progress.recipe.js +30 -0
  56. package/dist/cjs/components/select/select.js +3 -3
  57. package/dist/cjs/components/select/select.recipe.js +63 -10
  58. package/dist/cjs/components/snackbar/index.js +8 -0
  59. package/dist/cjs/components/snackbar/snackbar.js +121 -0
  60. package/dist/cjs/components/snackbar/snackbar.recipe.js +71 -0
  61. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
  62. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +37 -12
  63. package/dist/cjs/components/tabs/tabs.js +10 -4
  64. package/dist/cjs/components/tabs/tabs.recipe.js +23 -6
  65. package/dist/cjs/components/text/text.recipe.js +8 -7
  66. package/dist/cjs/components/textarea/textarea.js +3 -2
  67. package/dist/cjs/components/textarea/textarea.recipe.js +13 -9
  68. package/dist/cjs/components/textlink/textlink.recipe.js +6 -3
  69. package/dist/cjs/index.js +8 -0
  70. package/dist/cjs/product/authshell/authshell.recipe.js +5 -1
  71. package/dist/cjs/product/command/command.recipe.js +4 -1
  72. package/dist/cjs/product/comments/comments.js +7 -2
  73. package/dist/cjs/product/comments/comments.recipe.js +25 -7
  74. package/dist/cjs/product/memberssettings/index.js +6 -0
  75. package/dist/cjs/product/memberssettings/memberssettings.js +99 -0
  76. package/dist/cjs/product/memberssettings/memberssettings.recipe.js +83 -0
  77. package/dist/cjs/product/notificationssettings/index.js +5 -0
  78. package/dist/cjs/product/notificationssettings/notificationssettings.js +19 -0
  79. package/dist/cjs/product/notificationssettings/notificationssettings.recipe.js +44 -0
  80. package/dist/cjs/product/recordpage/recordpage.js +101 -9
  81. package/dist/cjs/product/recordpage/recordpage.recipe.js +43 -6
  82. package/dist/cjs/product/workspacegeneralsettings/index.js +5 -0
  83. package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.js +21 -0
  84. package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +51 -0
  85. package/dist/cjs/tokens/contract.js +1 -0
  86. package/dist/cjs/tokens/elevation.js +8 -5
  87. package/dist/cjs/tokens/palette.js +107 -33
  88. package/dist/cjs/tokens/scale.js +45 -2
  89. package/dist/cjs/tokens/semantic.js +26 -0
  90. package/dist/columncalc.css +15 -7
  91. package/dist/columncalc.layered.css +15 -7
  92. package/dist/command.css +23 -19
  93. package/dist/command.layered.css +23 -19
  94. package/dist/comments.css +28 -19
  95. package/dist/comments.d.ts +2 -2
  96. package/dist/comments.layered.css +28 -19
  97. package/dist/datatable.css +161 -67
  98. package/dist/datatable.layered.css +161 -67
  99. package/dist/datepicker.css +13 -41
  100. package/dist/datepicker.layered.css +13 -41
  101. package/dist/datepickerfield.css +4 -1
  102. package/dist/datepickerfield.layered.css +4 -1
  103. package/dist/dialog.css +12 -7
  104. package/dist/dialog.layered.css +12 -7
  105. package/dist/emptystate.css +5 -3
  106. package/dist/emptystate.layered.css +5 -3
  107. package/dist/esm/components/accentpicker/accentpicker.js +30 -0
  108. package/dist/esm/components/accentpicker/accentpicker.recipe.js +22 -0
  109. package/dist/esm/components/accentpicker/index.js +2 -0
  110. package/dist/esm/components/avatar/avatar.recipe.js +4 -1
  111. package/dist/esm/components/badge/badge.recipe.js +38 -10
  112. package/dist/esm/components/bottomsheet/bottomsheet.js +52 -0
  113. package/dist/esm/components/bottomsheet/bottomsheet.recipe.js +74 -0
  114. package/dist/esm/components/bottomsheet/index.js +2 -0
  115. package/dist/esm/components/button/button.recipe.js +56 -22
  116. package/dist/esm/components/checkbox/checkbox.recipe.js +61 -9
  117. package/dist/esm/components/chip/chip.js +14 -2
  118. package/dist/esm/components/chip/chip.recipe.js +69 -1
  119. package/dist/esm/components/chipgroup/chipgroup.js +15 -0
  120. package/dist/esm/components/chipgroup/chipgroup.recipe.js +33 -0
  121. package/dist/esm/components/chipgroup/index.js +2 -0
  122. package/dist/esm/components/datatable/datatable.js +5 -1
  123. package/dist/esm/components/datatable/datatable.recipe.js +11 -2
  124. package/dist/esm/components/dialog/dialog.recipe.js +22 -11
  125. package/dist/esm/components/emptystate/emptystate.recipe.js +7 -2
  126. package/dist/esm/components/fileupload/fileupload.js +20 -5
  127. package/dist/esm/components/input/index.js +1 -1
  128. package/dist/esm/components/input/input.js +33 -3
  129. package/dist/esm/components/input/input.recipe.js +23 -8
  130. package/dist/esm/components/menu/menu.recipe.js +21 -7
  131. package/dist/esm/components/menusheet/index.js +2 -0
  132. package/dist/esm/components/menusheet/menusheet.js +95 -0
  133. package/dist/esm/components/menusheet/menusheet.recipe.js +100 -0
  134. package/dist/esm/components/multiselect/multiselect.js +2 -2
  135. package/dist/esm/components/multiselect/multiselect.recipe.js +45 -12
  136. package/dist/esm/components/progress/progress.js +22 -5
  137. package/dist/esm/components/progress/progress.recipe.js +30 -0
  138. package/dist/esm/components/select/select.js +3 -3
  139. package/dist/esm/components/select/select.recipe.js +63 -10
  140. package/dist/esm/components/snackbar/index.js +2 -0
  141. package/dist/esm/components/snackbar/snackbar.js +84 -0
  142. package/dist/esm/components/snackbar/snackbar.recipe.js +68 -0
  143. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
  144. package/dist/esm/components/tabletoolbar/tabletoolbar.js +37 -12
  145. package/dist/esm/components/tabs/tabs.js +10 -4
  146. package/dist/esm/components/tabs/tabs.recipe.js +23 -6
  147. package/dist/esm/components/text/text.recipe.js +8 -7
  148. package/dist/esm/components/textarea/textarea.js +3 -2
  149. package/dist/esm/components/textarea/textarea.recipe.js +14 -10
  150. package/dist/esm/components/textlink/textlink.recipe.js +6 -3
  151. package/dist/esm/index.js +8 -0
  152. package/dist/esm/product/authshell/authshell.recipe.js +5 -1
  153. package/dist/esm/product/command/command.recipe.js +4 -1
  154. package/dist/esm/product/comments/comments.js +7 -2
  155. package/dist/esm/product/comments/comments.recipe.js +25 -7
  156. package/dist/esm/product/memberssettings/index.js +1 -0
  157. package/dist/esm/product/memberssettings/memberssettings.js +62 -0
  158. package/dist/esm/product/memberssettings/memberssettings.recipe.js +80 -0
  159. package/dist/esm/product/notificationssettings/index.js +1 -0
  160. package/dist/esm/product/notificationssettings/notificationssettings.js +16 -0
  161. package/dist/esm/product/notificationssettings/notificationssettings.recipe.js +41 -0
  162. package/dist/esm/product/recordpage/recordpage.js +102 -10
  163. package/dist/esm/product/recordpage/recordpage.recipe.js +43 -6
  164. package/dist/esm/product/workspacegeneralsettings/index.js +1 -0
  165. package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.js +18 -0
  166. package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +48 -0
  167. package/dist/esm/tokens/contract.js +2 -1
  168. package/dist/esm/tokens/elevation.js +8 -5
  169. package/dist/esm/tokens/palette.js +107 -33
  170. package/dist/esm/tokens/scale.js +44 -1
  171. package/dist/esm/tokens/semantic.js +26 -0
  172. package/dist/fileupload.css +3 -1
  173. package/dist/fileupload.layered.css +3 -1
  174. package/dist/input.css +11 -2
  175. package/dist/input.layered.css +11 -2
  176. package/dist/listpage.css +3 -1
  177. package/dist/listpage.layered.css +3 -1
  178. package/dist/memberssettings.css +67 -0
  179. package/dist/memberssettings.d.ts +7 -0
  180. package/dist/memberssettings.layered.css +69 -0
  181. package/dist/menu.css +2 -2
  182. package/dist/menu.layered.css +2 -2
  183. package/dist/menusheet.css +36 -0
  184. package/dist/menusheet.d.ts +7 -0
  185. package/dist/menusheet.layered.css +38 -0
  186. package/dist/multiselect.css +17 -6
  187. package/dist/multiselect.d.ts +2 -2
  188. package/dist/multiselect.layered.css +17 -6
  189. package/dist/native/tokens.d.ts +2 -1
  190. package/dist/native/tokens.js +53 -25
  191. package/dist/notificationssettings.css +22 -0
  192. package/dist/notificationssettings.d.ts +7 -0
  193. package/dist/notificationssettings.layered.css +24 -0
  194. package/dist/objectsettings.css +4 -4
  195. package/dist/objectsettings.layered.css +4 -4
  196. package/dist/progress.css +3 -0
  197. package/dist/progress.layered.css +3 -0
  198. package/dist/recordpage.css +67 -23
  199. package/dist/recordpage.layered.css +67 -23
  200. package/dist/recordpanel.css +35 -16
  201. package/dist/recordpanel.layered.css +35 -16
  202. package/dist/resizablepanel.css +8 -5
  203. package/dist/resizablepanel.layered.css +8 -5
  204. package/dist/richtext.css +24 -8
  205. package/dist/richtext.layered.css +24 -8
  206. package/dist/savedviews.css +9 -2
  207. package/dist/savedviews.layered.css +9 -2
  208. package/dist/select.css +47 -7
  209. package/dist/select.d.ts +2 -2
  210. package/dist/select.layered.css +47 -7
  211. package/dist/settingsshell.css +2 -3
  212. package/dist/settingsshell.layered.css +2 -3
  213. package/dist/slider.css +6 -27
  214. package/dist/slider.layered.css +6 -27
  215. package/dist/snackbar.css +24 -0
  216. package/dist/snackbar.d.ts +7 -0
  217. package/dist/snackbar.layered.css +26 -0
  218. package/dist/statcard.css +3 -1
  219. package/dist/statcard.layered.css +3 -1
  220. package/dist/styles.css +927 -365
  221. package/dist/styles.layered.css +927 -365
  222. package/dist/table.css +28 -10
  223. package/dist/table.layered.css +28 -10
  224. package/dist/tabletoolbar.css +35 -24
  225. package/dist/tabletoolbar.layered.css +35 -24
  226. package/dist/tabs.css +18 -4
  227. package/dist/tabs.layered.css +18 -4
  228. package/dist/text.css +1 -1
  229. package/dist/text.layered.css +1 -1
  230. package/dist/textarea.css +4 -7
  231. package/dist/textarea.layered.css +4 -7
  232. package/dist/textlink.css +2 -2
  233. package/dist/textlink.layered.css +2 -2
  234. package/dist/themepicker.css +2 -1
  235. package/dist/themepicker.layered.css +2 -1
  236. package/dist/tokens.css +31 -13
  237. package/dist/tokens.json +53 -25
  238. package/dist/types/components/accentpicker/accentpicker.d.ts +23 -0
  239. package/dist/types/components/accentpicker/accentpicker.recipe.d.ts +3 -0
  240. package/dist/types/components/accentpicker/index.d.ts +2 -0
  241. package/dist/types/components/bottomsheet/bottomsheet.d.ts +35 -0
  242. package/dist/types/components/bottomsheet/bottomsheet.recipe.d.ts +3 -0
  243. package/dist/types/components/bottomsheet/index.d.ts +2 -0
  244. package/dist/types/components/button/button.recipe.d.ts +13 -8
  245. package/dist/types/components/checkbox/checkbox.recipe.d.ts +28 -5
  246. package/dist/types/components/chip/chip.d.ts +22 -0
  247. package/dist/types/components/chip/chip.recipe.d.ts +48 -0
  248. package/dist/types/components/chipgroup/chipgroup.d.ts +14 -0
  249. package/dist/types/components/chipgroup/chipgroup.recipe.d.ts +5 -0
  250. package/dist/types/components/chipgroup/index.d.ts +2 -0
  251. package/dist/types/components/datatable/datatable.d.ts +19 -0
  252. package/dist/types/components/fileupload/fileupload.d.ts +26 -0
  253. package/dist/types/components/input/index.d.ts +1 -1
  254. package/dist/types/components/input/input.d.ts +84 -0
  255. package/dist/types/components/menusheet/index.d.ts +2 -0
  256. package/dist/types/components/menusheet/menusheet.d.ts +42 -0
  257. package/dist/types/components/menusheet/menusheet.recipe.d.ts +3 -0
  258. package/dist/types/components/multiselect/multiselect.d.ts +4 -3
  259. package/dist/types/components/multiselect/multiselect.recipe.d.ts +3 -0
  260. package/dist/types/components/progress/progress.d.ts +16 -4
  261. package/dist/types/components/progress/progress.recipe.d.ts +22 -0
  262. package/dist/types/components/select/select.d.ts +6 -5
  263. package/dist/types/components/select/select.recipe.d.ts +3 -0
  264. package/dist/types/components/snackbar/index.d.ts +2 -0
  265. package/dist/types/components/snackbar/snackbar.d.ts +36 -0
  266. package/dist/types/components/snackbar/snackbar.recipe.d.ts +5 -0
  267. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +28 -1
  268. package/dist/types/components/tabs/tabs.d.ts +11 -1
  269. package/dist/types/components/textarea/textarea.d.ts +16 -0
  270. package/dist/types/index.d.ts +8 -0
  271. package/dist/types/product/comments/comments.d.ts +9 -3
  272. package/dist/types/product/comments/comments.recipe.d.ts +12 -2
  273. package/dist/types/product/memberssettings/index.d.ts +1 -0
  274. package/dist/types/product/memberssettings/memberssettings.d.ts +85 -0
  275. package/dist/types/product/memberssettings/memberssettings.recipe.d.ts +3 -0
  276. package/dist/types/product/notificationssettings/index.d.ts +1 -0
  277. package/dist/types/product/notificationssettings/notificationssettings.d.ts +37 -0
  278. package/dist/types/product/notificationssettings/notificationssettings.recipe.d.ts +3 -0
  279. package/dist/types/product/recordpage/recordpage.d.ts +89 -2
  280. package/dist/types/product/workspacegeneralsettings/index.d.ts +1 -0
  281. package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.d.ts +48 -0
  282. package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.recipe.d.ts +3 -0
  283. package/dist/types/tokens/contract.d.ts +7 -1
  284. package/dist/types/tokens/elevation.d.ts +8 -5
  285. package/dist/types/tokens/palette.d.ts +28 -12
  286. package/dist/types/tokens/scale.d.ts +12 -1
  287. package/dist/types/tokens/semantic.d.ts +17 -0
  288. package/dist/wheelpicker.css +4 -2
  289. package/dist/wheelpicker.layered.css +4 -2
  290. package/dist/workspacegeneralsettings.css +30 -0
  291. package/dist/workspacegeneralsettings.d.ts +7 -0
  292. package/dist/workspacegeneralsettings.layered.css +32 -0
  293. package/package.json +41 -1
@@ -41,12 +41,14 @@ const lucide_react_1 = require("lucide-react");
41
41
  const React = __importStar(require("react"));
42
42
  const avatar_1 = require("../../components/avatar");
43
43
  const checkbox_1 = require("../../components/checkbox");
44
+ const drawer_1 = require("../../components/drawer");
44
45
  const menu_1 = require("../../components/menu");
45
46
  const select_1 = require("../../components/select");
46
47
  const spinner_1 = require("../../components/spinner");
47
48
  const switch_1 = require("../../components/switch");
48
49
  const tabs_1 = require("../../components/tabs");
49
50
  const core_1 = require("../../core");
51
+ const comments_1 = require("../comments");
50
52
  const column_1 = require("./column");
51
53
  const editable_field_1 = require("./editable-field");
52
54
  const recordpage_recipe_1 = require("./recordpage.recipe");
@@ -71,9 +73,16 @@ exports.recordPageLabels = {
71
73
  breadcrumb: "Breadcrumb",
72
74
  editRecord: "Edit record",
73
75
  recordActions: "Record actions",
74
- addToFavourites: "Add to favourites",
75
- removeFromFavourites: "Remove from favourites",
76
+ // US spelling, matching Attio's own live text exactly (#621) — this string
77
+ // is shared with the entity header's favourite-star aria-label, so both
78
+ // read "favorites" now, not just the menu.
79
+ addToFavourites: "Add to favorites",
80
+ removeFromFavourites: "Remove from favorites",
76
81
  copyRecordLink: "Copy record link",
82
+ configurePage: "Configure page",
83
+ copyPageUrl: "Copy page URL",
84
+ copyRecordId: "Copy record ID",
85
+ mergeRecords: "Merge records",
77
86
  deleteRecord: "Delete record",
78
87
  linkRecords: "Link records",
79
88
  // Tooltip copy re-measured live for #865 (was "Log a note"/"Create a
@@ -88,6 +97,8 @@ exports.recordPageLabels = {
88
97
  composeEmail: "Compose email",
89
98
  askAttio: "Ask AI",
90
99
  addToList: "Add to list",
100
+ share: "Share",
101
+ comments: "Comments",
91
102
  noLists: "This record has not been added to any lists.",
92
103
  highlights: "Highlights",
93
104
  recordDetails: "Record Details",
@@ -300,7 +311,14 @@ function NotesSection({ notes, onAdd, labels, }) {
300
311
  return ((0, jsx_runtime_1.jsxs)("section", { children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: labels.tabs.notes, count: notes.length, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", onClick: () => setOpen(true), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), labels.newNote] }) }), open && ((0, jsx_runtime_1.jsx)(Composer, { labels: labels, multiline: true, placeholder: labels.notePlaceholder, submitLabel: labels.saveNote, onCancel: () => setOpen(false), onSubmit: (t) => {
301
312
  onAdd(t);
302
313
  setOpen(false);
303
- } })), notes.length === 0 && !open ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: labels.noNotesYet })) : (notes.map((n) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-note", children: [(0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "sm", shape: "circle", tone: "neutral", children: "Y" }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-note-body", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-note-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-author", children: labels.you }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-time", children: n.time })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-note-text", children: n.text })] })] }, n.id))))] }));
314
+ } })), notes.length === 0 && !open ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: labels.noNotesYet })) : (
315
+ // #871: one line, not a two-row card -- measured live: avatar,
316
+ // then the note's own title and body run together inline, then a
317
+ // relative time at the far end of the SAME row. No author name at
318
+ // all (Attio's real preview never shows one here, only the note's
319
+ // own content) -- `labels.you` stays defined for a consumer that
320
+ // still wants it elsewhere, just unused in this exact spot now.
321
+ notes.map((n) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-note", children: [(0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-note-left", children: [(0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "sm", shape: "circle", tone: "neutral", children: "Y" }), n.title && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-title", children: n.title })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-text", children: n.text })] }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-time", children: n.time })] }, n.id))))] }));
304
322
  }
305
323
  function TasksSection({ tasks, onAdd, onToggle, labels, }) {
306
324
  const [open, setOpen] = React.useState(false);
@@ -333,13 +351,51 @@ function EmptyCard({ icon, children, }) {
333
351
  * `RecordPage`'s own root does: `<div className={recordpageRecipe()}>`
334
352
  * (also exported from this package).
335
353
  */
336
- function RecordDetails({ record, columns, sections, onEdit, labels, className, ...rest }) {
354
+ function RecordDetails({ record, columns, sections, onEdit, labels, className, resizable = false, width: controlledWidth, defaultWidth = DETAILS_DEFAULT_W, onWidthChange, minWidth = DETAILS_MIN_W, maxWidth = DETAILS_MAX_W, ...rest }) {
337
355
  const t = useRecordPageLabels(labels);
338
356
  const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, editable_field_1.useEditableField)(onEdit);
339
357
  const [detailsOpen, setDetailsOpen] = React.useState(true);
340
358
  const [searchOpen, setSearchOpen] = React.useState(false);
341
359
  const [fieldQuery, setFieldQuery] = React.useState("");
342
360
  const [showAllValues, setShowAllValues] = React.useState(false);
361
+ // #930: controlled/uncontrolled width, same split as RecordPanel's own
362
+ // resizable width -- only read when `resizable`, same reasoning as
363
+ // RecordPanel's own (a non-resizing consumer has no business carrying
364
+ // width state at all).
365
+ const [internalWidth, setInternalWidth] = React.useState(defaultWidth);
366
+ const width = controlledWidth ?? internalWidth;
367
+ const setWidth = (next) => {
368
+ const clamped = Math.max(minWidth, Math.min(maxWidth, next));
369
+ if (controlledWidth === undefined)
370
+ setInternalWidth(clamped);
371
+ onWidthChange?.(clamped);
372
+ };
373
+ const [detailsResizing, setDetailsResizing] = React.useState(false);
374
+ const detailsDragRef = React.useRef(null);
375
+ const onDetailsResizeDown = (e) => {
376
+ // This column is a leading (left-docked) rail, the mirror image of
377
+ // RecordPanel's own trailing (right-docked) one -- a rightward pull
378
+ // grows it in LTR, the same direction RecordPage's own internal aside
379
+ // resize already uses (#212/#255).
380
+ detailsDragRef.current = {
381
+ x: e.clientX,
382
+ w: width,
383
+ dir: (0, core_1.isRtlElement)(e.currentTarget) ? -1 : 1,
384
+ };
385
+ setDetailsResizing(true);
386
+ e.target.setPointerCapture(e.pointerId);
387
+ };
388
+ const onDetailsResizeMove = (e) => {
389
+ const r = detailsDragRef.current;
390
+ if (!r)
391
+ return;
392
+ setWidth(r.w + r.dir * (e.clientX - r.x));
393
+ };
394
+ const onDetailsResizeUp = (e) => {
395
+ detailsDragRef.current = null;
396
+ setDetailsResizing(false);
397
+ e.target.releasePointerCapture(e.pointerId);
398
+ };
343
399
  const fields = columns.filter((col) => col.type !== "entity");
344
400
  const q = fieldQuery.trim().toLowerCase();
345
401
  const matches = (col) => !q || col.label.toLowerCase().includes(q);
@@ -376,7 +432,7 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
376
432
  groups = [{ title: undefined, fields: shown }];
377
433
  }
378
434
  const totalShown = groups.reduce((n, g) => n + g.fields.length, 0);
379
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, core_1.cx)("crisp-recordpage-section", className), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-detailhead", children: [searchOpen ? ((0, jsx_runtime_1.jsx)("input", {
435
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, core_1.cx)("crisp-recordpage-section", className), "data-resizable": resizable ? "" : undefined, style: resizable ? { width } : undefined, ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-detailhead", children: [searchOpen ? ((0, jsx_runtime_1.jsx)("input", {
380
436
  // biome-ignore lint/a11y/noAutofocus: focusing the just-opened field search is expected
381
437
  autoFocus: true, type: "text", className: "crisp-recordpage-fieldsearch", placeholder: t.searchPlaceholder, "aria-label": t.searchFields, value: fieldQuery, onChange: (e) => setFieldQuery(e.target.value), onKeyDown: (e) => {
382
438
  if (e.key === "Escape") {
@@ -450,7 +506,13 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
450
506
  setSearchOpen(next);
451
507
  if (!next)
452
508
  setFieldQuery("");
453
- }, children: showAllValues ? t.viewLess : t.viewAllValues }))] })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-noresults", children: t.noFieldsMatch(fieldQuery) })))] }));
509
+ }, children: showAllValues ? t.viewLess : t.viewAllValues }))] })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-noresults", children: t.noFieldsMatch(fieldQuery) }))), resizable && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-detailresize", "data-active": detailsResizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(width), "aria-valuemin": minWidth, "aria-valuemax": maxWidth, tabIndex: 0, onPointerDown: onDetailsResizeDown, onPointerMove: onDetailsResizeMove, onPointerUp: onDetailsResizeUp, onKeyDown: (e) => {
510
+ if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
511
+ return;
512
+ const rtl = (0, core_1.isRtlElement)(e.currentTarget);
513
+ const grow = e.key === (rtl ? "ArrowLeft" : "ArrowRight");
514
+ setWidth(grow ? width + 16 : width - 16);
515
+ } }))] }));
454
516
  }
455
517
  RecordDetails.displayName = "RecordDetails";
456
518
  /**
@@ -461,7 +523,7 @@ RecordDetails.displayName = "RecordDetails";
461
523
  * Emails sections (Notes & Tasks are live — add and check things off). Drop it
462
524
  * into the app's main content area.
463
525
  */
464
- function RecordPage({ record, columns, collection = "Records", labels, onBack, onToggleFull, full, className, onEdit, tabs: tabsProp, defaultTab, notes: notesProp, onAddNote, tasks: tasksProp, onAddTask, onToggleTask, sections, highlights: highlightsProp, quickActions: quickActionsProp, ...rest }) {
526
+ function RecordPage({ record, columns, collection = "Records", labels, onBack, onToggleFull, full, onClose, closeLabel = "Close", onPrevious, previousRecordLabel = "Previous record", onNext, nextRecordLabel = "Next record", counterLabel, className, onEdit, tabs: tabsProp, defaultTab, notes: notesProp, onAddNote, tasks: tasksProp, onAddTask, onToggleTask, sections, highlights: highlightsProp, quickActions: quickActionsProp, comments: commentsProp, onPostComment, currentUser, onShare, ...rest }) {
465
527
  const t = useRecordPageLabels(labels);
466
528
  const [favorite, setFavorite] = React.useState(false);
467
529
  // Notes/Tasks are controlled when the caller supplies `notes`/`tasks` (even
@@ -473,6 +535,11 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
473
535
  const [internalTasks, setInternalTasks] = React.useState([]);
474
536
  const notes = notesProp ?? internalNotes;
475
537
  const tasks = tasksProp ?? internalTasks;
538
+ // Comments follow the same controlled/self-contained duality (#864).
539
+ const [internalComments, setInternalComments] = React.useState([]);
540
+ const comments = commentsProp ?? internalComments;
541
+ const [commentsOpen, setCommentsOpen] = React.useState(false);
542
+ const me = currentUser ?? { id: "me", name: "You" };
476
543
  const [showAllActivity, setShowAllActivity] = React.useState(false);
477
544
  // Drag-resizable left details column.
478
545
  const [detailsW, setDetailsW] = React.useState(DETAILS_DEFAULT_W);
@@ -631,6 +698,31 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
631
698
  }
632
699
  setInternalTasks((n) => n.map((x) => (x.id === id ? { ...x, done: !x.done } : x)));
633
700
  };
701
+ const postComment = (text, threadId) => {
702
+ if (commentsProp) {
703
+ onPostComment?.(text, threadId);
704
+ return;
705
+ }
706
+ if (threadId == null) {
707
+ setInternalComments((prev) => [
708
+ {
709
+ id: nextId(),
710
+ root: { id: nextId(), author: me, time: t.justNow, body: text },
711
+ },
712
+ ...prev,
713
+ ]);
714
+ return;
715
+ }
716
+ setInternalComments((prev) => prev.map((th) => th.id === threadId
717
+ ? {
718
+ ...th,
719
+ replies: [
720
+ ...(th.replies ?? []),
721
+ { id: nextId(), author: me, time: t.justNow, body: text },
722
+ ],
723
+ }
724
+ : th));
725
+ };
634
726
  // A small, plausible activity feed derived from the record's own fields.
635
727
  const domain = byKey.get("domain");
636
728
  const cats = byKey.get("categories");
@@ -687,7 +779,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
687
779
  const effectivePanel = tabsProp
688
780
  ? (active) => tabsProp.find((tb) => tb.id === active)?.render()
689
781
  : builtinPanel;
690
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", children: [(0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), shortcut: "\u2318C", children: t.copyRecordLink }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), children: t.addToList }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, shortcut: "\u232B", children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }), t.addToList] }), quickActions.map((a, i) => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": a.label, onClick: a.onSelect, children: (0, jsx_runtime_1.jsx)(a.icon, { size: 15, strokeWidth: 1.75 }) }, i)))] }), (0, jsx_runtime_1.jsx)(RecordDetails, { record: record, columns: columns, sections: sections, onEdit: onEdit, labels: labels }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.lists, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), t.addToList] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: t.noLists })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-resizer", "data-active": resizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(detailsW), "aria-valuemin": DETAILS_MIN_W, "aria-valuemax": DETAILS_MAX_W, tabIndex: 0, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onKeyDown: (e) => {
782
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", "data-peek": onClose ? "" : undefined, children: [onClose ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-peekbar", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-peek-iconbtn", "aria-label": closeLabel, onClick: onClose, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 16, strokeWidth: 1.75 }) }), (onPrevious || onNext) && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-peek-pager", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-peek-navbtn", "aria-label": previousRecordLabel, disabled: !onPrevious, onClick: onPrevious, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronUp, { size: 16, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-peek-navbtn", "aria-label": nextRecordLabel, disabled: !onNext, onClick: onNext, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 16, strokeWidth: 1.75 }) })] })), counterLabel != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-peek-counter", children: counterLabel }))] })) : ((0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", onClick: onShare, children: t.share }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: () => setCommentsOpen(true), "aria-label": t.comments, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MessageSquare, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Merge, { size: 15, strokeWidth: 1.75 }), children: t.mergeRecords }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 15, strokeWidth: 1.75 }), children: t.configurePage }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), children: t.copyPageUrl }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), children: t.copyRecordId }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }), t.addToList] }), quickActions.map((a, i) => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": a.label, onClick: a.onSelect, children: (0, jsx_runtime_1.jsx)(a.icon, { size: 15, strokeWidth: 1.75 }) }, i)))] }), (0, jsx_runtime_1.jsx)(RecordDetails, { record: record, columns: columns, sections: sections, onEdit: onEdit, labels: labels }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.lists, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), t.addToList] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: t.noLists })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-resizer", "data-active": resizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(detailsW), "aria-valuemin": DETAILS_MIN_W, "aria-valuemax": DETAILS_MAX_W, tabIndex: 0, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onKeyDown: (e) => {
691
783
  if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
692
784
  return;
693
785
  // The pointer drag learned its direction in #212; this did not.
@@ -699,6 +791,6 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
699
791
  setDetailsW((w) => grow
700
792
  ? Math.min(DETAILS_MAX_W, w + 16)
701
793
  : Math.max(DETAILS_MIN_W, w - 16));
702
- } }), (0, jsx_runtime_1.jsx)("main", { className: "crisp-recordpage-main", children: (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: effectiveTabs, defaultValue: tabsProp ? defaultTab : "overview", "aria-label": `${name} record`, children: effectivePanel }) })] })] }));
794
+ } }), (0, jsx_runtime_1.jsx)("main", { className: "crisp-recordpage-main", children: (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: effectiveTabs, defaultValue: tabsProp ? defaultTab : "overview", "aria-label": `${name} record`, children: effectivePanel }) })] }), (0, jsx_runtime_1.jsx)(drawer_1.Drawer, { open: commentsOpen, onOpenChange: setCommentsOpen, "aria-label": t.comments, style: { width: 320 }, children: (0, jsx_runtime_1.jsx)(comments_1.CommentsPanel, { threads: comments, currentUserId: me.id, onPost: postComment, onClose: () => setCommentsOpen(false), role: undefined }) })] }));
703
795
  }
704
796
  RecordPage.displayName = "RecordPage";
@@ -26,6 +26,21 @@ const config = (0, core_1.defineRecipe)({
26
26
  & * { box-sizing: border-box; }
27
27
 
28
28
  & .crisp-recordpage-topbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 44px; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["3"]}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; }
29
+ /* #624: expanding a peek to its full record keeps a hybrid header
30
+ (Close/Previous/Next/counter) instead of reverting to the plain
31
+ breadcrumb above -- measured live on a real expanded record: 49px
32
+ tall (not 44px), 8px/10px padding, same borderSubtle hairline. Same
33
+ tokens as product/recordpanel's own already-shipped toolbar, not
34
+ new values -- this is the same row, reused in a second component. */
35
+ & .crisp-recordpage-topbar[data-peek] { height: 49px; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["2.5"]}; }
36
+ & .crisp-recordpage-peekbar { display: flex; align-items: center; }
37
+ & .crisp-recordpage-peek-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: transparent; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 55%, transparent); font-family: inherit; cursor: pointer; transition: background-color .12s; }
38
+ & .crisp-recordpage-peek-iconbtn:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
39
+ & .crisp-recordpage-peek-pager { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; margin-inline-start: ${tokens_1.contract.space["3"]}; }
40
+ & .crisp-recordpage-peek-navbtn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field}; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; cursor: pointer; }
41
+ & .crisp-recordpage-peek-navbtn:hover:not(:disabled) { background: ${tokens_1.contract.bgRaised}; }
42
+ & .crisp-recordpage-peek-navbtn:disabled { opacity: 0.4; cursor: not-allowed; }
43
+ & .crisp-recordpage-peek-counter { margin-inline-start: ${tokens_1.contract.space["3"]}; font-size: 12px; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
29
44
  & .crisp-recordpage-crumbs { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; min-width: 0; }
30
45
  & .crisp-recordpage-crumb { display: inline-flex; align-items: center; height: 26px; padding: 0 ${tokens_1.contract.space["1.5"]}; margin: 0 calc(-1 * ${tokens_1.contract.space["1.5"]}) 0 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; cursor: pointer; }
31
46
  & .crisp-recordpage-crumb:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
@@ -45,6 +60,17 @@ const config = (0, core_1.defineRecipe)({
45
60
  & .crisp-recordpage-resizer::before { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-start: -4px; width: 9px; }
46
61
  & .crisp-recordpage-resizer::after { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-start: -1px; width: 2px; background: transparent; transition: background-color .12s ease; }
47
62
  & .crisp-recordpage-resizer:hover::after, & .crisp-recordpage-resizer[data-active]::after { background: color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 55%, transparent); }
63
+ /* #930: RecordDetails' own standalone resize handle -- same visible
64
+ hit-slop/line-highlight shape as .crisp-recordpage-resizer just above,
65
+ just absolutely positioned at the trailing edge instead of a 0-width
66
+ flex sibling, since RecordDetails always returns a single root (the
67
+ same internal-strip placement RecordPanel's own resize handle uses,
68
+ mirrored to the opposite edge -- this column is leading, RecordPanel
69
+ is trailing). */
70
+ & .crisp-recordpage-section[data-resizable] { position: relative; }
71
+ & .crisp-recordpage-detailresize { position: absolute; top: 0; bottom: 0; inset-inline-end: -4px; width: 9px; cursor: col-resize; z-index: 5; touch-action: none; }
72
+ & .crisp-recordpage-detailresize::after { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-end: 3px; width: 2px; background: transparent; transition: background-color .12s ease; }
73
+ & .crisp-recordpage-detailresize:hover::after, & .crisp-recordpage-detailresize[data-active]::after { background: color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 55%, transparent); }
48
74
  & .crisp-recordpage-entity { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; padding: ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["2"]}; }
49
75
  & .crisp-recordpage-entity-logo { width: 32px; height: 32px; border-radius: 30%; flex-shrink: 0; object-fit: cover; background: ${tokens_1.contract.bgRaised}; }
50
76
  & .crisp-recordpage-entity-name { flex: 0 1 auto; min-width: 0; font-size: ${tokens_1.contract.text.xl}; font-weight: ${tokens_1.contract.weight.semibold}; letter-spacing: -0.3px; color: ${tokens_1.contract.fgPrimary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -178,12 +204,23 @@ const config = (0, core_1.defineRecipe)({
178
204
  & .crisp-recordpage-btn--primary { box-shadow: none; background: ${tokens_1.contract.bgBrandSolid}; color: ${tokens_1.contract.fgOnBrand}; }
179
205
  & .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
180
206
 
181
- & .crisp-recordpage-note { display: flex; gap: ${tokens_1.contract.space["2.5"]}; padding: ${tokens_1.contract.space["2.5"]} 0; border-top: 1px solid ${tokens_1.contract.borderSubtle}; }
182
- & .crisp-recordpage-note-body { flex: 1; min-width: 0; }
183
- & .crisp-recordpage-note-head { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; margin-bottom: ${tokens_1.contract.space["0.5"]}; }
184
- & .crisp-recordpage-note-author { font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
185
- & .crisp-recordpage-note-time { font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
186
- & .crisp-recordpage-note-text { font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; white-space: pre-wrap; word-break: break-word; }
207
+ /* #871: one bordered card per note (border-radius.xl, borderSubtle),
208
+ not a flush divider-list row -- measured live on a real populated
209
+ note: the whole row is flex space-between, avatar+title+body on the
210
+ left (its own flex, gap.2), the relative time alone on the right.
211
+ The real DOM nests an inner clickable button (padding 6/8, radius.md)
212
+ inside an outer card (padding 4px, radius.xl) -- collapsed into this
213
+ one non-interactive div's own combined padding (2.5/3) since crisp's
214
+ NotesSection has no click-to-open behaviour to justify the extra
215
+ layer. The 6px gap between stacked cards is NOT independently
216
+ measured (this workspace only ever had one real note to check) --
217
+ a judgement call off the existing space scale, not a live value. */
218
+ & .crisp-recordpage-note { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["3"]}; padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["3"]}; border: 1px solid ${tokens_1.contract.borderSubtle}; border-radius: ${tokens_1.contract.radius.xl}; }
219
+ & .crisp-recordpage-note + .crisp-recordpage-note { margin-top: ${tokens_1.contract.space["1.5"]}; }
220
+ & .crisp-recordpage-note-left { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; min-width: 0; overflow: hidden; }
221
+ & .crisp-recordpage-note-title { flex-shrink: 0; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
222
+ & .crisp-recordpage-note-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
223
+ & .crisp-recordpage-note-time { flex-shrink: 0; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 50%, transparent); }
187
224
 
188
225
  & .crisp-recordpage-task { display: flex; align-items: flex-start; gap: ${tokens_1.contract.space["2"]}; padding: ${tokens_1.contract.space["1.5"]} 0; border-top: 1px solid ${tokens_1.contract.borderSubtle}; }
189
226
  & .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; padding-top: 1px; }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkspaceGeneralSettings = void 0;
4
+ var workspacegeneralsettings_1 = require("./workspacegeneralsettings");
5
+ Object.defineProperty(exports, "WorkspaceGeneralSettings", { enumerable: true, get: function () { return workspacegeneralsettings_1.WorkspaceGeneralSettings; } });
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkspaceGeneralSettings = WorkspaceGeneralSettings;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const lucide_react_1 = require("lucide-react");
6
+ const avatar_1 = require("../../components/avatar");
7
+ const button_1 = require("../../components/button");
8
+ const formfield_1 = require("../../components/formfield");
9
+ const input_1 = require("../../components/input");
10
+ const table_1 = require("../../components/table");
11
+ const textlink_1 = require("../../components/textlink");
12
+ const workspacegeneralsettings_recipe_1 = require("./workspacegeneralsettings.recipe");
13
+ /**
14
+ * Attio's Settings → Workspace → General page (crisp#638, P-128), measured
15
+ * live: a logo + Name/Slug section, an "Export workspace data" table, and a
16
+ * "Danger zone" delete-workspace row.
17
+ */
18
+ function WorkspaceGeneralSettings({ logoSrc, workspaceInitial, onUploadLogo, name, onNameChange, slug, onCopySlug, exports: exportRows, onStartExport, onDeleteWorkspace, className, title = "General", description = "Change the settings for your current workspace.", learnMoreLabel = "Learn more", learnMoreHref = "#", logoHelpText = "We only support PNGs, JPEGs and GIFs under 10MB", uploadLogoLabel = "Upload logo", nameFieldLabel = "Name", slugFieldLabel = "Slug", copySlugLabel = "Copy slug", exportSectionTitle = "Export workspace data", exportSectionDescription = "Exports are in CSV format and can be downloaded within 7 days", startExportLabel = "Start new export", typeColumnLabel = "Type", dateColumnLabel = "Date", noExportsLabel = "No exports yet", dangerSectionTitle = "Danger zone", deleteWorkspaceTitle = "Delete workspace", deleteWorkspaceWarning = "Once deleted, your workspace cannot be recovered", deleteWorkspaceLabel = "Delete workspace", ...rest }) {
19
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, workspacegeneralsettings_recipe_1.workspacegeneralsettingsRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-page", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-heading", children: [(0, jsx_runtime_1.jsx)("h1", { className: "crisp-workspacegeneralsettings-title", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "crisp-workspacegeneralsettings-desc", children: [description, " ", (0, jsx_runtime_1.jsx)(textlink_1.TextLink, { href: learnMoreHref, children: learnMoreLabel })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-logorow", children: [logoSrc ? ((0, jsx_runtime_1.jsx)("img", { src: logoSrc, alt: "", width: 48, height: 48, style: { borderRadius: "30%", objectFit: "cover" } })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "xl", shape: "rounded", tone: "brand", children: workspaceInitial })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-logotext", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-workspacegeneralsettings-logohelp", children: logoHelpText }), (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "neutral", size: "sm", onClick: onUploadLogo, children: uploadLogoLabel })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-fieldrow", children: [(0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: nameFieldLabel, children: (0, jsx_runtime_1.jsx)(input_1.Input, { value: name, onChange: (e) => onNameChange(e.target.value) }) }), (0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: slugFieldLabel, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-slugfield", children: [(0, jsx_runtime_1.jsx)(input_1.Input, { value: slug, readOnly: true }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-workspacegeneralsettings-copybtn", "aria-label": copySlugLabel, onClick: onCopySlug, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 16 }) })] }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-sectionhead", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-sectionhead-text", children: [(0, jsx_runtime_1.jsx)("h2", { className: "crisp-workspacegeneralsettings-sectiontitle", children: exportSectionTitle }), (0, jsx_runtime_1.jsx)("p", { className: "crisp-workspacegeneralsettings-desc", children: exportSectionDescription })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "neutral", size: "sm", onClick: onStartExport, children: startExportLabel })] }), (0, jsx_runtime_1.jsxs)(table_1.Table, { children: [(0, jsx_runtime_1.jsx)(table_1.TableHeader, { children: (0, jsx_runtime_1.jsxs)(table_1.TableRow, { children: [(0, jsx_runtime_1.jsx)(table_1.TableHead, { children: typeColumnLabel }), (0, jsx_runtime_1.jsx)(table_1.TableHead, { children: dateColumnLabel })] }) }), (0, jsx_runtime_1.jsx)(table_1.TableBody, { children: exportRows.length === 0 ? ((0, jsx_runtime_1.jsx)(table_1.TableRow, { children: (0, jsx_runtime_1.jsx)(table_1.TableCell, { colSpan: 2, children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-workspacegeneralsettings-emptyrow", children: noExportsLabel }) }) })) : (exportRows.map((row) => ((0, jsx_runtime_1.jsxs)(table_1.TableRow, { children: [(0, jsx_runtime_1.jsx)(table_1.TableCell, { children: row.type }), (0, jsx_runtime_1.jsx)(table_1.TableCell, { children: row.date })] }, row.id)))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-section", children: [(0, jsx_runtime_1.jsx)("h2", { className: "crisp-workspacegeneralsettings-sectiontitle", children: dangerSectionTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-dangerrow", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-dangertext", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-workspacegeneralsettings-rowtitle", children: deleteWorkspaceTitle }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-workspacegeneralsettings-dangerwarning", children: deleteWorkspaceWarning })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "danger", size: "sm", onClick: onDeleteWorkspace, children: deleteWorkspaceLabel })] })] })] }) }));
20
+ }
21
+ WorkspaceGeneralSettings.displayName = "WorkspaceGeneralSettings";
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.workspacegeneralsettingsRecipe = void 0;
4
+ const core_1 = require("../../core");
5
+ const tokens_1 = require("../../tokens");
6
+ // Measured live against app.attio.com/<workspace>/settings/workspace
7
+ // (crisp#638, P-128). Logo tile + Name/Slug fields side by side, an
8
+ // "Export workspace data" section (header row + Type/Date table + empty
9
+ // state), and a "Danger zone" section (a red-tinted bordered row).
10
+ const config = (0, core_1.defineRecipe)({
11
+ name: "workspacegeneralsettings",
12
+ base: `& .crisp-workspacegeneralsettings-page { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["6"]}; font-family: ${tokens_1.contract.font.sans}; }
13
+ & .crisp-workspacegeneralsettings-heading { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["0.5"]}; }
14
+ & .crisp-workspacegeneralsettings-title { font-size: 24px; line-height: 28px; font-weight: ${tokens_1.contract.weight.semibold}; letter-spacing: -0.48px; color: ${tokens_1.contract.fgPrimary}; margin: 0; }
15
+ & .crisp-workspacegeneralsettings-desc { font-size: ${tokens_1.contract.text.lg}; line-height: 20px; color: ${tokens_1.contract.fgMuted}; margin: 0; }
16
+
17
+ & .crisp-workspacegeneralsettings-section { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["4"]}; }
18
+ & .crisp-workspacegeneralsettings-sectiontitle { font-size: 16px; line-height: 20px; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; margin: 0; }
19
+ & .crisp-workspacegeneralsettings-sectionhead { display: flex; align-items: flex-start; justify-content: space-between; gap: ${tokens_1.contract.space["4"]}; }
20
+ & .crisp-workspacegeneralsettings-sectionhead-text { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1"]}; }
21
+
22
+ /* Logo row: a tile + helper text + "Upload logo" button. */
23
+ & .crisp-workspacegeneralsettings-logorow { display: flex; align-items: center; gap: ${tokens_1.contract.space["4"]}; }
24
+ & .crisp-workspacegeneralsettings-logohelp { font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
25
+ & .crisp-workspacegeneralsettings-logotext { display: flex; flex-direction: column; align-items: flex-start; gap: ${tokens_1.contract.space["1"]}; }
26
+
27
+ /* Name + Slug sit side by side, each ~half the content width. */
28
+ & .crisp-workspacegeneralsettings-fieldrow { display: flex; gap: ${tokens_1.contract.space["4"]}; }
29
+ & .crisp-workspacegeneralsettings-fieldrow > * { flex: 1; min-width: 0; }
30
+ & .crisp-workspacegeneralsettings-slugfield { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; }
31
+ & .crisp-workspacegeneralsettings-slugfield > :first-child { flex: 1; min-width: 0; }
32
+ & .crisp-workspacegeneralsettings-copybtn { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 32px; height: 32px; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; font-family: inherit; color: ${tokens_1.contract.fgMuted}; cursor: pointer; }
33
+ & .crisp-workspacegeneralsettings-copybtn:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
34
+
35
+ /* Export-data empty state -- measured: 14/500/63%-opacity, centred in a
36
+ 40px row, no border of its own (the Table wrapper already draws it). */
37
+ & .crisp-workspacegeneralsettings-emptyrow { padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["4"]}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); text-align: center; }
38
+
39
+ /* Danger zone: a red-tinted bordered row, distinct from every other
40
+ card on the page. */
41
+ & .crisp-workspacegeneralsettings-dangerrow { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["6"]}; padding: ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["4"]}; border: 1px solid color-mix(in srgb, ${tokens_1.contract.bgDanger} 30%, transparent); border-radius: 12px; background: color-mix(in srgb, ${tokens_1.contract.bgDanger} 6%, transparent); }
42
+ & .crisp-workspacegeneralsettings-dangertext { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1"]}; }
43
+ & .crisp-workspacegeneralsettings-rowtitle { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
44
+ & .crisp-workspacegeneralsettings-dangerwarning { font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
45
+ `,
46
+ variants: {},
47
+ defaultVariants: {},
48
+ compoundVariants: [],
49
+ });
50
+ exports.workspacegeneralsettingsRecipe = (0, core_1.resolveRecipe)(config);
51
+ exports.default = config;
@@ -19,4 +19,5 @@ exports.contract = Object.assign(colors, {
19
19
  font: mapScale("font", scale_1.font),
20
20
  text: mapScale("text", scale_1.text),
21
21
  weight: mapScale("weight", scale_1.weight),
22
+ tracking: mapScale("tracking", scale_1.tracking),
22
23
  });
@@ -15,9 +15,11 @@ const contract_1 = require("./contract");
15
15
  */
16
16
  exports.elevation = {
17
17
  /**
18
- * Tier 1 — anything floating and *attached*: menus, popovers, dropdowns,
18
+ * Tier 1 — anything floating and *attached*: popovers, dropdowns,
19
19
  * hover-preview cards, the floating sidebar, the record peek, drawers, the
20
20
  * bulk bar. Pairs with a 10–12px radius and, for panels, an 8px gutter.
21
+ * NOT `Menu` (your-moon/crisp#934) -- that moved to
22
+ * `selectFloating`, seed-design's own flat shadow, below.
21
23
  */
22
24
  floating: `inset 0 0 0 1px ${contract_1.contract.ringPopover}, 0 0 0 1px ${contract_1.contract.shadowPopover1}, 0 4px 8px -4px ${contract_1.contract.shadowPopover2}, 0 4px 12px -2px ${contract_1.contract.shadowPopover3}`,
23
25
  /**
@@ -60,10 +62,11 @@ exports.elevation = {
60
62
  */
61
63
  fieldNoRing: `0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04)`,
62
64
  /**
63
- * Select's own listbox shadow (crisp/#867) — seed-design's `$shadow.s3`, a
64
- * single layer, NOT `floating` above. This component follows seed, not
65
- * Attio, for the same reason `DatePicker` follows seed's calendar
66
- * structure: an explicit owner request to match seed-design exactly.
65
+ * Seed-design's own `$shadow.s3`, a single flat layer, NOT `floating`
66
+ * above. Originally Select's own listbox shadow (crisp/#867); also `Menu`'s
67
+ * (your-moon/crisp#934) -- the raw seed dump confirms Menu
68
+ * is the one component seed's own spec gives a shadow to at all, and it's
69
+ * this exact value. Despite the name, not exclusive to Select.
67
70
  */
68
71
  selectFloating: `0 4px 16px ${contract_1.contract.shadowSelect}`,
69
72
  };