@crisp-ui-kit/crisp 0.57.1 → 0.57.3

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 (277) hide show
  1. package/dist/authshell.css +9 -4
  2. package/dist/authshell.layered.css +9 -4
  3. package/dist/badge.css +3 -3
  4. package/dist/badge.layered.css +3 -3
  5. package/dist/board.css +28 -8
  6. package/dist/board.layered.css +28 -8
  7. package/dist/bottomsheet.css +26 -0
  8. package/dist/bottomsheet.d.ts +7 -0
  9. package/dist/bottomsheet.layered.css +28 -0
  10. package/dist/button.css +10 -6
  11. package/dist/button.d.ts +2 -2
  12. package/dist/button.layered.css +10 -6
  13. package/dist/checkbox.css +7 -3
  14. package/dist/checkbox.layered.css +7 -3
  15. package/dist/chip.css +16 -1
  16. package/dist/chip.d.ts +3 -1
  17. package/dist/chip.layered.css +16 -1
  18. package/dist/chipgroup.css +5 -0
  19. package/dist/chipgroup.d.ts +7 -0
  20. package/dist/chipgroup.layered.css +7 -0
  21. package/dist/cjs/components/badge/badge.recipe.js +22 -8
  22. package/dist/cjs/components/bottomsheet/bottomsheet.js +90 -0
  23. package/dist/cjs/components/bottomsheet/bottomsheet.recipe.js +77 -0
  24. package/dist/cjs/components/bottomsheet/index.js +9 -0
  25. package/dist/cjs/components/breadcrumb/breadcrumb.js +1 -1
  26. package/dist/cjs/components/button/button.recipe.js +67 -15
  27. package/dist/cjs/components/checkbox/checkbox.recipe.js +61 -9
  28. package/dist/cjs/components/chip/chip.js +14 -2
  29. package/dist/cjs/components/chip/chip.recipe.js +72 -2
  30. package/dist/cjs/components/chipgroup/chipgroup.js +51 -0
  31. package/dist/cjs/components/chipgroup/chipgroup.recipe.js +36 -0
  32. package/dist/cjs/components/chipgroup/index.js +7 -0
  33. package/dist/cjs/components/datatable/datatable.js +5 -1
  34. package/dist/cjs/components/datatable/datatable.recipe.js +21 -6
  35. package/dist/cjs/components/datepickerfield/datepickerfield.js +2 -2
  36. package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +16 -3
  37. package/dist/cjs/components/dialog/dialog.recipe.js +21 -10
  38. package/dist/cjs/components/emptystate/emptystate.recipe.js +7 -2
  39. package/dist/cjs/components/fileupload/fileupload.js +21 -4
  40. package/dist/cjs/components/input/index.js +2 -1
  41. package/dist/cjs/components/input/input.js +31 -1
  42. package/dist/cjs/components/input/input.recipe.js +16 -9
  43. package/dist/cjs/components/menu/menu.js +18 -2
  44. package/dist/cjs/components/menu/menu.recipe.js +21 -7
  45. package/dist/cjs/components/menusheet/index.js +9 -0
  46. package/dist/cjs/components/menusheet/menusheet.js +133 -0
  47. package/dist/cjs/components/menusheet/menusheet.recipe.js +103 -0
  48. package/dist/cjs/components/multiselect/multiselect.js +1 -1
  49. package/dist/cjs/components/multiselect/multiselect.recipe.js +33 -9
  50. package/dist/cjs/components/select/select.js +1 -1
  51. package/dist/cjs/components/select/select.recipe.js +38 -12
  52. package/dist/cjs/components/snackbar/index.js +8 -0
  53. package/dist/cjs/components/snackbar/snackbar.js +121 -0
  54. package/dist/cjs/components/snackbar/snackbar.recipe.js +71 -0
  55. package/dist/cjs/components/table/table.recipe.js +7 -1
  56. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
  57. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +37 -12
  58. package/dist/cjs/components/tabs/tabs.js +10 -4
  59. package/dist/cjs/components/tabs/tabs.recipe.js +23 -6
  60. package/dist/cjs/components/textarea/textarea.recipe.js +11 -8
  61. package/dist/cjs/core/floating-portal.js +7 -4
  62. package/dist/cjs/index.js +7 -0
  63. package/dist/cjs/product/authshell/authshell.recipe.js +5 -1
  64. package/dist/cjs/product/command/command.recipe.js +4 -1
  65. package/dist/cjs/product/comments/comments.js +7 -2
  66. package/dist/cjs/product/comments/comments.recipe.js +25 -7
  67. package/dist/cjs/product/inbox/inbox.js +11 -3
  68. package/dist/cjs/product/memberssettings/index.js +6 -0
  69. package/dist/cjs/product/memberssettings/memberssettings.js +99 -0
  70. package/dist/cjs/product/memberssettings/memberssettings.recipe.js +83 -0
  71. package/dist/cjs/product/notificationssettings/index.js +5 -0
  72. package/dist/cjs/product/notificationssettings/notificationssettings.js +19 -0
  73. package/dist/cjs/product/notificationssettings/notificationssettings.recipe.js +44 -0
  74. package/dist/cjs/product/recordpage/index.js +2 -1
  75. package/dist/cjs/product/recordpage/recordpage.js +106 -9
  76. package/dist/cjs/product/recordpage/recordpage.recipe.js +68 -6
  77. package/dist/cjs/product/workspacegeneralsettings/index.js +5 -0
  78. package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.js +21 -0
  79. package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +51 -0
  80. package/dist/cjs/tokens/contract.js +1 -0
  81. package/dist/cjs/tokens/elevation.js +8 -5
  82. package/dist/cjs/tokens/palette.js +28 -8
  83. package/dist/cjs/tokens/scale.js +44 -2
  84. package/dist/cjs/tokens/semantic.js +2 -0
  85. package/dist/columncalc.css +15 -7
  86. package/dist/columncalc.layered.css +15 -7
  87. package/dist/command.css +23 -19
  88. package/dist/command.layered.css +23 -19
  89. package/dist/comments.css +28 -19
  90. package/dist/comments.d.ts +2 -2
  91. package/dist/comments.layered.css +28 -19
  92. package/dist/datatable.css +171 -71
  93. package/dist/datatable.layered.css +171 -71
  94. package/dist/datepicker.css +13 -41
  95. package/dist/datepicker.layered.css +13 -41
  96. package/dist/datepickerfield.css +12 -3
  97. package/dist/datepickerfield.d.ts +2 -2
  98. package/dist/datepickerfield.layered.css +12 -3
  99. package/dist/dialog.css +12 -7
  100. package/dist/dialog.layered.css +12 -7
  101. package/dist/emptystate.css +5 -3
  102. package/dist/emptystate.layered.css +5 -3
  103. package/dist/esm/components/badge/badge.recipe.js +22 -8
  104. package/dist/esm/components/bottomsheet/bottomsheet.js +52 -0
  105. package/dist/esm/components/bottomsheet/bottomsheet.recipe.js +74 -0
  106. package/dist/esm/components/bottomsheet/index.js +2 -0
  107. package/dist/esm/components/breadcrumb/breadcrumb.js +1 -1
  108. package/dist/esm/components/button/button.recipe.js +68 -16
  109. package/dist/esm/components/checkbox/checkbox.recipe.js +61 -9
  110. package/dist/esm/components/chip/chip.js +14 -2
  111. package/dist/esm/components/chip/chip.recipe.js +72 -2
  112. package/dist/esm/components/chipgroup/chipgroup.js +15 -0
  113. package/dist/esm/components/chipgroup/chipgroup.recipe.js +33 -0
  114. package/dist/esm/components/chipgroup/index.js +2 -0
  115. package/dist/esm/components/datatable/datatable.js +5 -1
  116. package/dist/esm/components/datatable/datatable.recipe.js +21 -6
  117. package/dist/esm/components/datepickerfield/datepickerfield.js +2 -2
  118. package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +16 -3
  119. package/dist/esm/components/dialog/dialog.recipe.js +22 -11
  120. package/dist/esm/components/emptystate/emptystate.recipe.js +7 -2
  121. package/dist/esm/components/fileupload/fileupload.js +20 -5
  122. package/dist/esm/components/input/index.js +1 -1
  123. package/dist/esm/components/input/input.js +30 -0
  124. package/dist/esm/components/input/input.recipe.js +17 -10
  125. package/dist/esm/components/menu/menu.js +18 -2
  126. package/dist/esm/components/menu/menu.recipe.js +21 -7
  127. package/dist/esm/components/menusheet/index.js +2 -0
  128. package/dist/esm/components/menusheet/menusheet.js +95 -0
  129. package/dist/esm/components/menusheet/menusheet.recipe.js +100 -0
  130. package/dist/esm/components/multiselect/multiselect.js +1 -1
  131. package/dist/esm/components/multiselect/multiselect.recipe.js +33 -9
  132. package/dist/esm/components/select/select.js +1 -1
  133. package/dist/esm/components/select/select.recipe.js +38 -12
  134. package/dist/esm/components/snackbar/index.js +2 -0
  135. package/dist/esm/components/snackbar/snackbar.js +84 -0
  136. package/dist/esm/components/snackbar/snackbar.recipe.js +68 -0
  137. package/dist/esm/components/table/table.recipe.js +7 -1
  138. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
  139. package/dist/esm/components/tabletoolbar/tabletoolbar.js +37 -12
  140. package/dist/esm/components/tabs/tabs.js +10 -4
  141. package/dist/esm/components/tabs/tabs.recipe.js +23 -6
  142. package/dist/esm/components/textarea/textarea.recipe.js +12 -9
  143. package/dist/esm/core/floating-portal.js +7 -4
  144. package/dist/esm/index.js +7 -0
  145. package/dist/esm/product/authshell/authshell.recipe.js +5 -1
  146. package/dist/esm/product/command/command.recipe.js +4 -1
  147. package/dist/esm/product/comments/comments.js +7 -2
  148. package/dist/esm/product/comments/comments.recipe.js +25 -7
  149. package/dist/esm/product/inbox/inbox.js +11 -3
  150. package/dist/esm/product/memberssettings/index.js +1 -0
  151. package/dist/esm/product/memberssettings/memberssettings.js +62 -0
  152. package/dist/esm/product/memberssettings/memberssettings.recipe.js +80 -0
  153. package/dist/esm/product/notificationssettings/index.js +1 -0
  154. package/dist/esm/product/notificationssettings/notificationssettings.js +16 -0
  155. package/dist/esm/product/notificationssettings/notificationssettings.recipe.js +41 -0
  156. package/dist/esm/product/recordpage/index.js +1 -1
  157. package/dist/esm/product/recordpage/recordpage.js +106 -10
  158. package/dist/esm/product/recordpage/recordpage.recipe.js +68 -6
  159. package/dist/esm/product/workspacegeneralsettings/index.js +1 -0
  160. package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.js +18 -0
  161. package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +48 -0
  162. package/dist/esm/tokens/contract.js +2 -1
  163. package/dist/esm/tokens/elevation.js +8 -5
  164. package/dist/esm/tokens/palette.js +28 -8
  165. package/dist/esm/tokens/scale.js +43 -1
  166. package/dist/esm/tokens/semantic.js +2 -0
  167. package/dist/fileupload.css +3 -1
  168. package/dist/fileupload.layered.css +3 -1
  169. package/dist/input.css +6 -4
  170. package/dist/input.layered.css +6 -4
  171. package/dist/listpage.css +3 -1
  172. package/dist/listpage.layered.css +3 -1
  173. package/dist/memberssettings.css +67 -0
  174. package/dist/memberssettings.d.ts +7 -0
  175. package/dist/memberssettings.layered.css +69 -0
  176. package/dist/menu.css +2 -2
  177. package/dist/menu.layered.css +2 -2
  178. package/dist/menusheet.css +36 -0
  179. package/dist/menusheet.d.ts +7 -0
  180. package/dist/menusheet.layered.css +38 -0
  181. package/dist/multiselect.css +13 -6
  182. package/dist/multiselect.layered.css +13 -6
  183. package/dist/native/tokens.d.ts +2 -1
  184. package/dist/native/tokens.js +20 -3
  185. package/dist/notificationssettings.css +22 -0
  186. package/dist/notificationssettings.d.ts +7 -0
  187. package/dist/notificationssettings.layered.css +24 -0
  188. package/dist/objectsettings.css +4 -4
  189. package/dist/objectsettings.layered.css +4 -4
  190. package/dist/recordpage.css +90 -23
  191. package/dist/recordpage.layered.css +90 -23
  192. package/dist/recordpanel.css +35 -16
  193. package/dist/recordpanel.layered.css +35 -16
  194. package/dist/resizablepanel.css +8 -5
  195. package/dist/resizablepanel.layered.css +8 -5
  196. package/dist/richtext.css +24 -8
  197. package/dist/richtext.layered.css +24 -8
  198. package/dist/savedviews.css +9 -2
  199. package/dist/savedviews.layered.css +9 -2
  200. package/dist/select.css +25 -5
  201. package/dist/select.layered.css +25 -5
  202. package/dist/settingsshell.css +2 -3
  203. package/dist/settingsshell.layered.css +2 -3
  204. package/dist/slider.css +6 -27
  205. package/dist/slider.layered.css +6 -27
  206. package/dist/snackbar.css +24 -0
  207. package/dist/snackbar.d.ts +7 -0
  208. package/dist/snackbar.layered.css +26 -0
  209. package/dist/statcard.css +3 -1
  210. package/dist/statcard.layered.css +3 -1
  211. package/dist/styles.css +911 -354
  212. package/dist/styles.layered.css +911 -354
  213. package/dist/table.css +35 -12
  214. package/dist/table.layered.css +35 -12
  215. package/dist/tabletoolbar.css +35 -24
  216. package/dist/tabletoolbar.layered.css +35 -24
  217. package/dist/tabs.css +18 -4
  218. package/dist/tabs.layered.css +18 -4
  219. package/dist/textarea.css +2 -6
  220. package/dist/textarea.layered.css +2 -6
  221. package/dist/themepicker.css +2 -1
  222. package/dist/themepicker.layered.css +2 -1
  223. package/dist/tokens.css +13 -2
  224. package/dist/tokens.json +20 -3
  225. package/dist/types/components/bottomsheet/bottomsheet.d.ts +35 -0
  226. package/dist/types/components/bottomsheet/bottomsheet.recipe.d.ts +3 -0
  227. package/dist/types/components/bottomsheet/index.d.ts +2 -0
  228. package/dist/types/components/breadcrumb/breadcrumb.d.ts +9 -1
  229. package/dist/types/components/button/button.d.ts +2 -0
  230. package/dist/types/components/button/button.recipe.d.ts +24 -6
  231. package/dist/types/components/checkbox/checkbox.recipe.d.ts +28 -5
  232. package/dist/types/components/chip/chip.d.ts +22 -0
  233. package/dist/types/components/chip/chip.recipe.d.ts +49 -1
  234. package/dist/types/components/chipgroup/chipgroup.d.ts +14 -0
  235. package/dist/types/components/chipgroup/chipgroup.recipe.d.ts +5 -0
  236. package/dist/types/components/chipgroup/index.d.ts +2 -0
  237. package/dist/types/components/datatable/datatable.d.ts +19 -0
  238. package/dist/types/components/datepickerfield/datepickerfield.d.ts +4 -1
  239. package/dist/types/components/datepickerfield/datepickerfield.recipe.d.ts +18 -3
  240. package/dist/types/components/fileupload/fileupload.d.ts +26 -0
  241. package/dist/types/components/input/index.d.ts +1 -1
  242. package/dist/types/components/input/input.d.ts +72 -0
  243. package/dist/types/components/menusheet/index.d.ts +2 -0
  244. package/dist/types/components/menusheet/menusheet.d.ts +42 -0
  245. package/dist/types/components/menusheet/menusheet.recipe.d.ts +3 -0
  246. package/dist/types/components/snackbar/index.d.ts +2 -0
  247. package/dist/types/components/snackbar/snackbar.d.ts +36 -0
  248. package/dist/types/components/snackbar/snackbar.recipe.d.ts +5 -0
  249. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +28 -1
  250. package/dist/types/components/tabs/tabs.d.ts +11 -1
  251. package/dist/types/core/floating-portal.d.ts +6 -5
  252. package/dist/types/index.d.ts +7 -0
  253. package/dist/types/product/comments/comments.d.ts +9 -3
  254. package/dist/types/product/comments/comments.recipe.d.ts +12 -2
  255. package/dist/types/product/inbox/inbox.d.ts +13 -1
  256. package/dist/types/product/memberssettings/index.d.ts +1 -0
  257. package/dist/types/product/memberssettings/memberssettings.d.ts +85 -0
  258. package/dist/types/product/memberssettings/memberssettings.recipe.d.ts +3 -0
  259. package/dist/types/product/notificationssettings/index.d.ts +1 -0
  260. package/dist/types/product/notificationssettings/notificationssettings.d.ts +37 -0
  261. package/dist/types/product/notificationssettings/notificationssettings.recipe.d.ts +3 -0
  262. package/dist/types/product/recordpage/index.d.ts +1 -1
  263. package/dist/types/product/recordpage/recordpage.d.ts +99 -2
  264. package/dist/types/product/workspacegeneralsettings/index.d.ts +1 -0
  265. package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.d.ts +48 -0
  266. package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.recipe.d.ts +3 -0
  267. package/dist/types/tokens/contract.d.ts +4 -1
  268. package/dist/types/tokens/elevation.d.ts +8 -5
  269. package/dist/types/tokens/palette.d.ts +9 -1
  270. package/dist/types/tokens/scale.d.ts +11 -1
  271. package/dist/types/tokens/semantic.d.ts +2 -0
  272. package/dist/wheelpicker.css +4 -2
  273. package/dist/wheelpicker.layered.css +4 -2
  274. package/dist/workspacegeneralsettings.css +30 -0
  275. package/dist/workspacegeneralsettings.d.ts +7 -0
  276. package/dist/workspacegeneralsettings.layered.css +32 -0
  277. package/package.json +36 -1
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MembersSettings = MembersSettings;
37
+ exports.InviteMembersDialog = InviteMembersDialog;
38
+ const jsx_runtime_1 = require("react/jsx-runtime");
39
+ const lucide_react_1 = require("lucide-react");
40
+ const React = __importStar(require("react"));
41
+ const avatar_1 = require("../../components/avatar");
42
+ const badge_1 = require("../../components/badge");
43
+ const button_1 = require("../../components/button");
44
+ const dialog_1 = require("../../components/dialog");
45
+ const formfield_1 = require("../../components/formfield");
46
+ const select_1 = require("../../components/select");
47
+ const tabs_keyboard_1 = require("../../components/tabs/tabs-keyboard");
48
+ const textarea_1 = require("../../components/textarea");
49
+ const textlink_1 = require("../../components/textlink");
50
+ const memberssettings_recipe_1 = require("./memberssettings.recipe");
51
+ /**
52
+ * Attio's "Members and teams" settings page (crisp#636, P-119/P-120):
53
+ * title + description, a Members/Teams segmented switcher, a
54
+ * search+Filter+Invite toolbar, and the members table (User/Role/Teams).
55
+ * Compose `InviteMembersDialog` alongside for the "Invite members" flow.
56
+ */
57
+ function MembersSettings({ members, searchValue, onSearchChange, onFilterClick, onInviteClick, onRowMenuClick, tab: tabProp, onTabChange, teamsContent, className, title = "Members and teams", description = "Manage workspace members and teams, set access levels, and invite new users.", learnMoreLabel = "Learn more", learnMoreHref = "#", membersTabLabel = "Members", teamsTabLabel = "Teams", tablistLabel = "Members and teams", searchPlaceholder = "Search name or email", filterLabel = "Filter", inviteLabel = "Invite members", userColumnLabel = "User", roleColumnLabel = "Role", teamsColumnLabel = "Teams", memberActionsLabel = "Member actions", noTeamsLabel = "No teams yet", ...rest }) {
58
+ const [internalTab, setInternalTab] = React.useState("members");
59
+ const tab = tabProp ?? internalTab;
60
+ const setTab = (next) => {
61
+ if (tabProp === undefined)
62
+ setInternalTab(next);
63
+ onTabChange?.(next);
64
+ };
65
+ const listRef = React.useRef(null);
66
+ const tabEntries = [
67
+ {
68
+ value: "members",
69
+ label: membersTabLabel,
70
+ icon: (0, jsx_runtime_1.jsx)(lucide_react_1.User, { size: 16 }),
71
+ },
72
+ {
73
+ value: "teams",
74
+ label: teamsTabLabel,
75
+ icon: (0, jsx_runtime_1.jsx)(lucide_react_1.UsersRound, { size: 16 }),
76
+ },
77
+ ];
78
+ const { onKeyDown, tabIndexFor } = (0, tabs_keyboard_1.useTablistKeyboard)({
79
+ tabs: tabEntries,
80
+ active: tab,
81
+ select: (value) => setTab(value),
82
+ listRef,
83
+ });
84
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, memberssettings_recipe_1.memberssettingsRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-memberssettings-page", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-memberssettings-heading", children: [(0, jsx_runtime_1.jsx)("h1", { className: "crisp-memberssettings-title", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "crisp-memberssettings-desc", children: [description, " ", (0, jsx_runtime_1.jsx)(textlink_1.TextLink, { href: learnMoreHref, children: learnMoreLabel })] })] }), (0, jsx_runtime_1.jsx)("div", { ref: listRef, className: "crisp-memberssettings-tabpair", role: "tablist", "aria-label": tablistLabel, onKeyDown: onKeyDown, children: tabEntries.map((t) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "tab", "data-value": t.value, "aria-selected": tab === t.value, "data-selected": tab === t.value ? "" : undefined, tabIndex: tabIndexFor(t.value), className: "crisp-memberssettings-tab", onClick: () => setTab(t.value), children: [t.icon, t.label] }, t.value))) }), tab === "members" ? ((0, jsx_runtime_1.jsxs)("div", { role: "tabpanel", "aria-label": membersTabLabel, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-memberssettings-toolbar", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-memberssettings-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 16 }), (0, jsx_runtime_1.jsx)("input", { value: searchValue, onChange: (e) => onSearchChange?.(e.target.value), placeholder: searchPlaceholder })] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-memberssettings-filterbtn", onClick: onFilterClick, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Filter, { size: 14 }), filterLabel] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-memberssettings-invitebtn", onClick: onInviteClick, children: inviteLabel })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-memberssettings-table-wrap", children: (0, jsx_runtime_1.jsxs)("table", { className: "crisp-memberssettings-table", children: [(0, jsx_runtime_1.jsx)("thead", { children: (0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("th", { children: userColumnLabel }), (0, jsx_runtime_1.jsx)("th", { children: roleColumnLabel }), (0, jsx_runtime_1.jsx)("th", { children: teamsColumnLabel })] }) }), (0, jsx_runtime_1.jsx)("tbody", { children: members.map((m) => ((0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("td", { children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-memberssettings-user", children: [m.avatarSrc ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-memberssettings-avatarimg", src: m.avatarSrc, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "circle", tone: "brand", children: String(m.name).charAt(0) })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-memberssettings-usermeta", children: [(0, jsx_runtime_1.jsxs)("span", { children: [m.name, m.isYou ? " (You)" : ""] }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-memberssettings-useremail", children: m.email })] })] }) }), (0, jsx_runtime_1.jsx)("td", { children: m.role === "Admin" ? ((0, jsx_runtime_1.jsx)(badge_1.Badge, { tone: "purple", children: m.role })) : (m.role) }), (0, jsx_runtime_1.jsxs)("td", { children: [m.teams ?? "—", (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-memberssettings-kebab", "aria-label": memberActionsLabel, onClick: () => onRowMenuClick?.(m), children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16 }) })] })] }, m.id))) })] }) })] })) : ((0, jsx_runtime_1.jsx)("div", { role: "tabpanel", "aria-label": teamsTabLabel, children: teamsContent ?? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-memberssettings-teamspanel", children: noTeamsLabel })) }))] }) }));
85
+ }
86
+ MembersSettings.displayName = "MembersSettings";
87
+ /**
88
+ * Attio's "Invite members" modal (crisp#636, P-120), measured live: 708px
89
+ * wide, a multi-email composer, an "Invite as" select (default Member) and
90
+ * an optional "Add to team" search-or-create select, footer "Send Invites".
91
+ */
92
+ function InviteMembersDialog({ open, onOpenChange, emails, onEmailsChange, inviteAs, onInviteAsChange, team, onTeamChange, teamOptions = [], onSend, title = "Invite members", emailsPlaceholder = "Send Invite to ...", inviteAsFieldLabel = "Invite as", memberOptionLabel = "Member — can edit", adminOptionLabel = "Admin — full access", addToTeamFieldLabel = "Add to team", addToTeamPlaceholder = "Search or create a team", sendLabel = "Send Invites ⌘⏎", ...rest }) {
93
+ const inviteAsOptions = [
94
+ { value: "member", label: memberOptionLabel },
95
+ { value: "admin", label: adminOptionLabel },
96
+ ];
97
+ return ((0, jsx_runtime_1.jsxs)(dialog_1.Dialog, { open: open, onOpenChange: onOpenChange, title: title, width: 708, ...rest, children: [(0, jsx_runtime_1.jsxs)(dialog_1.DialogBody, { children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-memberssettings-invitefield", children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: emails, onChange: (e) => onEmailsChange(e.target.value), placeholder: emailsPlaceholder, rows: 3 }) }), (0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: inviteAsFieldLabel, children: (0, jsx_runtime_1.jsx)(select_1.Select, { options: inviteAsOptions, value: inviteAs, onValueChange: (v) => onInviteAsChange(v) }) }), (0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: addToTeamFieldLabel, optional: true, children: (0, jsx_runtime_1.jsx)(select_1.Select, { options: teamOptions, value: team, onValueChange: onTeamChange, placeholder: addToTeamPlaceholder, searchable: true }) })] }), (0, jsx_runtime_1.jsx)(dialog_1.DialogFooter, { children: (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "primary", onClick: onSend, children: sendLabel }) })] }));
98
+ }
99
+ InviteMembersDialog.displayName = "InviteMembersDialog";
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.memberssettingsRecipe = void 0;
4
+ const core_1 = require("../../core");
5
+ const tokens_1 = require("../../tokens");
6
+ // Measured live against app.attio.com/<workspace>/settings/members-and-teams
7
+ // (crisp#636, P-119/P-120). The Members/Teams switcher is a plain segmented
8
+ // pill toggle -- NOT the shared `Tabs` primitive, which always reserves an
9
+ // 8px baseline strip and draws an ink underline (crisp#749's own tabs
10
+ // recipe comment): this page's tab container measured a clean 28px, no
11
+ // baseline, no underline, bg transparent. Reusing `Tabs` here would paint a
12
+ // baseline Attio's own switcher doesn't have.
13
+ const config = (0, core_1.defineRecipe)({
14
+ name: "memberssettings",
15
+ base: `& .crisp-memberssettings-page { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["6"]}; font-family: ${tokens_1.contract.font.sans}; }
16
+ & .crisp-memberssettings-heading { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["0.5"]}; }
17
+ & .crisp-memberssettings-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; }
18
+ & .crisp-memberssettings-desc { font-size: ${tokens_1.contract.text.lg}; line-height: 20px; color: ${tokens_1.contract.fgMuted}; margin: 0; }
19
+
20
+ /* Segmented Members/Teams switcher -- measured: 28px pills, radius 8,
21
+ 4px gap, 6px icon-label gap, 14/500 label, selected bg bgSubtle +
22
+ inset borderSubtle ring, unselected transparent + a flat 63%-opacity
23
+ fgPrimary mix (measured rgba(0,0,0,.63) on the live page, not the
24
+ solid fgMuted token — same alpha technique this file's table header
25
+ already uses). */
26
+ & .crisp-memberssettings-tabpair { display: inline-flex; align-items: center; gap: 4px; }
27
+ & .crisp-memberssettings-tab { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: 28px; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; box-shadow: inset 0 0 0 1px transparent; font-family: inherit; 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); cursor: pointer; white-space: nowrap; transition: color .12s ease, background-color .12s ease, box-shadow .12s ease; }
28
+ & .crisp-memberssettings-tab svg { flex-shrink: 0; }
29
+ & .crisp-memberssettings-tab:hover:not([data-selected]) { color: ${tokens_1.contract.fgPrimary}; }
30
+ & .crisp-memberssettings-tab[data-selected] { color: ${tokens_1.contract.fgPrimary}; background: ${tokens_1.contract.bgSubtle}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}; }
31
+ & .crisp-memberssettings-tab:focus-visible { outline: 2px solid ${tokens_1.contract.bgBrandSolid}; outline-offset: 1px; }
32
+
33
+ /* Toolbar row: search grows, Filter + Invite sit trailing -- measured
34
+ 32px height on all three, search radius 9 with a 6% ink ring,
35
+ Filter/Invite radius 9 with the button drop-shadow pairing. */
36
+ & .crisp-memberssettings-toolbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
37
+ & .crisp-memberssettings-search { display: flex; align-items: center; flex: 1; min-width: 0; gap: ${tokens_1.contract.space["1.5"]}; height: 32px; padding: 0 ${tokens_1.contract.space["2.5"]} 0 ${tokens_1.contract.space["2"]}; border-radius: 9px; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); color: ${tokens_1.contract.fgMuted}; }
38
+ & .crisp-memberssettings-search:focus-within { box-shadow: inset 0 0 0 1px ${tokens_1.contract.bgBrandSolid}; }
39
+ & .crisp-memberssettings-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
40
+ & .crisp-memberssettings-search input::placeholder { color: ${tokens_1.contract.fgMuted}; }
41
+ & .crisp-memberssettings-filterbtn { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: 32px; padding: 6px 10px 6px 8px; border: none; border-radius: 9px; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px transparent, 0 0 2px 0 rgba(28,40,64,.18), 0 1px 3px 0 rgba(0,0,0,.04); color: ${tokens_1.contract.fgPrimary}; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; cursor: pointer; white-space: nowrap; }
42
+ & .crisp-memberssettings-filterbtn:hover { background: ${tokens_1.contract.bgRaised}; }
43
+ /* your-moon/crisp#979: bgBrandContrast, not bgBrandSolid -- the accent
44
+ (#0298d9) only clears 3.23:1 with white; the darker sibling clears
45
+ 4.5:1+, same fix already applied to Button/Badge/Avatar (#897) and
46
+ TableToolbar/Dialog/Command/Comments/AuthShell (#953/#961), which
47
+ explicitly flagged this button as found-not-fixed. */
48
+ & .crisp-memberssettings-invitebtn { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: 32px; padding: 6px 10px 6px 8px; border: none; border-radius: 9px; background: ${tokens_1.contract.bgBrandContrast}; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06), 0 2px 4px -2px color-mix(in srgb, ${tokens_1.contract.bgBrandContrast} 12%, transparent), 0 3px 6px -2px color-mix(in srgb, ${tokens_1.contract.bgBrandContrast} 8%, transparent); color: ${tokens_1.contract.fgOnBrand}; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; cursor: pointer; white-space: nowrap; }
49
+ & .crisp-memberssettings-invitebtn:hover { filter: brightness(0.95); }
50
+
51
+ /* Table wrapper -- measured card: radius 12, 1px borderSubtle, 40px
52
+ rows, header label 12/500/63%-opacity fgPrimary. */
53
+ & .crisp-memberssettings-table-wrap { border-radius: 12px; border: 1px solid ${tokens_1.contract.borderSubtle}; overflow: hidden; }
54
+ & .crisp-memberssettings-table { width: 100%; border-collapse: collapse; font-family: inherit; }
55
+ & .crisp-memberssettings-table th { height: 32px; padding: 0 ${tokens_1.contract.space["4"]}; text-align: start; 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); border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; background: ${tokens_1.contract.bgSurface}; }
56
+ & .crisp-memberssettings-table td { height: 40px; padding: 0 ${tokens_1.contract.space["4"]}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; }
57
+ & .crisp-memberssettings-table tr:last-child td { border-bottom: none; }
58
+ & .crisp-memberssettings-user { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
59
+ & .crisp-memberssettings-avatarimg { width: 24px; height: 24px; border-radius: ${tokens_1.contract.radius.full}; object-fit: cover; }
60
+ /* Name + email sit on ONE line, not stacked -- confirmed live: both spans
61
+ share the same y and the same 14px size, only the email's colour
62
+ differs (a flat 63%-opacity fgPrimary mix, not a smaller muted font). */
63
+ & .crisp-memberssettings-usermeta { display: flex; align-items: baseline; gap: ${tokens_1.contract.space["2"]}; min-width: 0; }
64
+ & .crisp-memberssettings-usermeta > span:first-child { flex-shrink: 0; }
65
+ & .crisp-memberssettings-useremail { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.regular}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
66
+ & .crisp-memberssettings-kebab { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-inline-start: auto; border: none; border-radius: ${tokens_1.contract.radius.sm}; background: none; font-family: inherit; color: ${tokens_1.contract.fgMuted}; cursor: pointer; }
67
+ & .crisp-memberssettings-kebab:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
68
+
69
+ & .crisp-memberssettings-teamspanel { display: flex; align-items: center; justify-content: center; padding: ${tokens_1.contract.space["8"]} 0; color: ${tokens_1.contract.fgMuted}; font-size: ${tokens_1.contract.text.lg}; }
70
+
71
+ /* Invite dialog fields -- measured 708x386 dialog, radius 16; the
72
+ "Invite as"/"Add to team" selects are 32/34px with a flat 1px
73
+ 6%-ink border and 9/10px radius respectively (Attio's own two
74
+ selects don't share one radius). */
75
+ & .crisp-memberssettings-invitefield { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1.5"]}; }
76
+ & .crisp-memberssettings-invitelabel { font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
77
+ `,
78
+ variants: {},
79
+ defaultVariants: {},
80
+ compoundVariants: [],
81
+ });
82
+ exports.memberssettingsRecipe = (0, core_1.resolveRecipe)(config);
83
+ exports.default = config;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationsSettings = void 0;
4
+ var notificationssettings_1 = require("./notificationssettings");
5
+ Object.defineProperty(exports, "NotificationsSettings", { enumerable: true, get: function () { return notificationssettings_1.NotificationsSettings; } });
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationsSettings = NotificationsSettings;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const lucide_react_1 = require("lucide-react");
6
+ const checkbox_1 = require("../../components/checkbox");
7
+ const switch_1 = require("../../components/switch");
8
+ const textlink_1 = require("../../components/textlink");
9
+ const notificationssettings_recipe_1 = require("./notificationssettings.recipe");
10
+ /**
11
+ * Attio's "Notifications" settings page (crisp#630, P-083): title +
12
+ * description, a "Daily digest" card (a single toggle row), and a
13
+ * "Collaboration notifications" matrix — a header row plus one row per
14
+ * event, each with an Email and an App checkbox. Measured live.
15
+ */
16
+ function NotificationsSettings({ dailyDigestEnabled, onDailyDigestChange, rows, onEmailChange, onAppChange, className, title = "Notifications", description = "Customize your notification settings to stay informed without being overwhelmed.", learnMoreLabel = "Learn more", learnMoreHref = "#", dailyDigestSectionTitle = "Daily digest", dailyDigestRowTitle = "Enable daily digest", dailyDigestRowDescription = "Includes tasks overdue and due today. Sent every morning if any tasks are due or overdue.", collaborationSectionTitle = "Collaboration notifications", notifyMeAboutLabel = "Notify me about", emailColumnLabel = "Email", appColumnLabel = "App", ...rest }) {
17
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, notificationssettings_recipe_1.notificationssettingsRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-page", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-heading", children: [(0, jsx_runtime_1.jsx)("h1", { className: "crisp-notificationssettings-title", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "crisp-notificationssettings-desc", children: [description, " ", (0, jsx_runtime_1.jsx)(textlink_1.TextLink, { href: learnMoreHref, children: learnMoreLabel })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-section", children: [(0, jsx_runtime_1.jsx)("h2", { className: "crisp-notificationssettings-sectiontitle", children: dailyDigestSectionTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-digestcard", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-digesttext", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-notificationssettings-rowtitle", children: dailyDigestRowTitle }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-notificationssettings-rowdesc", children: dailyDigestRowDescription })] }), (0, jsx_runtime_1.jsx)(switch_1.Switch, { checked: dailyDigestEnabled, onCheckedChange: onDailyDigestChange, "aria-label": dailyDigestRowTitle })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-section", children: [(0, jsx_runtime_1.jsx)("h2", { className: "crisp-notificationssettings-sectiontitle", children: collaborationSectionTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-matrix", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-matrixhead", children: [(0, jsx_runtime_1.jsxs)("span", { className: "crisp-notificationssettings-matrixhead-about", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Bell, { size: 14 }), notifyMeAboutLabel] }), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-notificationssettings-matrixhead-col", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 14 }), emailColumnLabel] }), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-notificationssettings-matrixhead-col", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.MonitorSmartphone, { size: 14 }), appColumnLabel] })] }), rows.map((row) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-matrixrow", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-notificationssettings-matrixrow-about", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-notificationssettings-rowtitle", children: row.title }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-notificationssettings-rowdesc", children: row.description })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-notificationssettings-matrixrow-col", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { checked: row.email, onChange: (e) => onEmailChange(row.id, e.target.checked), "aria-label": `${emailColumnLabel}: ${typeof row.title === "string" ? row.title : row.id}` }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-notificationssettings-matrixrow-col", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { checked: row.app, onChange: (e) => onAppChange(row.id, e.target.checked), "aria-label": `${appColumnLabel}: ${typeof row.title === "string" ? row.title : row.id}` }) })] }, row.id)))] })] })] }) }));
18
+ }
19
+ NotificationsSettings.displayName = "NotificationsSettings";
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.notificationssettingsRecipe = void 0;
4
+ const core_1 = require("../../core");
5
+ const tokens_1 = require("../../tokens");
6
+ // Measured live against app.attio.com/<workspace>/settings/notifications
7
+ // (crisp#630, P-083). Two sections, each a 16/600 heading over a bordered
8
+ // 12px-radius card: "Daily digest" (a single 56px row, label 14/500 +
9
+ // description 12/500/63%-opacity, a Switch trailing) and "Collaboration
10
+ // notifications" (a header row -- 12/500/63%-opacity labels -- then 7 rows,
11
+ // each 52px, a title/description pair on the left and two Checkboxes,
12
+ // right-aligned under Email/App, per row).
13
+ const config = (0, core_1.defineRecipe)({
14
+ name: "notificationssettings",
15
+ base: `& .crisp-notificationssettings-page { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["6"]}; font-family: ${tokens_1.contract.font.sans}; }
16
+ & .crisp-notificationssettings-heading { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["0.5"]}; }
17
+ & .crisp-notificationssettings-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; }
18
+ & .crisp-notificationssettings-desc { font-size: ${tokens_1.contract.text.lg}; line-height: 20px; color: ${tokens_1.contract.fgMuted}; margin: 0; }
19
+
20
+ & .crisp-notificationssettings-section { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["4"]}; }
21
+ & .crisp-notificationssettings-sectiontitle { font-size: 16px; line-height: 20px; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; margin: 0; }
22
+
23
+ /* Daily digest card: one bordered 12px-radius row. */
24
+ & .crisp-notificationssettings-digestcard { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["6"]}; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["3"]}; border: 1px solid ${tokens_1.contract.borderSubtle}; border-radius: 12px; background: ${tokens_1.contract.bgSurface}; }
25
+ & .crisp-notificationssettings-digesttext { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1"]}; }
26
+ & .crisp-notificationssettings-rowtitle { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
27
+ & .crisp-notificationssettings-rowdesc { 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); }
28
+
29
+ /* Collaboration matrix: a bordered card, header row + N body rows. */
30
+ & .crisp-notificationssettings-matrix { border: 1px solid ${tokens_1.contract.borderSubtle}; border-radius: 12px; overflow: hidden; background: ${tokens_1.contract.bgSurface}; }
31
+ & .crisp-notificationssettings-matrixhead { display: flex; align-items: center; gap: ${tokens_1.contract.space["3"]}; padding: 0 ${tokens_1.contract.space["4"]}; height: 40px; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; }
32
+ & .crisp-notificationssettings-matrixhead-about { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; flex: 1; min-width: 0; 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); }
33
+ & .crisp-notificationssettings-matrixhead-col { display: flex; align-items: center; justify-content: center; gap: ${tokens_1.contract.space["1.5"]}; width: 64px; 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} 63%, transparent); }
34
+ & .crisp-notificationssettings-matrixrow { display: flex; align-items: center; gap: ${tokens_1.contract.space["3"]}; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["4"]}; min-height: 52px; }
35
+ & .crisp-notificationssettings-matrixrow + .crisp-notificationssettings-matrixrow { border-top: 1px solid ${tokens_1.contract.borderSubtle}; }
36
+ & .crisp-notificationssettings-matrixrow-about { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1"]}; flex: 1; min-width: 0; }
37
+ & .crisp-notificationssettings-matrixrow-col { display: flex; align-items: center; justify-content: center; width: 64px; flex-shrink: 0; }
38
+ `,
39
+ variants: {},
40
+ defaultVariants: {},
41
+ compoundVariants: [],
42
+ });
43
+ exports.notificationssettingsRecipe = (0, core_1.resolveRecipe)(config);
44
+ exports.default = config;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.recordpageRecipe = exports.recordPageLabels = exports.RecordPage = exports.RecordDetails = exports.useEditableField = exports.editableInputType = exports.tagTone = void 0;
3
+ exports.recordpageRecipe = exports.recordPageLabels = exports.RecordPageMain = exports.RecordPage = exports.RecordDetails = exports.useEditableField = exports.editableInputType = exports.tagTone = void 0;
4
4
  var column_1 = require("./column");
5
5
  Object.defineProperty(exports, "tagTone", { enumerable: true, get: function () { return column_1.tagTone; } });
6
6
  var editable_field_1 = require("./editable-field");
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "useEditableField", { enumerable: true, get: func
9
9
  var recordpage_1 = require("./recordpage");
10
10
  Object.defineProperty(exports, "RecordDetails", { enumerable: true, get: function () { return recordpage_1.RecordDetails; } });
11
11
  Object.defineProperty(exports, "RecordPage", { enumerable: true, get: function () { return recordpage_1.RecordPage; } });
12
+ Object.defineProperty(exports, "RecordPageMain", { enumerable: true, get: function () { return recordpage_1.RecordPageMain; } });
12
13
  Object.defineProperty(exports, "recordPageLabels", { enumerable: true, get: function () { return recordpage_1.recordPageLabels; } });
13
14
  var recordpage_recipe_1 = require("./recordpage.recipe");
14
15
  Object.defineProperty(exports, "recordpageRecipe", { enumerable: true, get: function () { return recordpage_recipe_1.recordpageRecipe; } });
@@ -35,11 +35,13 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.recordPageLabels = void 0;
37
37
  exports.RecordDetails = RecordDetails;
38
+ exports.RecordPageMain = RecordPageMain;
38
39
  exports.RecordPage = RecordPage;
39
40
  const jsx_runtime_1 = require("react/jsx-runtime");
40
41
  const lucide_react_1 = require("lucide-react");
41
42
  const React = __importStar(require("react"));
42
43
  const avatar_1 = require("../../components/avatar");
44
+ const button_1 = require("../../components/button");
43
45
  const checkbox_1 = require("../../components/checkbox");
44
46
  const drawer_1 = require("../../components/drawer");
45
47
  const menu_1 = require("../../components/menu");
@@ -100,6 +102,22 @@ exports.recordPageLabels = {
100
102
  share: "Share",
101
103
  comments: "Comments",
102
104
  noLists: "This record has not been added to any lists.",
105
+ filters: "Filters",
106
+ addMeeting: "Add meeting",
107
+ noFiles: "No files",
108
+ filesHint: "Drag a file here or choose one from your computer.",
109
+ newFolder: "New folder",
110
+ uploadFile: "Upload file",
111
+ fileMoreActions: "More file actions",
112
+ noDealsFound: "No Deals found",
113
+ noDealsHint: "There are no related records for this relationship.",
114
+ newDeal: "New Deal",
115
+ noEmails: "No emails",
116
+ noEmailsHint: "This record doesn't have any emails, or they may be hidden due to permissions.",
117
+ configureMailbox: "Configure mailbox",
118
+ upgradeToViewCalls: "Upgrade to view calls",
119
+ callsUpgradeHint: "No call recordings yet! Upgrade to Pro to start recording calls.",
120
+ upgrade: "Upgrade",
103
121
  highlights: "Highlights",
104
122
  recordDetails: "Record Details",
105
123
  searchFields: "Search fields",
@@ -311,7 +329,14 @@ function NotesSection({ notes, onAdd, labels, }) {
311
329
  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) => {
312
330
  onAdd(t);
313
331
  setOpen(false);
314
- } })), 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))))] }));
332
+ } })), notes.length === 0 && !open ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: labels.noNotesYet })) : (
333
+ // #871: one line, not a two-row card -- measured live: avatar,
334
+ // then the note's own title and body run together inline, then a
335
+ // relative time at the far end of the SAME row. No author name at
336
+ // all (Attio's real preview never shows one here, only the note's
337
+ // own content) -- `labels.you` stays defined for a consumer that
338
+ // still wants it elsewhere, just unused in this exact spot now.
339
+ 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))))] }));
315
340
  }
316
341
  function TasksSection({ tasks, onAdd, onToggle, labels, }) {
317
342
  const [open, setOpen] = React.useState(false);
@@ -344,13 +369,51 @@ function EmptyCard({ icon, children, }) {
344
369
  * `RecordPage`'s own root does: `<div className={recordpageRecipe()}>`
345
370
  * (also exported from this package).
346
371
  */
347
- function RecordDetails({ record, columns, sections, onEdit, labels, className, ...rest }) {
372
+ 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 }) {
348
373
  const t = useRecordPageLabels(labels);
349
374
  const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, editable_field_1.useEditableField)(onEdit);
350
375
  const [detailsOpen, setDetailsOpen] = React.useState(true);
351
376
  const [searchOpen, setSearchOpen] = React.useState(false);
352
377
  const [fieldQuery, setFieldQuery] = React.useState("");
353
378
  const [showAllValues, setShowAllValues] = React.useState(false);
379
+ // #930: controlled/uncontrolled width, same split as RecordPanel's own
380
+ // resizable width -- only read when `resizable`, same reasoning as
381
+ // RecordPanel's own (a non-resizing consumer has no business carrying
382
+ // width state at all).
383
+ const [internalWidth, setInternalWidth] = React.useState(defaultWidth);
384
+ const width = controlledWidth ?? internalWidth;
385
+ const setWidth = (next) => {
386
+ const clamped = Math.max(minWidth, Math.min(maxWidth, next));
387
+ if (controlledWidth === undefined)
388
+ setInternalWidth(clamped);
389
+ onWidthChange?.(clamped);
390
+ };
391
+ const [detailsResizing, setDetailsResizing] = React.useState(false);
392
+ const detailsDragRef = React.useRef(null);
393
+ const onDetailsResizeDown = (e) => {
394
+ // This column is a leading (left-docked) rail, the mirror image of
395
+ // RecordPanel's own trailing (right-docked) one -- a rightward pull
396
+ // grows it in LTR, the same direction RecordPage's own internal aside
397
+ // resize already uses (#212/#255).
398
+ detailsDragRef.current = {
399
+ x: e.clientX,
400
+ w: width,
401
+ dir: (0, core_1.isRtlElement)(e.currentTarget) ? -1 : 1,
402
+ };
403
+ setDetailsResizing(true);
404
+ e.target.setPointerCapture(e.pointerId);
405
+ };
406
+ const onDetailsResizeMove = (e) => {
407
+ const r = detailsDragRef.current;
408
+ if (!r)
409
+ return;
410
+ setWidth(r.w + r.dir * (e.clientX - r.x));
411
+ };
412
+ const onDetailsResizeUp = (e) => {
413
+ detailsDragRef.current = null;
414
+ setDetailsResizing(false);
415
+ e.target.releasePointerCapture(e.pointerId);
416
+ };
354
417
  const fields = columns.filter((col) => col.type !== "entity");
355
418
  const q = fieldQuery.trim().toLowerCase();
356
419
  const matches = (col) => !q || col.label.toLowerCase().includes(q);
@@ -387,7 +450,7 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
387
450
  groups = [{ title: undefined, fields: shown }];
388
451
  }
389
452
  const totalShown = groups.reduce((n, g) => n + g.fields.length, 0);
390
- 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", {
453
+ 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", {
391
454
  // biome-ignore lint/a11y/noAutofocus: focusing the just-opened field search is expected
392
455
  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) => {
393
456
  if (e.key === "Escape") {
@@ -461,9 +524,37 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
461
524
  setSearchOpen(next);
462
525
  if (!next)
463
526
  setFieldQuery("");
464
- }, children: showAllValues ? t.viewLess : t.viewAllValues }))] })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-noresults", children: t.noFieldsMatch(fieldQuery) })))] }));
527
+ }, 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) => {
528
+ if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
529
+ return;
530
+ const rtl = (0, core_1.isRtlElement)(e.currentTarget);
531
+ const grow = e.key === (rtl ? "ArrowLeft" : "ArrowRight");
532
+ setWidth(grow ? width + 16 : width - 16);
533
+ } }))] }));
465
534
  }
466
535
  RecordDetails.displayName = "RecordDetails";
536
+ /**
537
+ * The main/tab-content column's own box, on its own (#750) — the same
538
+ * "standalone piece" `RecordDetails` already is for the Details column,
539
+ * mirrored to the other side of the layout. `RecordPage` composes this
540
+ * internally for its own tabbed body (below) — this exact box, not a second
541
+ * copy — so a consumer building a custom record page (its own tab set, its
542
+ * own menu, `RecordDetails` for the left column, but not the full
543
+ * `RecordPage`, which hardcodes the CRM tab set) gets the same
544
+ * Attio-measured inset: `flex: 1; min-width: 0; display: flex;
545
+ * flex-direction: column; min-height: 0; overflow-y: auto; padding: 12px
546
+ * 20px` (`recordpage.recipe.ts`'s own `.crisp-recordpage-main`) — without
547
+ * reaching for that internal class name directly, the only option before
548
+ * this existed.
549
+ *
550
+ * Needs the same single `.crisp-recordpage`-scoped ancestor `RecordDetails`
551
+ * already documents — wrap both in `recordpageRecipe()`, the way
552
+ * `RecordPage`'s own root does.
553
+ */
554
+ function RecordPageMain({ className, children, ...rest }) {
555
+ return ((0, jsx_runtime_1.jsx)("main", { className: (0, core_1.cx)("crisp-recordpage-main", className), ...rest, children: children }));
556
+ }
557
+ RecordPageMain.displayName = "RecordPageMain";
467
558
  /**
468
559
  * The full-page company record view — the page that opens when you click into a
469
560
  * record (as opposed to the peek [RecordPanel]). A top breadcrumb bar with
@@ -472,7 +563,7 @@ RecordDetails.displayName = "RecordDetails";
472
563
  * Emails sections (Notes & Tasks are live — add and check things off). Drop it
473
564
  * into the app's main content area.
474
565
  */
475
- 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, comments: commentsProp, onPostComment, currentUser, onShare, ...rest }) {
566
+ 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 }) {
476
567
  const t = useRecordPageLabels(labels);
477
568
  const [favorite, setFavorite] = React.useState(false);
478
569
  // Notes/Tasks are controlled when the caller supplies `notes`/`tasks` (even
@@ -704,13 +795,19 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
704
795
  case "overview":
705
796
  return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-panel", children: [highlights !== false && ((0, jsx_runtime_1.jsxs)("section", { children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-section-title", children: t.highlights }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-hl-card", children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-hl-grid", children: highlights.map((h) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-hl-cell", children: [h.icon && ((0, jsx_runtime_1.jsx)(h.icon, { className: "crisp-recordpage-hl-icon", size: 15, strokeWidth: 1.75 })), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-hl-label", children: h.label }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-hl-value", children: h.value ?? ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-hl-value--empty", children: h.empty })) })] }, h.label))) }) })] })), activityFeed, (0, jsx_runtime_1.jsxs)("section", { children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.emails, count: 0 }), emailsEmpty] }), (0, jsx_runtime_1.jsx)(NotesSection, { notes: notes, onAdd: addNote, labels: t }), (0, jsx_runtime_1.jsx)(TasksSection, { tasks: tasks, onAdd: addTask, onToggle: toggleTask, labels: t })] }));
706
797
  case "activity":
707
- return (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: activityFeed });
798
+ return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: (0, jsx_runtime_1.jsxs)("section", { children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.activity, action: (0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-tabtoolbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { size: 14, strokeWidth: 1.75 }), t.filters] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 1.75 }), t.addMeeting] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-feed", children: activity.map((a) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-feed-item", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-feed-dot", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Activity, { size: 13, strokeWidth: 2 }) }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-feed-body", children: [a.text, (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-feed-time", children: a.time })] })] }, a.id))) })] }) }));
799
+ case "files":
800
+ return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel crisp-recordpage-panel--center", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-illustrated", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-illustrated-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Folder, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-title", children: t.noFiles }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-desc", children: t.filesHint }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-illustrated-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 1.75 }), t.newFolder] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 1.75 }), t.uploadFile] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.fileMoreActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) })] })] }) }));
801
+ case "deals":
802
+ return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel crisp-recordpage-panel--center", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-illustrated", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-illustrated-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Merge, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-title", children: t.noDealsFound }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-desc", children: t.noDealsHint }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-actions", children: (0, jsx_runtime_1.jsxs)(button_1.Button, { intent: "primary", size: "md", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), t.newDeal] }) })] }) }));
708
803
  case "notes":
709
804
  return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: (0, jsx_runtime_1.jsx)(NotesSection, { notes: notes, onAdd: addNote, labels: t }) }));
710
805
  case "tasks":
711
806
  return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: (0, jsx_runtime_1.jsx)(TasksSection, { tasks: tasks, onAdd: addTask, onToggle: toggleTask, labels: t }) }));
712
807
  case "emails":
713
- return (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: emailsEmpty });
808
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-panel", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.emails }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel crisp-recordpage-panel--center", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-illustrated", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-illustrated-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-title", children: t.noEmails }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-desc", children: t.noEmailsHint }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-actions", children: (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "primary", size: "md", children: t.configureMailbox }) })] }) })] }));
809
+ case "calls":
810
+ return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel crisp-recordpage-panel--center", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-illustrated", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-illustrated-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Phone, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-title crisp-recordpage-illustrated-title--lg", children: t.upgradeToViewCalls }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-desc", children: t.callsUpgradeHint }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-actions", children: (0, jsx_runtime_1.jsxs)(button_1.Button, { intent: "primary", size: "md", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Zap, { size: 15, strokeWidth: 1.75 }), t.upgrade] }) })] }) }));
714
811
  default:
715
812
  return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: (0, jsx_runtime_1.jsx)(EmptyCard, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Folder, { size: 22, strokeWidth: 1.5 }), children: t.nothingHereYet }) }));
716
813
  }
@@ -728,7 +825,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
728
825
  const effectivePanel = tabsProp
729
826
  ? (active) => tabsProp.find((tb) => tb.id === active)?.render()
730
827
  : builtinPanel;
731
- 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.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) => {
828
+ 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) => {
732
829
  if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
733
830
  return;
734
831
  // The pointer drag learned its direction in #212; this did not.
@@ -740,6 +837,6 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
740
837
  setDetailsW((w) => grow
741
838
  ? Math.min(DETAILS_MAX_W, w + 16)
742
839
  : Math.max(DETAILS_MIN_W, w - 16));
743
- } }), (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 }) })] }));
840
+ } }), (0, jsx_runtime_1.jsx)(RecordPageMain, { 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 }) })] }));
744
841
  }
745
842
  RecordPage.displayName = "RecordPage";