@crisp-ui-kit/crisp 0.57.3 → 0.57.4

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 (169) hide show
  1. package/dist/assigneepicker.css +13 -0
  2. package/dist/assigneepicker.d.ts +7 -0
  3. package/dist/assigneepicker.layered.css +15 -0
  4. package/dist/button.css +1 -1
  5. package/dist/button.layered.css +1 -1
  6. package/dist/cjs/components/button/button.recipe.js +15 -10
  7. package/dist/cjs/components/datatable/datatable.js +6 -3
  8. package/dist/cjs/components/datatable/datatable.recipe.js +35 -2
  9. package/dist/cjs/components/menu/menu.js +48 -8
  10. package/dist/cjs/components/multiselect/multiselect.js +3 -0
  11. package/dist/cjs/components/multiselect/multiselect.recipe.js +18 -0
  12. package/dist/cjs/components/select/select.js +2 -2
  13. package/dist/cjs/components/select/select.recipe.js +19 -0
  14. package/dist/cjs/core/index.js +2 -1
  15. package/dist/cjs/core/place-floating.js +38 -0
  16. package/dist/cjs/index.js +8 -0
  17. package/dist/cjs/product/assigneepicker/assigneepicker.js +127 -0
  18. package/dist/cjs/product/assigneepicker/assigneepicker.recipe.js +36 -0
  19. package/dist/cjs/product/assigneepicker/index.js +7 -0
  20. package/dist/cjs/product/notesgallery/index.js +7 -0
  21. package/dist/cjs/product/notesgallery/notesgallery.js +80 -0
  22. package/dist/cjs/product/notesgallery/notesgallery.recipe.js +46 -0
  23. package/dist/cjs/product/objectpagemenu/index.js +17 -0
  24. package/dist/cjs/product/objectpagemenu/objectpagemenu.js +26 -0
  25. package/dist/cjs/product/objectpagemenu/objectpagemenu.recipe.js +30 -0
  26. package/dist/cjs/product/objectsettings/objectsettings.js +107 -14
  27. package/dist/cjs/product/recordpage/recordpage.js +64 -5
  28. package/dist/cjs/product/recordpage/recordpage.recipe.js +38 -0
  29. package/dist/cjs/product/recordpicker/index.js +7 -0
  30. package/dist/cjs/product/recordpicker/recordpicker.js +100 -0
  31. package/dist/cjs/product/recordpicker/recordpicker.recipe.js +36 -0
  32. package/dist/cjs/product/savedviews/index.js +2 -1
  33. package/dist/cjs/product/savedviews/savedviews.js +22 -0
  34. package/dist/cjs/product/savedviews/savedviews.recipe.js +47 -0
  35. package/dist/cjs/product/share/index.js +7 -0
  36. package/dist/cjs/product/share/share.js +179 -0
  37. package/dist/cjs/product/share/share.recipe.js +114 -0
  38. package/dist/cjs/product/shortcutssheet/index.js +17 -0
  39. package/dist/cjs/product/shortcutssheet/shortcutssheet.js +125 -0
  40. package/dist/cjs/product/shortcutssheet/shortcutssheet.recipe.js +50 -0
  41. package/dist/cjs/product/taskeditpopover/index.js +7 -0
  42. package/dist/cjs/product/taskeditpopover/taskeditpopover.js +159 -0
  43. package/dist/cjs/product/taskeditpopover/taskeditpopover.recipe.js +68 -0
  44. package/dist/cjs/product/workspaceswitchermenu/index.js +17 -0
  45. package/dist/cjs/product/workspaceswitchermenu/workspaceswitchermenu.js +38 -0
  46. package/dist/cjs/product/workspaceswitchermenu/workspaceswitchermenu.recipe.js +34 -0
  47. package/dist/cjs/tokens/palette.js +27 -0
  48. package/dist/cjs/tokens/semantic.js +20 -0
  49. package/dist/datatable.css +40 -7
  50. package/dist/datatable.layered.css +40 -7
  51. package/dist/esm/components/button/button.recipe.js +15 -10
  52. package/dist/esm/components/datatable/datatable.js +6 -3
  53. package/dist/esm/components/datatable/datatable.recipe.js +35 -2
  54. package/dist/esm/components/menu/menu.js +47 -7
  55. package/dist/esm/components/multiselect/multiselect.js +3 -0
  56. package/dist/esm/components/multiselect/multiselect.recipe.js +18 -0
  57. package/dist/esm/components/select/select.js +2 -2
  58. package/dist/esm/components/select/select.recipe.js +19 -0
  59. package/dist/esm/core/index.js +1 -1
  60. package/dist/esm/core/place-floating.js +37 -0
  61. package/dist/esm/index.js +8 -0
  62. package/dist/esm/product/assigneepicker/assigneepicker.js +91 -0
  63. package/dist/esm/product/assigneepicker/assigneepicker.recipe.js +33 -0
  64. package/dist/esm/product/assigneepicker/index.js +2 -0
  65. package/dist/esm/product/notesgallery/index.js +2 -0
  66. package/dist/esm/product/notesgallery/notesgallery.js +44 -0
  67. package/dist/esm/product/notesgallery/notesgallery.recipe.js +43 -0
  68. package/dist/esm/product/objectpagemenu/index.js +1 -0
  69. package/dist/esm/product/objectpagemenu/objectpagemenu.js +23 -0
  70. package/dist/esm/product/objectpagemenu/objectpagemenu.recipe.js +27 -0
  71. package/dist/esm/product/objectsettings/objectsettings.js +106 -13
  72. package/dist/esm/product/recordpage/recordpage.js +64 -5
  73. package/dist/esm/product/recordpage/recordpage.recipe.js +38 -0
  74. package/dist/esm/product/recordpicker/index.js +2 -0
  75. package/dist/esm/product/recordpicker/recordpicker.js +64 -0
  76. package/dist/esm/product/recordpicker/recordpicker.recipe.js +33 -0
  77. package/dist/esm/product/savedviews/index.js +1 -1
  78. package/dist/esm/product/savedviews/savedviews.js +22 -1
  79. package/dist/esm/product/savedviews/savedviews.recipe.js +47 -0
  80. package/dist/esm/product/share/index.js +2 -0
  81. package/dist/esm/product/share/share.js +143 -0
  82. package/dist/esm/product/share/share.recipe.js +111 -0
  83. package/dist/esm/product/shortcutssheet/index.js +1 -0
  84. package/dist/esm/product/shortcutssheet/shortcutssheet.js +88 -0
  85. package/dist/esm/product/shortcutssheet/shortcutssheet.recipe.js +47 -0
  86. package/dist/esm/product/taskeditpopover/index.js +2 -0
  87. package/dist/esm/product/taskeditpopover/taskeditpopover.js +123 -0
  88. package/dist/esm/product/taskeditpopover/taskeditpopover.recipe.js +65 -0
  89. package/dist/esm/product/workspaceswitchermenu/index.js +1 -0
  90. package/dist/esm/product/workspaceswitchermenu/workspaceswitchermenu.js +35 -0
  91. package/dist/esm/product/workspaceswitchermenu/workspaceswitchermenu.recipe.js +31 -0
  92. package/dist/esm/tokens/palette.js +27 -0
  93. package/dist/esm/tokens/semantic.js +20 -0
  94. package/dist/multiselect.css +18 -0
  95. package/dist/multiselect.layered.css +18 -0
  96. package/dist/native/tokens.d.ts +1 -1
  97. package/dist/native/tokens.js +56 -4
  98. package/dist/notesgallery.css +15 -0
  99. package/dist/notesgallery.d.ts +7 -0
  100. package/dist/notesgallery.layered.css +17 -0
  101. package/dist/objectpagemenu.css +3 -0
  102. package/dist/objectpagemenu.d.ts +7 -0
  103. package/dist/objectpagemenu.layered.css +5 -0
  104. package/dist/recordpage.css +36 -0
  105. package/dist/recordpage.layered.css +36 -0
  106. package/dist/recordpicker.css +13 -0
  107. package/dist/recordpicker.d.ts +7 -0
  108. package/dist/recordpicker.layered.css +15 -0
  109. package/dist/savedviews.css +47 -0
  110. package/dist/savedviews.layered.css +47 -0
  111. package/dist/select.css +19 -0
  112. package/dist/select.layered.css +19 -0
  113. package/dist/share.css +84 -0
  114. package/dist/share.d.ts +7 -0
  115. package/dist/share.layered.css +86 -0
  116. package/dist/shortcutssheet.css +24 -0
  117. package/dist/shortcutssheet.d.ts +7 -0
  118. package/dist/shortcutssheet.layered.css +26 -0
  119. package/dist/styles.css +387 -8
  120. package/dist/styles.layered.css +387 -8
  121. package/dist/taskeditpopover.css +36 -0
  122. package/dist/taskeditpopover.d.ts +7 -0
  123. package/dist/taskeditpopover.layered.css +38 -0
  124. package/dist/tokens.css +26 -0
  125. package/dist/tokens.json +56 -4
  126. package/dist/types/components/button/button.recipe.d.ts +2 -3
  127. package/dist/types/components/datatable/datatable.d.ts +8 -0
  128. package/dist/types/components/menu/menu.d.ts +50 -7
  129. package/dist/types/components/multiselect/multiselect.d.ts +9 -0
  130. package/dist/types/components/select/select.d.ts +10 -0
  131. package/dist/types/core/index.d.ts +1 -1
  132. package/dist/types/core/place-floating.d.ts +37 -0
  133. package/dist/types/index.d.ts +8 -0
  134. package/dist/types/product/assigneepicker/assigneepicker.d.ts +36 -0
  135. package/dist/types/product/assigneepicker/assigneepicker.recipe.d.ts +3 -0
  136. package/dist/types/product/assigneepicker/index.d.ts +2 -0
  137. package/dist/types/product/notesgallery/index.d.ts +2 -0
  138. package/dist/types/product/notesgallery/notesgallery.d.ts +54 -0
  139. package/dist/types/product/notesgallery/notesgallery.recipe.d.ts +3 -0
  140. package/dist/types/product/objectpagemenu/index.d.ts +1 -0
  141. package/dist/types/product/objectpagemenu/objectpagemenu.d.ts +40 -0
  142. package/dist/types/product/objectpagemenu/objectpagemenu.recipe.d.ts +17 -0
  143. package/dist/types/product/objectsettings/objectsettings.d.ts +71 -15
  144. package/dist/types/product/recordpage/index.d.ts +1 -1
  145. package/dist/types/product/recordpage/recordpage.d.ts +96 -1
  146. package/dist/types/product/recordpicker/index.d.ts +2 -0
  147. package/dist/types/product/recordpicker/recordpicker.d.ts +38 -0
  148. package/dist/types/product/recordpicker/recordpicker.recipe.d.ts +3 -0
  149. package/dist/types/product/savedviews/index.d.ts +1 -1
  150. package/dist/types/product/savedviews/savedviews.d.ts +36 -0
  151. package/dist/types/product/share/index.d.ts +2 -0
  152. package/dist/types/product/share/share.d.ts +85 -0
  153. package/dist/types/product/share/share.recipe.d.ts +3 -0
  154. package/dist/types/product/shortcutssheet/index.d.ts +1 -0
  155. package/dist/types/product/shortcutssheet/shortcutssheet.d.ts +49 -0
  156. package/dist/types/product/shortcutssheet/shortcutssheet.recipe.d.ts +3 -0
  157. package/dist/types/product/taskeditpopover/index.d.ts +2 -0
  158. package/dist/types/product/taskeditpopover/taskeditpopover.d.ts +67 -0
  159. package/dist/types/product/taskeditpopover/taskeditpopover.recipe.d.ts +3 -0
  160. package/dist/types/product/workspaceswitchermenu/index.d.ts +1 -0
  161. package/dist/types/product/workspaceswitchermenu/workspaceswitchermenu.d.ts +54 -0
  162. package/dist/types/product/workspaceswitchermenu/workspaceswitchermenu.recipe.d.ts +19 -0
  163. package/dist/types/tokens/contract.d.ts +13 -0
  164. package/dist/types/tokens/palette.d.ts +52 -0
  165. package/dist/types/tokens/semantic.d.ts +20 -0
  166. package/dist/workspaceswitchermenu.css +4 -0
  167. package/dist/workspaceswitchermenu.d.ts +7 -0
  168. package/dist/workspaceswitchermenu.layered.css +6 -0
  169. package/package.json +41 -1
@@ -44,6 +44,7 @@ const avatar_1 = require("../../components/avatar");
44
44
  const button_1 = require("../../components/button");
45
45
  const checkbox_1 = require("../../components/checkbox");
46
46
  const drawer_1 = require("../../components/drawer");
47
+ const kbd_1 = require("../../components/kbd");
47
48
  const menu_1 = require("../../components/menu");
48
49
  const select_1 = require("../../components/select");
49
50
  const spinner_1 = require("../../components/spinner");
@@ -118,6 +119,12 @@ exports.recordPageLabels = {
118
119
  upgradeToViewCalls: "Upgrade to view calls",
119
120
  callsUpgradeHint: "No call recordings yet! Upgrade to Pro to start recording calls.",
120
121
  upgrade: "Upgrade",
122
+ selectWorkflowTitle: "Select workflow",
123
+ closeWorkflowPopover: "Close",
124
+ searchWorkflowsPlaceholder: "Search workflows...",
125
+ noWorkflows: "No workflows",
126
+ createNewWorkflow: "Create new workflow",
127
+ navigate: "Navigate",
121
128
  highlights: "Highlights",
122
129
  recordDetails: "Record Details",
123
130
  searchFields: "Search fields",
@@ -515,7 +522,7 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, r
515
522
  commit(record.id, col.key, e.currentTarget.value);
516
523
  } }), isPending && ((0, jsx_runtime_1.jsx)(spinner_1.Spinner, { size: 14, className: "crisp-recordpage-edit-pending" })), fieldError && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-edit-error", children: fieldError }))] })] }, col.key));
517
524
  }
518
- return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-field", children: [label, (0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-field-value", "data-editable": canEdit ? "" : undefined, children: [canEdit ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-edit-trigger", onClick: () => openEditing(col.key), children: (0, jsx_runtime_1.jsx)(FieldValue, { col: col, row: record, labels: t }) })) : ((0, jsx_runtime_1.jsx)(FieldValue, { col: col, row: record, labels: t })), fieldError && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-edit-error", children: fieldError }))] })] }, col.key));
525
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-field", children: [label, (0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-field-value", "data-editable": canEdit ? "" : undefined, children: [canEdit && col.type === "url" ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FieldValue, { col: col, row: record, labels: t }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-edit-affordance", "aria-label": `Edit ${col.label}`, onClick: () => openEditing(col.key), children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 16, strokeWidth: 1.75 }) })] })) : canEdit ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-edit-trigger", onClick: () => openEditing(col.key), children: (0, jsx_runtime_1.jsx)(FieldValue, { col: col, row: record, labels: t }) })) : ((0, jsx_runtime_1.jsx)(FieldValue, { col: col, row: record, labels: t })), fieldError && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-edit-error", children: fieldError }))] })] }, col.key));
519
526
  })] }, g.title != null ? String(g.title) : `section-${i}`))), canRevealFields && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-viewall crisp-recordpage-viewall--section", onClick: () => {
520
527
  // Revealing all fields also opens the (focused) field
521
528
  // search; collapsing closes it.
@@ -555,6 +562,46 @@ function RecordPageMain({ className, children, ...rest }) {
555
562
  return ((0, jsx_runtime_1.jsx)("main", { className: (0, core_1.cx)("crisp-recordpage-main", className), ...rest, children: children }));
556
563
  }
557
564
  RecordPageMain.displayName = "RecordPageMain";
565
+ /**
566
+ * The "Run workflow" quick action's own popover (#620, P-018) — measured
567
+ * live on `app.attio.com`'s own record page: a centered, top-anchored
568
+ * overlay sharing the exact same frosted-bezel shell `product/command`'s
569
+ * own Cmd-K palette already uses (`elevation.modal`, `bgOverlayFrost` 60% +
570
+ * `blur(15px)`, radius `2xl`/`xl` outer/inner) — duplicated into this
571
+ * recipe rather than imported, the same "own copy per product surface"
572
+ * choice already made elsewhere in this codebase (`product/command` is
573
+ * outside this lane's own `product/recordpage` ownership).
574
+ *
575
+ * Chrome only, like the quick-action row's own Compose email/Add to list
576
+ * buttons above: crisp has no workflow data model to search or list yet, so
577
+ * the search box is real and typable but filters nothing, and the "No
578
+ * workflows" empty state always renders. The measured popover's own
579
+ * illustration is a bespoke Attio graphic (Golden Rule 4: Lucide only) —
580
+ * reuses crisp's own established "illustrated empty state" dotted-grid tile
581
+ * (`.crisp-recordpage-illustrated-icon`, already shipped for Files/Deals)
582
+ * with a `Workflow` glyph instead.
583
+ */
584
+ function WorkflowPopover({ open, onClose, labels, }) {
585
+ React.useEffect(() => {
586
+ if (!open)
587
+ return;
588
+ const onKey = (e) => {
589
+ if (e.key === "Escape")
590
+ onClose();
591
+ };
592
+ document.addEventListener("keydown", onKey);
593
+ return () => document.removeEventListener("keydown", onKey);
594
+ }, [open, onClose]);
595
+ if (!open)
596
+ return null;
597
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-workflow-backdrop" }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-workflow-positioner", onClick: (e) => {
598
+ if (e.target === e.currentTarget)
599
+ onClose();
600
+ }, children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-workflow-content", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-workflow-card", role: "dialog", "aria-modal": "true", "aria-label": labels.selectWorkflowTitle, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-workflow-header", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-workflow-title", children: labels.selectWorkflowTitle }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-workflow-close", "aria-label": labels.closeWorkflowPopover, onClick: onClose, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 14, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-workflow-search", children: (0, jsx_runtime_1.jsx)("input", {
601
+ // biome-ignore lint/a11y/noAutofocus: focusing the just-opened popover's search is expected
602
+ autoFocus: true, type: "text", role: "combobox", "aria-expanded": "true", "aria-label": labels.selectWorkflowTitle, placeholder: labels.searchWorkflowsPlaceholder, className: "crisp-recordpage-workflow-input" }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-workflow-sep" }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-workflow-empty", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-illustrated-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Workflow, { size: 40, strokeWidth: 1.25 }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-illustrated-desc", children: labels.noWorkflows }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-workflow-create", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 1.75 }), labels.createNewWorkflow] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-workflow-footer", children: (0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-workflow-footer-nav", children: [(0, jsx_runtime_1.jsx)(kbd_1.Kbd, { children: "\u2191" }), (0, jsx_runtime_1.jsx)(kbd_1.Kbd, { children: "\u2193" }), labels.navigate] }) })] }) }) })] }));
603
+ }
604
+ WorkflowPopover.displayName = "WorkflowPopover";
558
605
  /**
559
606
  * The full-page company record view — the page that opens when you click into a
560
607
  * record (as opposed to the peek [RecordPanel]). A top breadcrumb bar with
@@ -563,9 +610,15 @@ RecordPageMain.displayName = "RecordPageMain";
563
610
  * Emails sections (Notes & Tasks are live — add and check things off). Drop it
564
611
  * into the app's main content area.
565
612
  */
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 }) {
613
+ 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, avatarShape = "rounded", onEditRecord, onDelete, actions, showBreadcrumb = true, showShare = true, showAskAttio = true, showComments = true, ...rest }) {
567
614
  const t = useRecordPageLabels(labels);
568
615
  const [favorite, setFavorite] = React.useState(false);
616
+ // #620: the "Run workflow" quick action's own popover -- only the
617
+ // BUILT-IN default quick-action list opens it (below); a caller supplying
618
+ // its own `quickActions` owns every button's behaviour itself, the same
619
+ // "caller's own list, not a merge" contract `tabs`/`highlights` already
620
+ // make.
621
+ const [workflowPopoverOpen, setWorkflowPopoverOpen] = React.useState(false);
569
622
  // Notes/Tasks are controlled when the caller supplies `notes`/`tasks` (even
570
623
  // `[]`) -- otherwise RecordPage keeps its own self-contained state, as
571
624
  // before (#379). "Controlled" here means the array prop alone decides the
@@ -682,7 +735,13 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
682
735
  // choice `tabs` (#379) and `highlights` (#528) already make.
683
736
  const defaultQuickActions = [
684
737
  { label: t.logANote, icon: lucide_react_1.FileText },
685
- { label: t.runWorkflow, icon: lucide_react_1.Workflow },
738
+ // #620: only the built-in default wires this to crisp's own popover --
739
+ // see `workflowPopoverOpen`'s own comment above.
740
+ {
741
+ label: t.runWorkflow,
742
+ icon: lucide_react_1.Workflow,
743
+ onSelect: () => setWorkflowPopoverOpen(true),
744
+ },
686
745
  { label: t.createATask, icon: lucide_react_1.SquareCheck },
687
746
  ];
688
747
  const quickActions = quickActionsProp ?? defaultQuickActions;
@@ -825,7 +884,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
825
884
  const effectivePanel = tabsProp
826
885
  ? (active) => tabsProp.find((tb) => tb.id === active)?.render()
827
886
  : builtinPanel;
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) => {
887
+ 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 }))] })) : (showBreadcrumb && ((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: [showShare && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", onClick: onShare, children: t.share })), showComments && ((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 }) })), showAskAttio && ((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 }), actions && actions.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), actions.map((a) => ((0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(a.icon, { size: 15, strokeWidth: 1.75 }), onSelect: a.onSelect, danger: a.danger, children: a.label }, a.label)))] })), (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 }), onSelect: onDelete, 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: avatarShape, 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, onClick: onEditRecord, 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) => {
829
888
  if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
830
889
  return;
831
890
  // The pointer drag learned its direction in #212; this did not.
@@ -837,6 +896,6 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
837
896
  setDetailsW((w) => grow
838
897
  ? Math.min(DETAILS_MAX_W, w + 16)
839
898
  : Math.max(DETAILS_MIN_W, w - 16));
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 }) })] }));
899
+ } }), (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 }) }), (0, jsx_runtime_1.jsx)(WorkflowPopover, { open: workflowPopoverOpen, onClose: () => setWorkflowPopoverOpen(false), labels: t })] }));
841
900
  }
842
901
  RecordPage.displayName = "RecordPage";
@@ -127,6 +127,19 @@ const config = (0, core_1.defineRecipe)({
127
127
  the component's own comment) -- NOT \`display: contents\`, which
128
128
  drops a button's accessible semantics in some engines. */
129
129
  & .crisp-recordpage-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: ${tokens_1.contract.space["1"]}; margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
130
+ /* #990: measured live on app.attio.com's URL/domain attribute (hover the
131
+ row) -- the link itself never carries the edit affordance, a
132
+ separate 20px button trails it, mounting only on hover: 16px icon,
133
+ rgba(0,0,0,0.55) (crisp's own color-mix(fgPrimary 55%) -- the exact
134
+ formula .crisp-datatable-entity-action's identical muted icon
135
+ already uses), 6px radius (radius.sm). Reveal is opacity-based,
136
+ not the mount/unmount Attio's own DOM does, so a keyboard user
137
+ tabbing to it (:focus-visible) doesn't need the row hovered first --
138
+ same mechanism DataTable's own row actions (#601) already use. */
139
+ & .crisp-recordpage-edit-affordance { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 20px; height: 20px; margin: 0; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.sm}; background: none; font-family: inherit; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 55%, transparent); cursor: pointer; opacity: 0; transition: opacity .12s, background-color .12s, color .12s; }
140
+ & .crisp-recordpage-field:hover .crisp-recordpage-edit-affordance,
141
+ & .crisp-recordpage-edit-affordance:focus-visible { opacity: 1; }
142
+ & .crisp-recordpage-edit-affordance:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); color: ${tokens_1.contract.fgPrimary}; }
130
143
  & .crisp-recordpage-empty { color: ${tokens_1.contract.fgMuted}; }
131
144
 
132
145
  /* #431: measured live on app.attio.com's record page Details column --
@@ -264,6 +277,31 @@ const config = (0, core_1.defineRecipe)({
264
277
  & .crisp-recordstable-tag[data-tone="purple"] { background: color-mix(in srgb, ${tokens_1.contract.bgPurple} 16%, transparent); color: color-mix(in srgb, ${tokens_1.contract.bgPurple} 80%, ${tokens_1.contract.fgPrimary}); }
265
278
  & .crisp-recordstable-tag[data-tone="cyan"] { background: color-mix(in srgb, ${tokens_1.contract.bgCyan} 18%, transparent); color: color-mix(in srgb, ${tokens_1.contract.bgCyan} 82%, ${tokens_1.contract.fgPrimary}); }
266
279
  & .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, ${tokens_1.contract.bgOrange} 16%, transparent); color: color-mix(in srgb, ${tokens_1.contract.bgOrange} 82%, ${tokens_1.contract.fgPrimary}); }
280
+
281
+ /* #620: the "Run workflow" quick action's own popover -- measured live:
282
+ a centered, top-anchored overlay sharing product/command's own
283
+ Cmd-K-palette shell exactly (elevation.modal, bgOverlayFrost 60% +
284
+ blur(15px), radius 2xl/xl outer/inner) -- duplicated here rather than
285
+ imported, the same "own copy per product surface" choice already
286
+ made elsewhere in this codebase (product/command sits outside this
287
+ lane's own product/recordpage ownership). */
288
+ & .crisp-recordpage-workflow-backdrop { position: fixed; inset: 0; z-index: 60; background: transparent; }
289
+ & .crisp-recordpage-workflow-positioner { position: fixed; inset: 0; z-index: 61; display: flex; align-items: flex-start; justify-content: center; padding: 15vh ${tokens_1.contract.space["4"]} ${tokens_1.contract.space["4"]}; }
290
+ & .crisp-recordpage-workflow-content { position: relative; display: flex; flex-direction: column; box-sizing: border-box; width: 90vw; max-width: 808px; padding: ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius["2xl"]}; background: color-mix(in srgb, ${tokens_1.contract.bgOverlayFrost} 60%, transparent); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); box-shadow: ${tokens_1.elevation.modal}; opacity: 1; transform: scale(1); transition: opacity .2s ease, transform .2s ease; @starting-style { opacity: 0; transform: scale(0.97); } }
291
+ & .crisp-recordpage-workflow-card { display: flex; flex-direction: column; box-sizing: border-box; border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgSurface}; overflow: hidden; }
292
+ & .crisp-recordpage-workflow-header { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 52px; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["2"]} 0 ${tokens_1.contract.space["4"]}; }
293
+ & .crisp-recordpage-workflow-title { flex: 1; 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}; letter-spacing: -0.07px; color: ${tokens_1.contract.fgPrimary}; }
294
+ & .crisp-recordpage-workflow-close { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 28px; height: 28px; margin: 0; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 55%, transparent); font-family: inherit; cursor: pointer; transition: background-color .12s, color .12s; }
295
+ & .crisp-recordpage-workflow-close:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); color: ${tokens_1.contract.fgPrimary}; }
296
+ & .crisp-recordpage-workflow-search { display: flex; align-items: center; min-height: 52px; padding: ${tokens_1.contract.space["4"]}; }
297
+ & .crisp-recordpage-workflow-input { flex: 1; min-width: 0; border: none; outline: none; background: transparent; font-family: inherit; font-size: ${tokens_1.contract.text.xl}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
298
+ & .crisp-recordpage-workflow-input::placeholder { color: ${tokens_1.contract.fgMuted}; }
299
+ & .crisp-recordpage-workflow-sep { height: 1px; flex-shrink: 0; background: ${tokens_1.contract.borderSubtle}; }
300
+ & .crisp-recordpage-workflow-empty { display: flex; flex-direction: column; align-items: center; gap: ${tokens_1.contract.space["2"]}; padding: ${tokens_1.contract.space["6"]} ${tokens_1.contract.space["3"]}; text-align: center; }
301
+ & .crisp-recordpage-workflow-create { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: 32px; padding: 0 ${tokens_1.contract.space["3"]}; margin-top: ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field}; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; cursor: pointer; transition: background-color .12s; }
302
+ & .crisp-recordpage-workflow-create:hover { background: ${tokens_1.contract.bgRaised}; }
303
+ & .crisp-recordpage-workflow-footer { display: flex; align-items: center; height: 44px; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["2.5"]}; border-top: 1px solid ${tokens_1.contract.borderSubtle}; }
304
+ & .crisp-recordpage-workflow-footer-nav { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; 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); }
267
305
  `,
268
306
  variants: {},
269
307
  defaultVariants: {},
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.recordpickerRecipe = exports.RecordPicker = void 0;
4
+ var recordpicker_1 = require("./recordpicker");
5
+ Object.defineProperty(exports, "RecordPicker", { enumerable: true, get: function () { return recordpicker_1.RecordPicker; } });
6
+ var recordpicker_recipe_1 = require("./recordpicker.recipe");
7
+ Object.defineProperty(exports, "recordpickerRecipe", { enumerable: true, get: function () { return recordpicker_recipe_1.recordpickerRecipe; } });
@@ -0,0 +1,100 @@
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.RecordPicker = RecordPicker;
37
+ const jsx_runtime_1 = require("react/jsx-runtime");
38
+ const lucide_react_1 = require("lucide-react");
39
+ const React = __importStar(require("react"));
40
+ const select_1 = require("../../components/select");
41
+ const spinner_1 = require("../../components/spinner");
42
+ const core_1 = require("../../core");
43
+ const recordpicker_recipe_1 = require("./recordpicker.recipe");
44
+ /**
45
+ * The record-search picker behind a task's "Add record" chip -- measured
46
+ * live on app.attio.com's Tasks page ("Edit task" -> "Add record"): a
47
+ * "Search..." row, then a FLAT list mixed across every object type (a
48
+ * person result sat first, ahead of several companies, with no section
49
+ * headers -- unlike the mention picker's own grouped Users/Records shape,
50
+ * crisp#646). Attio's own live search took a moment to resolve, showing a
51
+ * centred spinner + "Loading..." row meanwhile; not independently
52
+ * re-measured against a second empty-results case, so `emptyLabel`'s
53
+ * default copy ("No records") is inferred by symmetry with
54
+ * `AssigneePicker`'s own measured "No users", not itself pixel-measured.
55
+ */
56
+ function RecordPicker({ records, loading = false, onSelect, query: queryProp, onQueryChange, searchLabel: searchLabelProp, loadingLabel: loadingLabelProp, emptyLabel: emptyLabelProp, className, ...rest }) {
57
+ const searchLabel = (0, core_1.useCrispMessage)(searchLabelProp, "Search...");
58
+ const loadingLabel = (0, core_1.useCrispMessage)(loadingLabelProp, "Loading...");
59
+ // crisp/#471: `emptyLabel` is typed `React.ReactNode`, so it resolves by
60
+ // hand rather than through `useCrispMessage`, which is string-only --
61
+ // same reasoning as `Inbox`'s own `emptyTitle`/`emptySubtitle`.
62
+ const crispMessages = (0, core_1.useCrispMessages)();
63
+ const emptyLabel = emptyLabelProp ?? crispMessages["No records"] ?? "No records";
64
+ const [internalQuery, setInternalQuery] = React.useState("");
65
+ const query = queryProp ?? internalQuery;
66
+ const setQuery = (q) => {
67
+ if (queryProp === undefined)
68
+ setInternalQuery(q);
69
+ onQueryChange?.(q);
70
+ };
71
+ const [highlight, setHighlight] = React.useState(0);
72
+ const autoId = React.useId();
73
+ const listboxId = `${autoId}-listbox`;
74
+ const optionId = (i) => `${autoId}-opt-${i}`;
75
+ const select = (r) => {
76
+ onSelect?.(r);
77
+ };
78
+ const { onKeyDown } = (0, select_1.useListboxKeyboard)({
79
+ enabledIndexes: records.map((_, i) => i),
80
+ highlight,
81
+ setHighlight,
82
+ commit: () => {
83
+ const r = records[highlight];
84
+ if (r)
85
+ select(r);
86
+ },
87
+ close: () => { },
88
+ dismiss: () => { },
89
+ });
90
+ const activeId = !loading && highlight >= 0 && highlight < records.length
91
+ ? optionId(highlight)
92
+ : undefined;
93
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpicker_recipe_1.recordpickerRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpicker-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 16, strokeWidth: 1.75 }), (0, jsx_runtime_1.jsx)("input", { type: "text", className: "crisp-recordpicker-search-input", placeholder: searchLabel, value: query, onChange: (e) => {
94
+ setQuery(e.target.value);
95
+ setHighlight(0);
96
+ }, onKeyDown: onKeyDown, role: "combobox", "aria-expanded": "true", "aria-controls": listboxId, "aria-activedescendant": activeId,
97
+ // biome-ignore lint/a11y/noAutofocus: focus the search field the moment its enclosing popover opens
98
+ autoFocus: true })] }), loading ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpicker-loading", children: [(0, jsx_runtime_1.jsx)(spinner_1.Spinner, { size: 16 }), loadingLabel] })) : records.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpicker-empty", children: emptyLabel })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpicker-list", role: "listbox", id: listboxId, children: records.map((r, i) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", id: optionId(i), role: "option", tabIndex: -1, "aria-selected": i === highlight, "data-highlighted": i === highlight ? "" : undefined, className: "crisp-recordpicker-option", onMouseEnter: () => setHighlight(i), onClick: () => select(r), children: [r.icon, r.name] }, r.id))) }))] }));
99
+ }
100
+ RecordPicker.displayName = "RecordPicker";
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.recordpickerRecipe = void 0;
4
+ const core_1 = require("../../core");
5
+ const tokens_1 = require("../../tokens");
6
+ // The record picker behind a task's "Add record" chip -- measured live on
7
+ // app.attio.com's Tasks page ("Edit task" -> "Add record" -> its own
8
+ // sub-popover, same measured 350px width as `AssigneePicker`'s): a
9
+ // borderless "Search..." row, then a flat list mixed across every object
10
+ // type (not grouped into sections -- that's the *mention* picker's own
11
+ // shape, crisp#646, a different, still-ungrouped-by-default surface here),
12
+ // each row a consumer-supplied type icon + the record's name. A "Loading..."
13
+ // row appears while results are in flight (the same measured centred
14
+ // Spinner + text DataTable's own #826 loading state already uses).
15
+ const config = (0, core_1.defineRecipe)({
16
+ name: "recordpicker",
17
+ base: `display: flex; flex-direction: column; box-sizing: border-box; width: 350px; font-family: ${tokens_1.contract.font.sans};
18
+
19
+ & .crisp-recordpicker-search { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 36px; padding: 0 ${tokens_1.contract.space["3"]}; color: ${tokens_1.contract.fgMuted}; }
20
+ & .crisp-recordpicker-search svg { flex-shrink: 0; }
21
+ & .crisp-recordpicker-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}; line-height: 20px; color: ${tokens_1.contract.fgPrimary}; }
22
+ & .crisp-recordpicker-search-input::placeholder { color: ${tokens_1.contract.fgMuted}; }
23
+
24
+ & .crisp-recordpicker-loading { display: flex; align-items: center; justify-content: center; gap: 10px; padding: ${tokens_1.contract.space["8"]} ${tokens_1.contract.space["3"]}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; line-height: 20px; }
25
+ & .crisp-recordpicker-empty { padding: ${tokens_1.contract.space["4"]} ${tokens_1.contract.space["3"]}; text-align: center; 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); }
26
+
27
+ & .crisp-recordpicker-list { display: flex; flex-direction: column; margin: 0; padding: ${tokens_1.contract.space["1"]}; list-style: none; max-height: 280px; overflow-y: auto; }
28
+ & .crisp-recordpicker-option { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; width: 100%; box-sizing: border-box; height: 32px; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; text-align: start; cursor: pointer; }
29
+ & .crisp-recordpicker-option svg { flex-shrink: 0; color: ${tokens_1.contract.fgMuted}; }
30
+ & .crisp-recordpicker-option:hover, & .crisp-recordpicker-option[data-highlighted] { background: ${tokens_1.contract.bgRaised}; }`,
31
+ variants: {},
32
+ defaultVariants: {},
33
+ compoundVariants: [],
34
+ });
35
+ exports.recordpickerRecipe = (0, core_1.resolveRecipe)(config);
36
+ exports.default = config;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.savedviewsRecipe = exports.SavedViews = void 0;
3
+ exports.savedviewsRecipe = exports.SavedViewsSaveBar = exports.SavedViews = void 0;
4
4
  var savedviews_1 = require("./savedviews");
5
5
  Object.defineProperty(exports, "SavedViews", { enumerable: true, get: function () { return savedviews_1.SavedViews; } });
6
+ Object.defineProperty(exports, "SavedViewsSaveBar", { enumerable: true, get: function () { return savedviews_1.SavedViewsSaveBar; } });
6
7
  var savedviews_recipe_1 = require("./savedviews.recipe");
7
8
  Object.defineProperty(exports, "savedviewsRecipe", { enumerable: true, get: function () { return savedviews_recipe_1.savedviewsRecipe; } });
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.SavedViews = SavedViews;
37
+ exports.SavedViewsSaveBar = SavedViewsSaveBar;
37
38
  const jsx_runtime_1 = require("react/jsx-runtime");
38
39
  const lucide_react_1 = require("lucide-react");
39
40
  const React = __importStar(require("react"));
@@ -236,3 +237,24 @@ function SavedViews({ label, icon, views, activeId, onSelect, onCreate, onRename
236
237
  }, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-savedviews-row-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-savedviews-row-label", children: createLabel })] })] }) }))] }));
237
238
  }
238
239
  SavedViews.displayName = "SavedViews";
240
+ /**
241
+ * The "unsaved changes" bar for a currently loaded saved view — Attio's own
242
+ * "Discard changes" + a split "Save for everyone ▾" button, measured live
243
+ * (app.attio.com, a saved Companies view with its sort changed). Not a part
244
+ * of `SavedViews`' own trigger/panel: Attio renders this in the page
245
+ * toolbar's own trailing slot, replacing whatever sits there at rest
246
+ * (Import/Export, "+ New …") — the same slot `TableToolbar`'s own
247
+ * `children` prop already documents ("Right-aligned actions after the
248
+ * count"). A consumer swaps this in for that slot's usual content once its
249
+ * own dirty check (live filters/sort/columns vs. the loaded view's
250
+ * snapshot) is true, and swaps it back out once it's false — this
251
+ * component itself carries no dirty state or visibility toggle.
252
+ */
253
+ function SavedViewsSaveBar({ onSave, onDiscard, onSaveAsNew, discardLabel: discardLabelProp, saveLabel: saveLabelProp, saveAsNewLabel: saveAsNewLabelProp, saveOptionsLabel: saveOptionsLabelProp, className, ...rest }) {
254
+ const discardLabel = (0, core_1.useCrispMessage)(discardLabelProp, "Discard changes");
255
+ const saveLabel = (0, core_1.useCrispMessage)(saveLabelProp, "Save for everyone");
256
+ const saveAsNewLabel = (0, core_1.useCrispMessage)(saveAsNewLabelProp, "Save as new view");
257
+ const saveOptionsLabel = (0, core_1.useCrispMessage)(saveOptionsLabelProp, "More save options");
258
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, core_1.cx)("crisp-savedviews-savebar", className), ...rest, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-savedviews-savebar-discard", onClick: onDiscard, children: discardLabel }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-savedviews-savebar-save-group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-savedviews-savebar-save", onClick: onSave, children: saveLabel }), onSaveAsNew && ((0, jsx_runtime_1.jsx)(menu_1.Menu, { align: "end", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-savedviews-savebar-save-chevron", "aria-label": saveOptionsLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 16, strokeWidth: 1.75 }) }), children: (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { onSelect: onSaveAsNew, children: saveAsNewLabel }) }))] })] }));
259
+ }
260
+ SavedViewsSaveBar.displayName = "SavedViewsSaveBar";
@@ -123,6 +123,53 @@ const config = (0, core_1.defineRecipe)({
123
123
  font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium};
124
124
  color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 50%, transparent);
125
125
  }
126
+
127
+ /* crisp#568: the "Discard changes" / "Save for everyone ▾" bar a
128
+ consumer swaps into its own toolbar's trailing slot (TableToolbar's
129
+ own children prop already documents "right-aligned actions after the
130
+ count") while the loaded view is dirty -- measured live on
131
+ app.attio.com replacing that exact slot's usual Import/Export + New
132
+ button. Not rendered inside SavedViews' own trigger/panel, which
133
+ stays untouched; this is its own export, SavedViewsSaveBar. */
134
+ .crisp-savedviews-savebar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; }
135
+ /* Rest-state color is a 55% color-mix of fgPrimary -- measured
136
+ identical to recordpanel's own ".crisp-recordpanel-section-action"
137
+ (its own comment: "measured 10px/400, a lighter mix..." -- font size
138
+ there was the SAME outer-vs-inner-div miss #688 corrected; the 55%
139
+ mix itself checks out independently here). Hover repeats crisp's own
140
+ already-measured Button ghost intent exactly (bgRaised + fgPrimary),
141
+ confirmed live (hover bg rgba(0,0,0,.04) + ink text matches bgRaised
142
+ + fgPrimary bit for bit) -- reused, not re-derived. */
143
+ .crisp-savedviews-savebar-discard {
144
+ box-sizing: border-box; display: inline-flex; align-items: center; height: 28px;
145
+ margin: 0; padding-inline: ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md};
146
+ background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium};
147
+ color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 55%, transparent); cursor: pointer;
148
+ transition: background-color .12s ease, color .12s ease;
149
+ }
150
+ .crisp-savedviews-savebar-discard:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
151
+ /* the split "Save for everyone ▾" pill -- two adjacent buttons sharing
152
+ one visual pill (measured: label half rounds only its outer/left
153
+ corners, the chevron half only its outer/right corners, seamless
154
+ between). Fill is crisp's OWN measured bgBrandContrast, not Attio's
155
+ own literal button blue -- the owner's directive is Attio structure/
156
+ sizing, seed-identity color (crisp direction doc). Hover/active reuse
157
+ Button's own already-measured primary-intent brightness filter
158
+ (crisp#910) rather than Attio's own literal darker fill, for the
159
+ same reason. */
160
+ .crisp-savedviews-savebar-save-group { display: flex; }
161
+ .crisp-savedviews-savebar-save, .crisp-savedviews-savebar-save-chevron {
162
+ box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
163
+ height: 28px; margin: 0; border: none; background: ${tokens_1.contract.bgBrandContrast}; color: ${tokens_1.contract.fgOnBrand};
164
+ cursor: pointer; transition: filter .2s;
165
+ }
166
+ .crisp-savedviews-savebar-save:hover, .crisp-savedviews-savebar-save-chevron:hover { filter: brightness(0.96); }
167
+ .crisp-savedviews-savebar-save:active, .crisp-savedviews-savebar-save-chevron:active { filter: brightness(0.92); }
168
+ .crisp-savedviews-savebar-save {
169
+ padding-inline: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["1.5"]}; border-radius: ${tokens_1.contract.radius.md} 0 0 ${tokens_1.contract.radius.md};
170
+ font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium};
171
+ }
172
+ .crisp-savedviews-savebar-save-chevron { width: 28px; padding: 0; border-radius: 0 ${tokens_1.contract.radius.md} ${tokens_1.contract.radius.md} 0; }
126
173
  `,
127
174
  variants: {},
128
175
  defaultVariants: {},
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shareRecipe = exports.SharePopover = void 0;
4
+ var share_1 = require("./share");
5
+ Object.defineProperty(exports, "SharePopover", { enumerable: true, get: function () { return share_1.SharePopover; } });
6
+ var share_recipe_1 = require("./share.recipe");
7
+ Object.defineProperty(exports, "shareRecipe", { enumerable: true, get: function () { return share_recipe_1.shareRecipe; } });