@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.
- package/dist/assigneepicker.css +13 -0
- package/dist/assigneepicker.d.ts +7 -0
- package/dist/assigneepicker.layered.css +15 -0
- package/dist/button.css +1 -1
- package/dist/button.layered.css +1 -1
- package/dist/cjs/components/button/button.recipe.js +15 -10
- package/dist/cjs/components/datatable/datatable.js +6 -3
- package/dist/cjs/components/datatable/datatable.recipe.js +35 -2
- package/dist/cjs/components/menu/menu.js +48 -8
- package/dist/cjs/components/multiselect/multiselect.js +3 -0
- package/dist/cjs/components/multiselect/multiselect.recipe.js +18 -0
- package/dist/cjs/components/select/select.js +2 -2
- package/dist/cjs/components/select/select.recipe.js +19 -0
- package/dist/cjs/core/index.js +2 -1
- package/dist/cjs/core/place-floating.js +38 -0
- package/dist/cjs/index.js +8 -0
- package/dist/cjs/product/assigneepicker/assigneepicker.js +127 -0
- package/dist/cjs/product/assigneepicker/assigneepicker.recipe.js +36 -0
- package/dist/cjs/product/assigneepicker/index.js +7 -0
- package/dist/cjs/product/notesgallery/index.js +7 -0
- package/dist/cjs/product/notesgallery/notesgallery.js +80 -0
- package/dist/cjs/product/notesgallery/notesgallery.recipe.js +46 -0
- package/dist/cjs/product/objectpagemenu/index.js +17 -0
- package/dist/cjs/product/objectpagemenu/objectpagemenu.js +26 -0
- package/dist/cjs/product/objectpagemenu/objectpagemenu.recipe.js +30 -0
- package/dist/cjs/product/objectsettings/objectsettings.js +107 -14
- package/dist/cjs/product/recordpage/recordpage.js +64 -5
- package/dist/cjs/product/recordpage/recordpage.recipe.js +38 -0
- package/dist/cjs/product/recordpicker/index.js +7 -0
- package/dist/cjs/product/recordpicker/recordpicker.js +100 -0
- package/dist/cjs/product/recordpicker/recordpicker.recipe.js +36 -0
- package/dist/cjs/product/savedviews/index.js +2 -1
- package/dist/cjs/product/savedviews/savedviews.js +22 -0
- package/dist/cjs/product/savedviews/savedviews.recipe.js +47 -0
- package/dist/cjs/product/share/index.js +7 -0
- package/dist/cjs/product/share/share.js +179 -0
- package/dist/cjs/product/share/share.recipe.js +114 -0
- package/dist/cjs/product/shortcutssheet/index.js +17 -0
- package/dist/cjs/product/shortcutssheet/shortcutssheet.js +125 -0
- package/dist/cjs/product/shortcutssheet/shortcutssheet.recipe.js +50 -0
- package/dist/cjs/product/taskeditpopover/index.js +7 -0
- package/dist/cjs/product/taskeditpopover/taskeditpopover.js +159 -0
- package/dist/cjs/product/taskeditpopover/taskeditpopover.recipe.js +68 -0
- package/dist/cjs/product/workspaceswitchermenu/index.js +17 -0
- package/dist/cjs/product/workspaceswitchermenu/workspaceswitchermenu.js +38 -0
- package/dist/cjs/product/workspaceswitchermenu/workspaceswitchermenu.recipe.js +34 -0
- package/dist/cjs/tokens/palette.js +27 -0
- package/dist/cjs/tokens/semantic.js +20 -0
- package/dist/datatable.css +40 -7
- package/dist/datatable.layered.css +40 -7
- package/dist/esm/components/button/button.recipe.js +15 -10
- package/dist/esm/components/datatable/datatable.js +6 -3
- package/dist/esm/components/datatable/datatable.recipe.js +35 -2
- package/dist/esm/components/menu/menu.js +47 -7
- package/dist/esm/components/multiselect/multiselect.js +3 -0
- package/dist/esm/components/multiselect/multiselect.recipe.js +18 -0
- package/dist/esm/components/select/select.js +2 -2
- package/dist/esm/components/select/select.recipe.js +19 -0
- package/dist/esm/core/index.js +1 -1
- package/dist/esm/core/place-floating.js +37 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/product/assigneepicker/assigneepicker.js +91 -0
- package/dist/esm/product/assigneepicker/assigneepicker.recipe.js +33 -0
- package/dist/esm/product/assigneepicker/index.js +2 -0
- package/dist/esm/product/notesgallery/index.js +2 -0
- package/dist/esm/product/notesgallery/notesgallery.js +44 -0
- package/dist/esm/product/notesgallery/notesgallery.recipe.js +43 -0
- package/dist/esm/product/objectpagemenu/index.js +1 -0
- package/dist/esm/product/objectpagemenu/objectpagemenu.js +23 -0
- package/dist/esm/product/objectpagemenu/objectpagemenu.recipe.js +27 -0
- package/dist/esm/product/objectsettings/objectsettings.js +106 -13
- package/dist/esm/product/recordpage/recordpage.js +64 -5
- package/dist/esm/product/recordpage/recordpage.recipe.js +38 -0
- package/dist/esm/product/recordpicker/index.js +2 -0
- package/dist/esm/product/recordpicker/recordpicker.js +64 -0
- package/dist/esm/product/recordpicker/recordpicker.recipe.js +33 -0
- package/dist/esm/product/savedviews/index.js +1 -1
- package/dist/esm/product/savedviews/savedviews.js +22 -1
- package/dist/esm/product/savedviews/savedviews.recipe.js +47 -0
- package/dist/esm/product/share/index.js +2 -0
- package/dist/esm/product/share/share.js +143 -0
- package/dist/esm/product/share/share.recipe.js +111 -0
- package/dist/esm/product/shortcutssheet/index.js +1 -0
- package/dist/esm/product/shortcutssheet/shortcutssheet.js +88 -0
- package/dist/esm/product/shortcutssheet/shortcutssheet.recipe.js +47 -0
- package/dist/esm/product/taskeditpopover/index.js +2 -0
- package/dist/esm/product/taskeditpopover/taskeditpopover.js +123 -0
- package/dist/esm/product/taskeditpopover/taskeditpopover.recipe.js +65 -0
- package/dist/esm/product/workspaceswitchermenu/index.js +1 -0
- package/dist/esm/product/workspaceswitchermenu/workspaceswitchermenu.js +35 -0
- package/dist/esm/product/workspaceswitchermenu/workspaceswitchermenu.recipe.js +31 -0
- package/dist/esm/tokens/palette.js +27 -0
- package/dist/esm/tokens/semantic.js +20 -0
- package/dist/multiselect.css +18 -0
- package/dist/multiselect.layered.css +18 -0
- package/dist/native/tokens.d.ts +1 -1
- package/dist/native/tokens.js +56 -4
- package/dist/notesgallery.css +15 -0
- package/dist/notesgallery.d.ts +7 -0
- package/dist/notesgallery.layered.css +17 -0
- package/dist/objectpagemenu.css +3 -0
- package/dist/objectpagemenu.d.ts +7 -0
- package/dist/objectpagemenu.layered.css +5 -0
- package/dist/recordpage.css +36 -0
- package/dist/recordpage.layered.css +36 -0
- package/dist/recordpicker.css +13 -0
- package/dist/recordpicker.d.ts +7 -0
- package/dist/recordpicker.layered.css +15 -0
- package/dist/savedviews.css +47 -0
- package/dist/savedviews.layered.css +47 -0
- package/dist/select.css +19 -0
- package/dist/select.layered.css +19 -0
- package/dist/share.css +84 -0
- package/dist/share.d.ts +7 -0
- package/dist/share.layered.css +86 -0
- package/dist/shortcutssheet.css +24 -0
- package/dist/shortcutssheet.d.ts +7 -0
- package/dist/shortcutssheet.layered.css +26 -0
- package/dist/styles.css +387 -8
- package/dist/styles.layered.css +387 -8
- package/dist/taskeditpopover.css +36 -0
- package/dist/taskeditpopover.d.ts +7 -0
- package/dist/taskeditpopover.layered.css +38 -0
- package/dist/tokens.css +26 -0
- package/dist/tokens.json +56 -4
- package/dist/types/components/button/button.recipe.d.ts +2 -3
- package/dist/types/components/datatable/datatable.d.ts +8 -0
- package/dist/types/components/menu/menu.d.ts +50 -7
- package/dist/types/components/multiselect/multiselect.d.ts +9 -0
- package/dist/types/components/select/select.d.ts +10 -0
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/place-floating.d.ts +37 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/product/assigneepicker/assigneepicker.d.ts +36 -0
- package/dist/types/product/assigneepicker/assigneepicker.recipe.d.ts +3 -0
- package/dist/types/product/assigneepicker/index.d.ts +2 -0
- package/dist/types/product/notesgallery/index.d.ts +2 -0
- package/dist/types/product/notesgallery/notesgallery.d.ts +54 -0
- package/dist/types/product/notesgallery/notesgallery.recipe.d.ts +3 -0
- package/dist/types/product/objectpagemenu/index.d.ts +1 -0
- package/dist/types/product/objectpagemenu/objectpagemenu.d.ts +40 -0
- package/dist/types/product/objectpagemenu/objectpagemenu.recipe.d.ts +17 -0
- package/dist/types/product/objectsettings/objectsettings.d.ts +71 -15
- package/dist/types/product/recordpage/index.d.ts +1 -1
- package/dist/types/product/recordpage/recordpage.d.ts +96 -1
- package/dist/types/product/recordpicker/index.d.ts +2 -0
- package/dist/types/product/recordpicker/recordpicker.d.ts +38 -0
- package/dist/types/product/recordpicker/recordpicker.recipe.d.ts +3 -0
- package/dist/types/product/savedviews/index.d.ts +1 -1
- package/dist/types/product/savedviews/savedviews.d.ts +36 -0
- package/dist/types/product/share/index.d.ts +2 -0
- package/dist/types/product/share/share.d.ts +85 -0
- package/dist/types/product/share/share.recipe.d.ts +3 -0
- package/dist/types/product/shortcutssheet/index.d.ts +1 -0
- package/dist/types/product/shortcutssheet/shortcutssheet.d.ts +49 -0
- package/dist/types/product/shortcutssheet/shortcutssheet.recipe.d.ts +3 -0
- package/dist/types/product/taskeditpopover/index.d.ts +2 -0
- package/dist/types/product/taskeditpopover/taskeditpopover.d.ts +67 -0
- package/dist/types/product/taskeditpopover/taskeditpopover.recipe.d.ts +3 -0
- package/dist/types/product/workspaceswitchermenu/index.d.ts +1 -0
- package/dist/types/product/workspaceswitchermenu/workspaceswitchermenu.d.ts +54 -0
- package/dist/types/product/workspaceswitchermenu/workspaceswitchermenu.recipe.d.ts +19 -0
- package/dist/types/tokens/contract.d.ts +13 -0
- package/dist/types/tokens/palette.d.ts +52 -0
- package/dist/types/tokens/semantic.d.ts +20 -0
- package/dist/workspaceswitchermenu.css +4 -0
- package/dist/workspaceswitchermenu.d.ts +7 -0
- package/dist/workspaceswitchermenu.layered.css +6 -0
- 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
|
-
|
|
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:
|
|
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; } });
|