@crisp-ui-kit/crisp 0.57.1 → 0.57.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authshell.css +9 -4
- package/dist/authshell.layered.css +9 -4
- package/dist/badge.css +3 -3
- package/dist/badge.layered.css +3 -3
- package/dist/board.css +28 -8
- package/dist/board.layered.css +28 -8
- package/dist/bottomsheet.css +26 -0
- package/dist/bottomsheet.d.ts +7 -0
- package/dist/bottomsheet.layered.css +28 -0
- package/dist/button.css +7 -6
- package/dist/button.layered.css +7 -6
- package/dist/checkbox.css +7 -3
- package/dist/checkbox.layered.css +7 -3
- package/dist/chip.css +15 -0
- package/dist/chip.d.ts +3 -1
- package/dist/chip.layered.css +15 -0
- package/dist/chipgroup.css +5 -0
- package/dist/chipgroup.d.ts +7 -0
- package/dist/chipgroup.layered.css +7 -0
- package/dist/cjs/components/badge/badge.recipe.js +22 -8
- package/dist/cjs/components/bottomsheet/bottomsheet.js +90 -0
- package/dist/cjs/components/bottomsheet/bottomsheet.recipe.js +77 -0
- package/dist/cjs/components/bottomsheet/index.js +9 -0
- package/dist/cjs/components/button/button.recipe.js +39 -15
- package/dist/cjs/components/checkbox/checkbox.recipe.js +61 -9
- package/dist/cjs/components/chip/chip.js +14 -2
- package/dist/cjs/components/chip/chip.recipe.js +69 -1
- package/dist/cjs/components/chipgroup/chipgroup.js +51 -0
- package/dist/cjs/components/chipgroup/chipgroup.recipe.js +36 -0
- package/dist/cjs/components/chipgroup/index.js +7 -0
- package/dist/cjs/components/datatable/datatable.js +5 -1
- package/dist/cjs/components/datatable/datatable.recipe.js +11 -2
- package/dist/cjs/components/dialog/dialog.recipe.js +21 -10
- package/dist/cjs/components/emptystate/emptystate.recipe.js +7 -2
- package/dist/cjs/components/fileupload/fileupload.js +21 -4
- package/dist/cjs/components/input/index.js +2 -1
- package/dist/cjs/components/input/input.js +31 -1
- package/dist/cjs/components/input/input.recipe.js +16 -9
- package/dist/cjs/components/menu/menu.recipe.js +21 -7
- package/dist/cjs/components/menusheet/index.js +9 -0
- package/dist/cjs/components/menusheet/menusheet.js +133 -0
- package/dist/cjs/components/menusheet/menusheet.recipe.js +103 -0
- package/dist/cjs/components/multiselect/multiselect.js +1 -1
- package/dist/cjs/components/multiselect/multiselect.recipe.js +33 -9
- package/dist/cjs/components/select/select.js +1 -1
- package/dist/cjs/components/select/select.recipe.js +38 -12
- package/dist/cjs/components/snackbar/index.js +8 -0
- package/dist/cjs/components/snackbar/snackbar.js +121 -0
- package/dist/cjs/components/snackbar/snackbar.recipe.js +71 -0
- package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
- package/dist/cjs/components/tabletoolbar/tabletoolbar.js +37 -12
- package/dist/cjs/components/tabs/tabs.js +10 -4
- package/dist/cjs/components/tabs/tabs.recipe.js +23 -6
- package/dist/cjs/components/textarea/textarea.recipe.js +11 -8
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/product/authshell/authshell.recipe.js +5 -1
- package/dist/cjs/product/command/command.recipe.js +4 -1
- package/dist/cjs/product/comments/comments.js +7 -2
- package/dist/cjs/product/comments/comments.recipe.js +25 -7
- package/dist/cjs/product/memberssettings/index.js +6 -0
- package/dist/cjs/product/memberssettings/memberssettings.js +99 -0
- package/dist/cjs/product/memberssettings/memberssettings.recipe.js +83 -0
- package/dist/cjs/product/notificationssettings/index.js +5 -0
- package/dist/cjs/product/notificationssettings/notificationssettings.js +19 -0
- package/dist/cjs/product/notificationssettings/notificationssettings.recipe.js +44 -0
- package/dist/cjs/product/recordpage/recordpage.js +57 -6
- package/dist/cjs/product/recordpage/recordpage.recipe.js +43 -6
- package/dist/cjs/product/workspacegeneralsettings/index.js +5 -0
- package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.js +21 -0
- package/dist/cjs/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +51 -0
- package/dist/cjs/tokens/contract.js +1 -0
- package/dist/cjs/tokens/elevation.js +8 -5
- package/dist/cjs/tokens/palette.js +28 -8
- package/dist/cjs/tokens/scale.js +44 -2
- package/dist/cjs/tokens/semantic.js +2 -0
- package/dist/columncalc.css +15 -7
- package/dist/columncalc.layered.css +15 -7
- package/dist/command.css +23 -19
- package/dist/command.layered.css +23 -19
- package/dist/comments.css +28 -19
- package/dist/comments.d.ts +2 -2
- package/dist/comments.layered.css +28 -19
- package/dist/datatable.css +161 -67
- package/dist/datatable.layered.css +161 -67
- package/dist/datepicker.css +13 -41
- package/dist/datepicker.layered.css +13 -41
- package/dist/datepickerfield.css +4 -1
- package/dist/datepickerfield.layered.css +4 -1
- package/dist/dialog.css +12 -7
- package/dist/dialog.layered.css +12 -7
- package/dist/emptystate.css +5 -3
- package/dist/emptystate.layered.css +5 -3
- package/dist/esm/components/badge/badge.recipe.js +22 -8
- package/dist/esm/components/bottomsheet/bottomsheet.js +52 -0
- package/dist/esm/components/bottomsheet/bottomsheet.recipe.js +74 -0
- package/dist/esm/components/bottomsheet/index.js +2 -0
- package/dist/esm/components/button/button.recipe.js +40 -16
- package/dist/esm/components/checkbox/checkbox.recipe.js +61 -9
- package/dist/esm/components/chip/chip.js +14 -2
- package/dist/esm/components/chip/chip.recipe.js +69 -1
- package/dist/esm/components/chipgroup/chipgroup.js +15 -0
- package/dist/esm/components/chipgroup/chipgroup.recipe.js +33 -0
- package/dist/esm/components/chipgroup/index.js +2 -0
- package/dist/esm/components/datatable/datatable.js +5 -1
- package/dist/esm/components/datatable/datatable.recipe.js +11 -2
- package/dist/esm/components/dialog/dialog.recipe.js +22 -11
- package/dist/esm/components/emptystate/emptystate.recipe.js +7 -2
- package/dist/esm/components/fileupload/fileupload.js +20 -5
- package/dist/esm/components/input/index.js +1 -1
- package/dist/esm/components/input/input.js +30 -0
- package/dist/esm/components/input/input.recipe.js +17 -10
- package/dist/esm/components/menu/menu.recipe.js +21 -7
- package/dist/esm/components/menusheet/index.js +2 -0
- package/dist/esm/components/menusheet/menusheet.js +95 -0
- package/dist/esm/components/menusheet/menusheet.recipe.js +100 -0
- package/dist/esm/components/multiselect/multiselect.js +1 -1
- package/dist/esm/components/multiselect/multiselect.recipe.js +33 -9
- package/dist/esm/components/select/select.js +1 -1
- package/dist/esm/components/select/select.recipe.js +38 -12
- package/dist/esm/components/snackbar/index.js +2 -0
- package/dist/esm/components/snackbar/snackbar.js +84 -0
- package/dist/esm/components/snackbar/snackbar.recipe.js +68 -0
- package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +7 -2
- package/dist/esm/components/tabletoolbar/tabletoolbar.js +37 -12
- package/dist/esm/components/tabs/tabs.js +10 -4
- package/dist/esm/components/tabs/tabs.recipe.js +23 -6
- package/dist/esm/components/textarea/textarea.recipe.js +12 -9
- package/dist/esm/index.js +7 -0
- package/dist/esm/product/authshell/authshell.recipe.js +5 -1
- package/dist/esm/product/command/command.recipe.js +4 -1
- package/dist/esm/product/comments/comments.js +7 -2
- package/dist/esm/product/comments/comments.recipe.js +25 -7
- package/dist/esm/product/memberssettings/index.js +1 -0
- package/dist/esm/product/memberssettings/memberssettings.js +62 -0
- package/dist/esm/product/memberssettings/memberssettings.recipe.js +80 -0
- package/dist/esm/product/notificationssettings/index.js +1 -0
- package/dist/esm/product/notificationssettings/notificationssettings.js +16 -0
- package/dist/esm/product/notificationssettings/notificationssettings.recipe.js +41 -0
- package/dist/esm/product/recordpage/recordpage.js +58 -7
- package/dist/esm/product/recordpage/recordpage.recipe.js +43 -6
- package/dist/esm/product/workspacegeneralsettings/index.js +1 -0
- package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.js +18 -0
- package/dist/esm/product/workspacegeneralsettings/workspacegeneralsettings.recipe.js +48 -0
- package/dist/esm/tokens/contract.js +2 -1
- package/dist/esm/tokens/elevation.js +8 -5
- package/dist/esm/tokens/palette.js +28 -8
- package/dist/esm/tokens/scale.js +43 -1
- package/dist/esm/tokens/semantic.js +2 -0
- package/dist/fileupload.css +3 -1
- package/dist/fileupload.layered.css +3 -1
- package/dist/input.css +6 -4
- package/dist/input.layered.css +6 -4
- package/dist/listpage.css +3 -1
- package/dist/listpage.layered.css +3 -1
- package/dist/memberssettings.css +67 -0
- package/dist/memberssettings.d.ts +7 -0
- package/dist/memberssettings.layered.css +69 -0
- package/dist/menu.css +2 -2
- package/dist/menu.layered.css +2 -2
- package/dist/menusheet.css +36 -0
- package/dist/menusheet.d.ts +7 -0
- package/dist/menusheet.layered.css +38 -0
- package/dist/multiselect.css +13 -6
- package/dist/multiselect.layered.css +13 -6
- package/dist/native/tokens.d.ts +2 -1
- package/dist/native/tokens.js +20 -3
- package/dist/notificationssettings.css +22 -0
- package/dist/notificationssettings.d.ts +7 -0
- package/dist/notificationssettings.layered.css +24 -0
- package/dist/objectsettings.css +4 -4
- package/dist/objectsettings.layered.css +4 -4
- package/dist/recordpage.css +67 -23
- package/dist/recordpage.layered.css +67 -23
- package/dist/recordpanel.css +35 -16
- package/dist/recordpanel.layered.css +35 -16
- package/dist/resizablepanel.css +8 -5
- package/dist/resizablepanel.layered.css +8 -5
- package/dist/richtext.css +24 -8
- package/dist/richtext.layered.css +24 -8
- package/dist/savedviews.css +9 -2
- package/dist/savedviews.layered.css +9 -2
- package/dist/select.css +25 -5
- package/dist/select.layered.css +25 -5
- package/dist/settingsshell.css +2 -3
- package/dist/settingsshell.layered.css +2 -3
- package/dist/slider.css +6 -27
- package/dist/slider.layered.css +6 -27
- package/dist/snackbar.css +24 -0
- package/dist/snackbar.d.ts +7 -0
- package/dist/snackbar.layered.css +26 -0
- package/dist/statcard.css +3 -1
- package/dist/statcard.layered.css +3 -1
- package/dist/styles.css +859 -345
- package/dist/styles.layered.css +859 -345
- package/dist/table.css +28 -10
- package/dist/table.layered.css +28 -10
- package/dist/tabletoolbar.css +35 -24
- package/dist/tabletoolbar.layered.css +35 -24
- package/dist/tabs.css +18 -4
- package/dist/tabs.layered.css +18 -4
- package/dist/textarea.css +2 -6
- package/dist/textarea.layered.css +2 -6
- package/dist/themepicker.css +2 -1
- package/dist/themepicker.layered.css +2 -1
- package/dist/tokens.css +13 -2
- package/dist/tokens.json +20 -3
- package/dist/types/components/bottomsheet/bottomsheet.d.ts +35 -0
- package/dist/types/components/bottomsheet/bottomsheet.recipe.d.ts +3 -0
- package/dist/types/components/bottomsheet/index.d.ts +2 -0
- package/dist/types/components/button/button.recipe.d.ts +11 -6
- package/dist/types/components/checkbox/checkbox.recipe.d.ts +28 -5
- package/dist/types/components/chip/chip.d.ts +22 -0
- package/dist/types/components/chip/chip.recipe.d.ts +48 -0
- package/dist/types/components/chipgroup/chipgroup.d.ts +14 -0
- package/dist/types/components/chipgroup/chipgroup.recipe.d.ts +5 -0
- package/dist/types/components/chipgroup/index.d.ts +2 -0
- package/dist/types/components/datatable/datatable.d.ts +19 -0
- package/dist/types/components/fileupload/fileupload.d.ts +26 -0
- package/dist/types/components/input/index.d.ts +1 -1
- package/dist/types/components/input/input.d.ts +72 -0
- package/dist/types/components/menusheet/index.d.ts +2 -0
- package/dist/types/components/menusheet/menusheet.d.ts +42 -0
- package/dist/types/components/menusheet/menusheet.recipe.d.ts +3 -0
- package/dist/types/components/snackbar/index.d.ts +2 -0
- package/dist/types/components/snackbar/snackbar.d.ts +36 -0
- package/dist/types/components/snackbar/snackbar.recipe.d.ts +5 -0
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +28 -1
- package/dist/types/components/tabs/tabs.d.ts +11 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/product/comments/comments.d.ts +9 -3
- package/dist/types/product/comments/comments.recipe.d.ts +12 -2
- package/dist/types/product/memberssettings/index.d.ts +1 -0
- package/dist/types/product/memberssettings/memberssettings.d.ts +85 -0
- package/dist/types/product/memberssettings/memberssettings.recipe.d.ts +3 -0
- package/dist/types/product/notificationssettings/index.d.ts +1 -0
- package/dist/types/product/notificationssettings/notificationssettings.d.ts +37 -0
- package/dist/types/product/notificationssettings/notificationssettings.recipe.d.ts +3 -0
- package/dist/types/product/recordpage/recordpage.d.ts +53 -2
- package/dist/types/product/workspacegeneralsettings/index.d.ts +1 -0
- package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.d.ts +48 -0
- package/dist/types/product/workspacegeneralsettings/workspacegeneralsettings.recipe.d.ts +3 -0
- package/dist/types/tokens/contract.d.ts +4 -1
- package/dist/types/tokens/elevation.d.ts +8 -5
- package/dist/types/tokens/palette.d.ts +9 -1
- package/dist/types/tokens/scale.d.ts +11 -1
- package/dist/types/tokens/semantic.d.ts +2 -0
- package/dist/wheelpicker.css +4 -2
- package/dist/wheelpicker.layered.css +4 -2
- package/dist/workspacegeneralsettings.css +30 -0
- package/dist/workspacegeneralsettings.d.ts +7 -0
- package/dist/workspacegeneralsettings.layered.css +32 -0
- package/package.json +36 -1
|
@@ -311,7 +311,14 @@ function NotesSection({ notes, onAdd, labels, }) {
|
|
|
311
311
|
return ((0, jsx_runtime_1.jsxs)("section", { children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: labels.tabs.notes, count: notes.length, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", onClick: () => setOpen(true), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), labels.newNote] }) }), open && ((0, jsx_runtime_1.jsx)(Composer, { labels: labels, multiline: true, placeholder: labels.notePlaceholder, submitLabel: labels.saveNote, onCancel: () => setOpen(false), onSubmit: (t) => {
|
|
312
312
|
onAdd(t);
|
|
313
313
|
setOpen(false);
|
|
314
|
-
} })), notes.length === 0 && !open ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: labels.noNotesYet })) : (
|
|
314
|
+
} })), notes.length === 0 && !open ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: labels.noNotesYet })) : (
|
|
315
|
+
// #871: one line, not a two-row card -- measured live: avatar,
|
|
316
|
+
// then the note's own title and body run together inline, then a
|
|
317
|
+
// relative time at the far end of the SAME row. No author name at
|
|
318
|
+
// all (Attio's real preview never shows one here, only the note's
|
|
319
|
+
// own content) -- `labels.you` stays defined for a consumer that
|
|
320
|
+
// still wants it elsewhere, just unused in this exact spot now.
|
|
321
|
+
notes.map((n) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-note", children: [(0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-note-left", children: [(0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "sm", shape: "circle", tone: "neutral", children: "Y" }), n.title && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-title", children: n.title })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-text", children: n.text })] }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-note-time", children: n.time })] }, n.id))))] }));
|
|
315
322
|
}
|
|
316
323
|
function TasksSection({ tasks, onAdd, onToggle, labels, }) {
|
|
317
324
|
const [open, setOpen] = React.useState(false);
|
|
@@ -344,13 +351,51 @@ function EmptyCard({ icon, children, }) {
|
|
|
344
351
|
* `RecordPage`'s own root does: `<div className={recordpageRecipe()}>`
|
|
345
352
|
* (also exported from this package).
|
|
346
353
|
*/
|
|
347
|
-
function RecordDetails({ record, columns, sections, onEdit, labels, className, ...rest }) {
|
|
354
|
+
function RecordDetails({ record, columns, sections, onEdit, labels, className, resizable = false, width: controlledWidth, defaultWidth = DETAILS_DEFAULT_W, onWidthChange, minWidth = DETAILS_MIN_W, maxWidth = DETAILS_MAX_W, ...rest }) {
|
|
348
355
|
const t = useRecordPageLabels(labels);
|
|
349
356
|
const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, editable_field_1.useEditableField)(onEdit);
|
|
350
357
|
const [detailsOpen, setDetailsOpen] = React.useState(true);
|
|
351
358
|
const [searchOpen, setSearchOpen] = React.useState(false);
|
|
352
359
|
const [fieldQuery, setFieldQuery] = React.useState("");
|
|
353
360
|
const [showAllValues, setShowAllValues] = React.useState(false);
|
|
361
|
+
// #930: controlled/uncontrolled width, same split as RecordPanel's own
|
|
362
|
+
// resizable width -- only read when `resizable`, same reasoning as
|
|
363
|
+
// RecordPanel's own (a non-resizing consumer has no business carrying
|
|
364
|
+
// width state at all).
|
|
365
|
+
const [internalWidth, setInternalWidth] = React.useState(defaultWidth);
|
|
366
|
+
const width = controlledWidth ?? internalWidth;
|
|
367
|
+
const setWidth = (next) => {
|
|
368
|
+
const clamped = Math.max(minWidth, Math.min(maxWidth, next));
|
|
369
|
+
if (controlledWidth === undefined)
|
|
370
|
+
setInternalWidth(clamped);
|
|
371
|
+
onWidthChange?.(clamped);
|
|
372
|
+
};
|
|
373
|
+
const [detailsResizing, setDetailsResizing] = React.useState(false);
|
|
374
|
+
const detailsDragRef = React.useRef(null);
|
|
375
|
+
const onDetailsResizeDown = (e) => {
|
|
376
|
+
// This column is a leading (left-docked) rail, the mirror image of
|
|
377
|
+
// RecordPanel's own trailing (right-docked) one -- a rightward pull
|
|
378
|
+
// grows it in LTR, the same direction RecordPage's own internal aside
|
|
379
|
+
// resize already uses (#212/#255).
|
|
380
|
+
detailsDragRef.current = {
|
|
381
|
+
x: e.clientX,
|
|
382
|
+
w: width,
|
|
383
|
+
dir: (0, core_1.isRtlElement)(e.currentTarget) ? -1 : 1,
|
|
384
|
+
};
|
|
385
|
+
setDetailsResizing(true);
|
|
386
|
+
e.target.setPointerCapture(e.pointerId);
|
|
387
|
+
};
|
|
388
|
+
const onDetailsResizeMove = (e) => {
|
|
389
|
+
const r = detailsDragRef.current;
|
|
390
|
+
if (!r)
|
|
391
|
+
return;
|
|
392
|
+
setWidth(r.w + r.dir * (e.clientX - r.x));
|
|
393
|
+
};
|
|
394
|
+
const onDetailsResizeUp = (e) => {
|
|
395
|
+
detailsDragRef.current = null;
|
|
396
|
+
setDetailsResizing(false);
|
|
397
|
+
e.target.releasePointerCapture(e.pointerId);
|
|
398
|
+
};
|
|
354
399
|
const fields = columns.filter((col) => col.type !== "entity");
|
|
355
400
|
const q = fieldQuery.trim().toLowerCase();
|
|
356
401
|
const matches = (col) => !q || col.label.toLowerCase().includes(q);
|
|
@@ -387,7 +432,7 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
|
|
|
387
432
|
groups = [{ title: undefined, fields: shown }];
|
|
388
433
|
}
|
|
389
434
|
const totalShown = groups.reduce((n, g) => n + g.fields.length, 0);
|
|
390
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, core_1.cx)("crisp-recordpage-section", className), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-detailhead", children: [searchOpen ? ((0, jsx_runtime_1.jsx)("input", {
|
|
435
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, core_1.cx)("crisp-recordpage-section", className), "data-resizable": resizable ? "" : undefined, style: resizable ? { width } : undefined, ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-detailhead", children: [searchOpen ? ((0, jsx_runtime_1.jsx)("input", {
|
|
391
436
|
// biome-ignore lint/a11y/noAutofocus: focusing the just-opened field search is expected
|
|
392
437
|
autoFocus: true, type: "text", className: "crisp-recordpage-fieldsearch", placeholder: t.searchPlaceholder, "aria-label": t.searchFields, value: fieldQuery, onChange: (e) => setFieldQuery(e.target.value), onKeyDown: (e) => {
|
|
393
438
|
if (e.key === "Escape") {
|
|
@@ -461,7 +506,13 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
|
|
|
461
506
|
setSearchOpen(next);
|
|
462
507
|
if (!next)
|
|
463
508
|
setFieldQuery("");
|
|
464
|
-
}, children: showAllValues ? t.viewLess : t.viewAllValues }))] })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-noresults", children: t.noFieldsMatch(fieldQuery) })))
|
|
509
|
+
}, children: showAllValues ? t.viewLess : t.viewAllValues }))] })) : ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-noresults", children: t.noFieldsMatch(fieldQuery) }))), resizable && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-detailresize", "data-active": detailsResizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(width), "aria-valuemin": minWidth, "aria-valuemax": maxWidth, tabIndex: 0, onPointerDown: onDetailsResizeDown, onPointerMove: onDetailsResizeMove, onPointerUp: onDetailsResizeUp, onKeyDown: (e) => {
|
|
510
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
|
|
511
|
+
return;
|
|
512
|
+
const rtl = (0, core_1.isRtlElement)(e.currentTarget);
|
|
513
|
+
const grow = e.key === (rtl ? "ArrowLeft" : "ArrowRight");
|
|
514
|
+
setWidth(grow ? width + 16 : width - 16);
|
|
515
|
+
} }))] }));
|
|
465
516
|
}
|
|
466
517
|
RecordDetails.displayName = "RecordDetails";
|
|
467
518
|
/**
|
|
@@ -472,7 +523,7 @@ RecordDetails.displayName = "RecordDetails";
|
|
|
472
523
|
* Emails sections (Notes & Tasks are live — add and check things off). Drop it
|
|
473
524
|
* into the app's main content area.
|
|
474
525
|
*/
|
|
475
|
-
function RecordPage({ record, columns, collection = "Records", labels, onBack, onToggleFull, full, className, onEdit, tabs: tabsProp, defaultTab, notes: notesProp, onAddNote, tasks: tasksProp, onAddTask, onToggleTask, sections, highlights: highlightsProp, quickActions: quickActionsProp, comments: commentsProp, onPostComment, currentUser, onShare, ...rest }) {
|
|
526
|
+
function RecordPage({ record, columns, collection = "Records", labels, onBack, onToggleFull, full, onClose, closeLabel = "Close", onPrevious, previousRecordLabel = "Previous record", onNext, nextRecordLabel = "Next record", counterLabel, className, onEdit, tabs: tabsProp, defaultTab, notes: notesProp, onAddNote, tasks: tasksProp, onAddTask, onToggleTask, sections, highlights: highlightsProp, quickActions: quickActionsProp, comments: commentsProp, onPostComment, currentUser, onShare, ...rest }) {
|
|
476
527
|
const t = useRecordPageLabels(labels);
|
|
477
528
|
const [favorite, setFavorite] = React.useState(false);
|
|
478
529
|
// Notes/Tasks are controlled when the caller supplies `notes`/`tasks` (even
|
|
@@ -728,7 +779,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
|
|
|
728
779
|
const effectivePanel = tabsProp
|
|
729
780
|
? (active) => tabsProp.find((tb) => tb.id === active)?.render()
|
|
730
781
|
: builtinPanel;
|
|
731
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", children: [(0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", onClick: onShare, children: t.share }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: () => setCommentsOpen(true), "aria-label": t.comments, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MessageSquare, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Merge, { size: 15, strokeWidth: 1.75 }), children: t.mergeRecords }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 15, strokeWidth: 1.75 }), children: t.configurePage }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), children: t.copyPageUrl }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), children: t.copyRecordId }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }), t.addToList] }), quickActions.map((a, i) => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": a.label, onClick: a.onSelect, children: (0, jsx_runtime_1.jsx)(a.icon, { size: 15, strokeWidth: 1.75 }) }, i)))] }), (0, jsx_runtime_1.jsx)(RecordDetails, { record: record, columns: columns, sections: sections, onEdit: onEdit, labels: labels }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.lists, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), t.addToList] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: t.noLists })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-resizer", "data-active": resizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(detailsW), "aria-valuemin": DETAILS_MIN_W, "aria-valuemax": DETAILS_MAX_W, tabIndex: 0, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onKeyDown: (e) => {
|
|
782
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", "data-peek": onClose ? "" : undefined, children: [onClose ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-peekbar", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-peek-iconbtn", "aria-label": closeLabel, onClick: onClose, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 16, strokeWidth: 1.75 }) }), (onPrevious || onNext) && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-peek-pager", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-peek-navbtn", "aria-label": previousRecordLabel, disabled: !onPrevious, onClick: onPrevious, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronUp, { size: 16, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-peek-navbtn", "aria-label": nextRecordLabel, disabled: !onNext, onClick: onNext, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 16, strokeWidth: 1.75 }) })] })), counterLabel != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-peek-counter", children: counterLabel }))] })) : ((0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", onClick: onShare, children: t.share }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: () => setCommentsOpen(true), "aria-label": t.comments, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MessageSquare, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Merge, { size: 15, strokeWidth: 1.75 }), children: t.mergeRecords }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 15, strokeWidth: 1.75 }), children: t.configurePage }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), children: t.copyPageUrl }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), children: t.copyRecordId }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }), t.addToList] }), quickActions.map((a, i) => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": a.label, onClick: a.onSelect, children: (0, jsx_runtime_1.jsx)(a.icon, { size: 15, strokeWidth: 1.75 }) }, i)))] }), (0, jsx_runtime_1.jsx)(RecordDetails, { record: record, columns: columns, sections: sections, onEdit: onEdit, labels: labels }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.lists, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), t.addToList] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: t.noLists })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-resizer", "data-active": resizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(detailsW), "aria-valuemin": DETAILS_MIN_W, "aria-valuemax": DETAILS_MAX_W, tabIndex: 0, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onKeyDown: (e) => {
|
|
732
783
|
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
|
|
733
784
|
return;
|
|
734
785
|
// The pointer drag learned its direction in #212; this did not.
|
|
@@ -26,6 +26,21 @@ const config = (0, core_1.defineRecipe)({
|
|
|
26
26
|
& * { box-sizing: border-box; }
|
|
27
27
|
|
|
28
28
|
& .crisp-recordpage-topbar { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 44px; flex-shrink: 0; padding: 0 ${tokens_1.contract.space["3"]}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; }
|
|
29
|
+
/* #624: expanding a peek to its full record keeps a hybrid header
|
|
30
|
+
(Close/Previous/Next/counter) instead of reverting to the plain
|
|
31
|
+
breadcrumb above -- measured live on a real expanded record: 49px
|
|
32
|
+
tall (not 44px), 8px/10px padding, same borderSubtle hairline. Same
|
|
33
|
+
tokens as product/recordpanel's own already-shipped toolbar, not
|
|
34
|
+
new values -- this is the same row, reused in a second component. */
|
|
35
|
+
& .crisp-recordpage-topbar[data-peek] { height: 49px; padding: ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["2.5"]}; }
|
|
36
|
+
& .crisp-recordpage-peekbar { display: flex; align-items: center; }
|
|
37
|
+
& .crisp-recordpage-peek-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: transparent; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 55%, transparent); font-family: inherit; cursor: pointer; transition: background-color .12s; }
|
|
38
|
+
& .crisp-recordpage-peek-iconbtn:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
|
|
39
|
+
& .crisp-recordpage-peek-pager { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; margin-inline-start: ${tokens_1.contract.space["3"]}; }
|
|
40
|
+
& .crisp-recordpage-peek-navbtn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field}; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; cursor: pointer; }
|
|
41
|
+
& .crisp-recordpage-peek-navbtn:hover:not(:disabled) { background: ${tokens_1.contract.bgRaised}; }
|
|
42
|
+
& .crisp-recordpage-peek-navbtn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
43
|
+
& .crisp-recordpage-peek-counter { margin-inline-start: ${tokens_1.contract.space["3"]}; font-size: 12px; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
29
44
|
& .crisp-recordpage-crumbs { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; min-width: 0; }
|
|
30
45
|
& .crisp-recordpage-crumb { display: inline-flex; align-items: center; height: 26px; padding: 0 ${tokens_1.contract.space["1.5"]}; margin: 0 calc(-1 * ${tokens_1.contract.space["1.5"]}) 0 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; cursor: pointer; }
|
|
31
46
|
& .crisp-recordpage-crumb:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
|
|
@@ -45,6 +60,17 @@ const config = (0, core_1.defineRecipe)({
|
|
|
45
60
|
& .crisp-recordpage-resizer::before { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-start: -4px; width: 9px; }
|
|
46
61
|
& .crisp-recordpage-resizer::after { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-start: -1px; width: 2px; background: transparent; transition: background-color .12s ease; }
|
|
47
62
|
& .crisp-recordpage-resizer:hover::after, & .crisp-recordpage-resizer[data-active]::after { background: color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 55%, transparent); }
|
|
63
|
+
/* #930: RecordDetails' own standalone resize handle -- same visible
|
|
64
|
+
hit-slop/line-highlight shape as .crisp-recordpage-resizer just above,
|
|
65
|
+
just absolutely positioned at the trailing edge instead of a 0-width
|
|
66
|
+
flex sibling, since RecordDetails always returns a single root (the
|
|
67
|
+
same internal-strip placement RecordPanel's own resize handle uses,
|
|
68
|
+
mirrored to the opposite edge -- this column is leading, RecordPanel
|
|
69
|
+
is trailing). */
|
|
70
|
+
& .crisp-recordpage-section[data-resizable] { position: relative; }
|
|
71
|
+
& .crisp-recordpage-detailresize { position: absolute; top: 0; bottom: 0; inset-inline-end: -4px; width: 9px; cursor: col-resize; z-index: 5; touch-action: none; }
|
|
72
|
+
& .crisp-recordpage-detailresize::after { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-end: 3px; width: 2px; background: transparent; transition: background-color .12s ease; }
|
|
73
|
+
& .crisp-recordpage-detailresize:hover::after, & .crisp-recordpage-detailresize[data-active]::after { background: color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 55%, transparent); }
|
|
48
74
|
& .crisp-recordpage-entity { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; padding: ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["1"]} ${tokens_1.contract.space["2"]}; }
|
|
49
75
|
& .crisp-recordpage-entity-logo { width: 32px; height: 32px; border-radius: 30%; flex-shrink: 0; object-fit: cover; background: ${tokens_1.contract.bgRaised}; }
|
|
50
76
|
& .crisp-recordpage-entity-name { flex: 0 1 auto; min-width: 0; font-size: ${tokens_1.contract.text.xl}; font-weight: ${tokens_1.contract.weight.semibold}; letter-spacing: -0.3px; color: ${tokens_1.contract.fgPrimary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -178,12 +204,23 @@ const config = (0, core_1.defineRecipe)({
|
|
|
178
204
|
& .crisp-recordpage-btn--primary { box-shadow: none; background: ${tokens_1.contract.bgBrandSolid}; color: ${tokens_1.contract.fgOnBrand}; }
|
|
179
205
|
& .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
180
206
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
207
|
+
/* #871: one bordered card per note (border-radius.xl, borderSubtle),
|
|
208
|
+
not a flush divider-list row -- measured live on a real populated
|
|
209
|
+
note: the whole row is flex space-between, avatar+title+body on the
|
|
210
|
+
left (its own flex, gap.2), the relative time alone on the right.
|
|
211
|
+
The real DOM nests an inner clickable button (padding 6/8, radius.md)
|
|
212
|
+
inside an outer card (padding 4px, radius.xl) -- collapsed into this
|
|
213
|
+
one non-interactive div's own combined padding (2.5/3) since crisp's
|
|
214
|
+
NotesSection has no click-to-open behaviour to justify the extra
|
|
215
|
+
layer. The 6px gap between stacked cards is NOT independently
|
|
216
|
+
measured (this workspace only ever had one real note to check) --
|
|
217
|
+
a judgement call off the existing space scale, not a live value. */
|
|
218
|
+
& .crisp-recordpage-note { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["3"]}; padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["3"]}; border: 1px solid ${tokens_1.contract.borderSubtle}; border-radius: ${tokens_1.contract.radius.xl}; }
|
|
219
|
+
& .crisp-recordpage-note + .crisp-recordpage-note { margin-top: ${tokens_1.contract.space["1.5"]}; }
|
|
220
|
+
& .crisp-recordpage-note-left { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; min-width: 0; overflow: hidden; }
|
|
221
|
+
& .crisp-recordpage-note-title { flex-shrink: 0; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
|
|
222
|
+
& .crisp-recordpage-note-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
|
|
223
|
+
& .crisp-recordpage-note-time { flex-shrink: 0; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 50%, transparent); }
|
|
187
224
|
|
|
188
225
|
& .crisp-recordpage-task { display: flex; align-items: flex-start; gap: ${tokens_1.contract.space["2"]}; padding: ${tokens_1.contract.space["1.5"]} 0; border-top: 1px solid ${tokens_1.contract.borderSubtle}; }
|
|
189
226
|
& .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; padding-top: 1px; }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkspaceGeneralSettings = void 0;
|
|
4
|
+
var workspacegeneralsettings_1 = require("./workspacegeneralsettings");
|
|
5
|
+
Object.defineProperty(exports, "WorkspaceGeneralSettings", { enumerable: true, get: function () { return workspacegeneralsettings_1.WorkspaceGeneralSettings; } });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkspaceGeneralSettings = WorkspaceGeneralSettings;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const lucide_react_1 = require("lucide-react");
|
|
6
|
+
const avatar_1 = require("../../components/avatar");
|
|
7
|
+
const button_1 = require("../../components/button");
|
|
8
|
+
const formfield_1 = require("../../components/formfield");
|
|
9
|
+
const input_1 = require("../../components/input");
|
|
10
|
+
const table_1 = require("../../components/table");
|
|
11
|
+
const textlink_1 = require("../../components/textlink");
|
|
12
|
+
const workspacegeneralsettings_recipe_1 = require("./workspacegeneralsettings.recipe");
|
|
13
|
+
/**
|
|
14
|
+
* Attio's Settings → Workspace → General page (crisp#638, P-128), measured
|
|
15
|
+
* live: a logo + Name/Slug section, an "Export workspace data" table, and a
|
|
16
|
+
* "Danger zone" delete-workspace row.
|
|
17
|
+
*/
|
|
18
|
+
function WorkspaceGeneralSettings({ logoSrc, workspaceInitial, onUploadLogo, name, onNameChange, slug, onCopySlug, exports: exportRows, onStartExport, onDeleteWorkspace, className, title = "General", description = "Change the settings for your current workspace.", learnMoreLabel = "Learn more", learnMoreHref = "#", logoHelpText = "We only support PNGs, JPEGs and GIFs under 10MB", uploadLogoLabel = "Upload logo", nameFieldLabel = "Name", slugFieldLabel = "Slug", copySlugLabel = "Copy slug", exportSectionTitle = "Export workspace data", exportSectionDescription = "Exports are in CSV format and can be downloaded within 7 days", startExportLabel = "Start new export", typeColumnLabel = "Type", dateColumnLabel = "Date", noExportsLabel = "No exports yet", dangerSectionTitle = "Danger zone", deleteWorkspaceTitle = "Delete workspace", deleteWorkspaceWarning = "Once deleted, your workspace cannot be recovered", deleteWorkspaceLabel = "Delete workspace", ...rest }) {
|
|
19
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: (0, workspacegeneralsettings_recipe_1.workspacegeneralsettingsRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-page", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-heading", children: [(0, jsx_runtime_1.jsx)("h1", { className: "crisp-workspacegeneralsettings-title", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "crisp-workspacegeneralsettings-desc", children: [description, " ", (0, jsx_runtime_1.jsx)(textlink_1.TextLink, { href: learnMoreHref, children: learnMoreLabel })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-logorow", children: [logoSrc ? ((0, jsx_runtime_1.jsx)("img", { src: logoSrc, alt: "", width: 48, height: 48, style: { borderRadius: "30%", objectFit: "cover" } })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "xl", shape: "rounded", tone: "brand", children: workspaceInitial })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-logotext", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-workspacegeneralsettings-logohelp", children: logoHelpText }), (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "neutral", size: "sm", onClick: onUploadLogo, children: uploadLogoLabel })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-fieldrow", children: [(0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: nameFieldLabel, children: (0, jsx_runtime_1.jsx)(input_1.Input, { value: name, onChange: (e) => onNameChange(e.target.value) }) }), (0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: slugFieldLabel, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-slugfield", children: [(0, jsx_runtime_1.jsx)(input_1.Input, { value: slug, readOnly: true }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-workspacegeneralsettings-copybtn", "aria-label": copySlugLabel, onClick: onCopySlug, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 16 }) })] }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-sectionhead", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-sectionhead-text", children: [(0, jsx_runtime_1.jsx)("h2", { className: "crisp-workspacegeneralsettings-sectiontitle", children: exportSectionTitle }), (0, jsx_runtime_1.jsx)("p", { className: "crisp-workspacegeneralsettings-desc", children: exportSectionDescription })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "neutral", size: "sm", onClick: onStartExport, children: startExportLabel })] }), (0, jsx_runtime_1.jsxs)(table_1.Table, { children: [(0, jsx_runtime_1.jsx)(table_1.TableHeader, { children: (0, jsx_runtime_1.jsxs)(table_1.TableRow, { children: [(0, jsx_runtime_1.jsx)(table_1.TableHead, { children: typeColumnLabel }), (0, jsx_runtime_1.jsx)(table_1.TableHead, { children: dateColumnLabel })] }) }), (0, jsx_runtime_1.jsx)(table_1.TableBody, { children: exportRows.length === 0 ? ((0, jsx_runtime_1.jsx)(table_1.TableRow, { children: (0, jsx_runtime_1.jsx)(table_1.TableCell, { colSpan: 2, children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-workspacegeneralsettings-emptyrow", children: noExportsLabel }) }) })) : (exportRows.map((row) => ((0, jsx_runtime_1.jsxs)(table_1.TableRow, { children: [(0, jsx_runtime_1.jsx)(table_1.TableCell, { children: row.type }), (0, jsx_runtime_1.jsx)(table_1.TableCell, { children: row.date })] }, row.id)))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-section", children: [(0, jsx_runtime_1.jsx)("h2", { className: "crisp-workspacegeneralsettings-sectiontitle", children: dangerSectionTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-dangerrow", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-workspacegeneralsettings-dangertext", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-workspacegeneralsettings-rowtitle", children: deleteWorkspaceTitle }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-workspacegeneralsettings-dangerwarning", children: deleteWorkspaceWarning })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { intent: "danger", size: "sm", onClick: onDeleteWorkspace, children: deleteWorkspaceLabel })] })] })] }) }));
|
|
20
|
+
}
|
|
21
|
+
WorkspaceGeneralSettings.displayName = "WorkspaceGeneralSettings";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.workspacegeneralsettingsRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
// Measured live against app.attio.com/<workspace>/settings/workspace
|
|
7
|
+
// (crisp#638, P-128). Logo tile + Name/Slug fields side by side, an
|
|
8
|
+
// "Export workspace data" section (header row + Type/Date table + empty
|
|
9
|
+
// state), and a "Danger zone" section (a red-tinted bordered row).
|
|
10
|
+
const config = (0, core_1.defineRecipe)({
|
|
11
|
+
name: "workspacegeneralsettings",
|
|
12
|
+
base: `& .crisp-workspacegeneralsettings-page { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["6"]}; font-family: ${tokens_1.contract.font.sans}; }
|
|
13
|
+
& .crisp-workspacegeneralsettings-heading { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["0.5"]}; }
|
|
14
|
+
& .crisp-workspacegeneralsettings-title { font-size: 24px; line-height: 28px; font-weight: ${tokens_1.contract.weight.semibold}; letter-spacing: -0.48px; color: ${tokens_1.contract.fgPrimary}; margin: 0; }
|
|
15
|
+
& .crisp-workspacegeneralsettings-desc { font-size: ${tokens_1.contract.text.lg}; line-height: 20px; color: ${tokens_1.contract.fgMuted}; margin: 0; }
|
|
16
|
+
|
|
17
|
+
& .crisp-workspacegeneralsettings-section { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["4"]}; }
|
|
18
|
+
& .crisp-workspacegeneralsettings-sectiontitle { font-size: 16px; line-height: 20px; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; margin: 0; }
|
|
19
|
+
& .crisp-workspacegeneralsettings-sectionhead { display: flex; align-items: flex-start; justify-content: space-between; gap: ${tokens_1.contract.space["4"]}; }
|
|
20
|
+
& .crisp-workspacegeneralsettings-sectionhead-text { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1"]}; }
|
|
21
|
+
|
|
22
|
+
/* Logo row: a tile + helper text + "Upload logo" button. */
|
|
23
|
+
& .crisp-workspacegeneralsettings-logorow { display: flex; align-items: center; gap: ${tokens_1.contract.space["4"]}; }
|
|
24
|
+
& .crisp-workspacegeneralsettings-logohelp { font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
|
|
25
|
+
& .crisp-workspacegeneralsettings-logotext { display: flex; flex-direction: column; align-items: flex-start; gap: ${tokens_1.contract.space["1"]}; }
|
|
26
|
+
|
|
27
|
+
/* Name + Slug sit side by side, each ~half the content width. */
|
|
28
|
+
& .crisp-workspacegeneralsettings-fieldrow { display: flex; gap: ${tokens_1.contract.space["4"]}; }
|
|
29
|
+
& .crisp-workspacegeneralsettings-fieldrow > * { flex: 1; min-width: 0; }
|
|
30
|
+
& .crisp-workspacegeneralsettings-slugfield { display: flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; }
|
|
31
|
+
& .crisp-workspacegeneralsettings-slugfield > :first-child { flex: 1; min-width: 0; }
|
|
32
|
+
& .crisp-workspacegeneralsettings-copybtn { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 32px; height: 32px; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; font-family: inherit; color: ${tokens_1.contract.fgMuted}; cursor: pointer; }
|
|
33
|
+
& .crisp-workspacegeneralsettings-copybtn:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
|
|
34
|
+
|
|
35
|
+
/* Export-data empty state -- measured: 14/500/63%-opacity, centred in a
|
|
36
|
+
40px row, no border of its own (the Table wrapper already draws it). */
|
|
37
|
+
& .crisp-workspacegeneralsettings-emptyrow { padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["4"]}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); text-align: center; }
|
|
38
|
+
|
|
39
|
+
/* Danger zone: a red-tinted bordered row, distinct from every other
|
|
40
|
+
card on the page. */
|
|
41
|
+
& .crisp-workspacegeneralsettings-dangerrow { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["6"]}; padding: ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["4"]}; border: 1px solid color-mix(in srgb, ${tokens_1.contract.bgDanger} 30%, transparent); border-radius: 12px; background: color-mix(in srgb, ${tokens_1.contract.bgDanger} 6%, transparent); }
|
|
42
|
+
& .crisp-workspacegeneralsettings-dangertext { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["1"]}; }
|
|
43
|
+
& .crisp-workspacegeneralsettings-rowtitle { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
|
|
44
|
+
& .crisp-workspacegeneralsettings-dangerwarning { font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
|
|
45
|
+
`,
|
|
46
|
+
variants: {},
|
|
47
|
+
defaultVariants: {},
|
|
48
|
+
compoundVariants: [],
|
|
49
|
+
});
|
|
50
|
+
exports.workspacegeneralsettingsRecipe = (0, core_1.resolveRecipe)(config);
|
|
51
|
+
exports.default = config;
|
|
@@ -15,9 +15,11 @@ const contract_1 = require("./contract");
|
|
|
15
15
|
*/
|
|
16
16
|
exports.elevation = {
|
|
17
17
|
/**
|
|
18
|
-
* Tier 1 — anything floating and *attached*:
|
|
18
|
+
* Tier 1 — anything floating and *attached*: popovers, dropdowns,
|
|
19
19
|
* hover-preview cards, the floating sidebar, the record peek, drawers, the
|
|
20
20
|
* bulk bar. Pairs with a 10–12px radius and, for panels, an 8px gutter.
|
|
21
|
+
* NOT `Menu` (your-moon/crisp#934) -- that moved to
|
|
22
|
+
* `selectFloating`, seed-design's own flat shadow, below.
|
|
21
23
|
*/
|
|
22
24
|
floating: `inset 0 0 0 1px ${contract_1.contract.ringPopover}, 0 0 0 1px ${contract_1.contract.shadowPopover1}, 0 4px 8px -4px ${contract_1.contract.shadowPopover2}, 0 4px 12px -2px ${contract_1.contract.shadowPopover3}`,
|
|
23
25
|
/**
|
|
@@ -60,10 +62,11 @@ exports.elevation = {
|
|
|
60
62
|
*/
|
|
61
63
|
fieldNoRing: `0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04)`,
|
|
62
64
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
65
|
+
* Seed-design's own `$shadow.s3`, a single flat layer, NOT `floating`
|
|
66
|
+
* above. Originally Select's own listbox shadow (crisp/#867); also `Menu`'s
|
|
67
|
+
* (your-moon/crisp#934) -- the raw seed dump confirms Menu
|
|
68
|
+
* is the one component seed's own spec gives a shadow to at all, and it's
|
|
69
|
+
* this exact value. Despite the name, not exclusive to Select.
|
|
67
70
|
*/
|
|
68
71
|
selectFloating: `0 4px 16px ${contract_1.contract.shadowSelect}`,
|
|
69
72
|
};
|
|
@@ -66,14 +66,34 @@ exports.palette = {
|
|
|
66
66
|
ringBrandSoft: { light: "#d6e5ff", dark: "#212224" },
|
|
67
67
|
tileActive: { light: "#ffffff", dark: "#101112" },
|
|
68
68
|
tileActiveShadow: { light: "rgba(0,0,0,0.04)", dark: "rgba(0,0,0,0)" },
|
|
69
|
-
// Dialog's page-dimming backdrop (crisp#677
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
|
|
69
|
+
// Dialog's page-dimming backdrop (crisp#677, Attio's own measured value:
|
|
70
|
+
// `rgba(0,0,0,.25)` light, `rgba(0,0,0,.55)` dark — `Dialog`'s own backdrop
|
|
71
|
+
// had shipped fully `transparent`, AUTHORING's Lesson 14 measured the
|
|
72
|
+
// command palette has NO dark backdrop and that got generalized to every
|
|
73
|
+
// `Dialog`, which this corrected).
|
|
74
|
+
//
|
|
75
|
+
// your-moon/crisp#934: light theme moved to seed-design's own scrim
|
|
76
|
+
// (`#00000074` ≈ 45% black, `bg.overlay`) — the owner's flat-dialog
|
|
77
|
+
// directive names "seed's own scrim" specifically, now that elevation is
|
|
78
|
+
// conveyed by the scrim alone (no more frosted-glass shadow/blur). Dark
|
|
79
|
+
// theme's `.55` is UNCHANGED: seed's own token system has no separate
|
|
80
|
+
// dark-theme scrim value to adopt, and `.55` wasn't found wrong -- only
|
|
81
|
+
// light had a sourced replacement value to move to.
|
|
82
|
+
bgScrim: { light: "rgba(0,0,0,0.45)", dark: "rgba(0,0,0,0.55)" },
|
|
83
|
+
// seed-design's `$color.bg.overlay` (BottomSheet/MenuSheet's own backdrop,
|
|
84
|
+
// crisp#911) — kept as its OWN token rather than folded into `bgScrim`
|
|
85
|
+
// above, even though #934 (landed after this one was added) moved
|
|
86
|
+
// `bgScrim`'s LIGHT value to the same `#00000074`: `bgOverlayStrong` is
|
|
87
|
+
// seed's literally theme-CONSTANT value (`color.yaml` gives the same hex
|
|
88
|
+
// for both `theme-light` and `theme-dark`), while `bgScrim` still differs
|
|
89
|
+
// by theme (`.45`/`.55`) -- the two tokens express different design
|
|
90
|
+
// decisions that currently coincide in one theme only.
|
|
91
|
+
bgOverlayStrong: { light: "#00000074", dark: "#00000074" },
|
|
92
|
+
// seed-design's `$color.stroke.neutral-muted` (MenuSheet group divider,
|
|
93
|
+
// crisp#911) -- a faint alpha hairline between grouped rows, theme-flipping
|
|
94
|
+
// (`color.yaml`: `static-black-alpha-300` light / `static-white-alpha-100`
|
|
95
|
+
// dark).
|
|
96
|
+
strokeGroupDivider: { light: "#00000010", dark: "#ffffff17" },
|
|
77
97
|
// The discard-confirm's description line (crisp#677, `Dialog`'s new
|
|
78
98
|
// `variant="alert"`) — measured live, both themes, over `popoverBg`: a
|
|
79
99
|
// theme-relative alpha rather than a flat gray, so it stays legible if
|
package/dist/cjs/tokens/scale.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// Recipes MUST reference these through the contract (`c.space[...]`), never a
|
|
10
10
|
// literal px — this file is the only exception.
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.weight = exports.text = exports.font = exports.size = exports.radius = exports.space = void 0;
|
|
12
|
+
exports.tracking = exports.weight = exports.text = exports.font = exports.size = exports.radius = exports.space = void 0;
|
|
13
13
|
// Spacing: gaps, padding, margins. Keys follow the Tailwind step convention
|
|
14
14
|
// (0.5 = half a 4px step = 2px) so the numbers stay legible to consumers.
|
|
15
15
|
exports.space = {
|
|
@@ -30,13 +30,22 @@ exports.space = {
|
|
|
30
30
|
// (inputs, rows, tiles); full is the pill.
|
|
31
31
|
exports.radius = {
|
|
32
32
|
xs: "4px", // seed-design's $radius.r1 — small badge / checkbox box corner
|
|
33
|
-
|
|
33
|
+
// your-moon/crisp#919: was `7px` (Attio's own most-measured
|
|
34
|
+
// radius, 70 occurrences) -- now a pill, matching seed-design's own
|
|
35
|
+
// `chip.yaml` (`$radius.full` at every size, no size-based radius step at
|
|
36
|
+
// all, unlike Button/Badge). Same numeric value as `full` below, kept as
|
|
37
|
+
// its own named token because every one of this token's ~9 consumers
|
|
38
|
+
// (Chip, DataTable/RecordPage/RecordsTable/MultiSelect's own tag/mention
|
|
39
|
+
// rules, TableToolbar/DatePickerField's date-preset chips) reasons about
|
|
40
|
+
// "the chip corner" as its own concept, not literally "a generic pill".
|
|
41
|
+
chip: "999px",
|
|
34
42
|
sm: "6px", // chips, badges
|
|
35
43
|
md: "8px", // inputs, search box
|
|
36
44
|
lg: "9px", // rows, tiles, list items
|
|
37
45
|
xl: "12px", // overlay items (command rows)
|
|
38
46
|
"2xl": "16px", // overlay panels (command surface)
|
|
39
47
|
"3xl": "20px", // seed-design's $radius.r5 — Select's listbox corner (crisp/#867)
|
|
48
|
+
"4xl": "24px", // seed-design's $radius.r6 — BottomSheet's top corner radius (crisp/#911)
|
|
40
49
|
full: "999px", // pills
|
|
41
50
|
};
|
|
42
51
|
// Component sizing — recurring measured dimensions that are neither spacing nor
|
|
@@ -88,3 +97,36 @@ exports.weight = {
|
|
|
88
97
|
semibold: "600",
|
|
89
98
|
bold: "700", // seed-design's font-weight-bold, for the seed-styled calendar
|
|
90
99
|
};
|
|
100
|
+
// Size-based letter-spacing ramp for DISPLAY/HEADING type (18px and up —
|
|
101
|
+
// `text.*` above tops out at 16px and stays untracked). crisp's five
|
|
102
|
+
// already-shipped headings tighten as they grow — authshell 20px/-0.4px (2%
|
|
103
|
+
// of size), objectsettings 24px/-0.48px (2%), richtext 32px/-0.6px (1.875%)
|
|
104
|
+
// — all Attio-measured (Inter) and left exactly as they are; this token
|
|
105
|
+
// never touches them, or the button (-0.07px) / table-cell (-0.14px)
|
|
106
|
+
// tracking, which are body sizes, not display type. (statcard's 28px/-0.4px,
|
|
107
|
+
// 1.43%, is a looser outlier — it sets tabular numerals, not prose — and is
|
|
108
|
+
// also left alone.)
|
|
109
|
+
//
|
|
110
|
+
// crisp#909: the study at docs/study/korean/ observed that Naver and Kakao
|
|
111
|
+
// both tighten tracking as type gets bigger, and crisp's OWN large type
|
|
112
|
+
// (EmptyState's 20px title, Dialog's 18px alert title, and any future
|
|
113
|
+
// heading) had no tracking at all — it read as default, not set. The study
|
|
114
|
+
// supplied the PATTERN only, never a number: Naver/Kakao's own values are
|
|
115
|
+
// Korean-specific and were not copied. The numbers below come from rendering
|
|
116
|
+
// real Mongolian Cyrillic ("Эрсдэлийн бүртгэл", "Хяналтын самбар") in VK Sans
|
|
117
|
+
// Display — crisp's own font override, see `font.sans` above — at every
|
|
118
|
+
// display size crisp uses today (18/20/24/26/28/32px), screenshotting six
|
|
119
|
+
// candidates per size (0%, 1%, 1.5%, 2%, 2.5%, 3% of the font-size) and
|
|
120
|
+
// checking for glyph collision. None collided even at 3%, so the pre-existing
|
|
121
|
+
// 2%-of-size rule the five Attio headings already happen to follow was kept
|
|
122
|
+
// as the ramp, rounded to the nearest 0.01px — it reads as deliberately set
|
|
123
|
+
// with headroom to spare, and keeps new display type visually consistent
|
|
124
|
+
// with the Attio-measured headings already shipped.
|
|
125
|
+
exports.tracking = {
|
|
126
|
+
"18": "-0.36px",
|
|
127
|
+
"20": "-0.4px",
|
|
128
|
+
"24": "-0.48px",
|
|
129
|
+
"26": "-0.52px",
|
|
130
|
+
"28": "-0.56px",
|
|
131
|
+
"32": "-0.64px",
|
|
132
|
+
};
|
|
@@ -41,6 +41,8 @@ exports.semantic = {
|
|
|
41
41
|
bgTileActive: "tileActive",
|
|
42
42
|
shadowTileActive: "tileActiveShadow",
|
|
43
43
|
bgScrim: "bgScrim",
|
|
44
|
+
bgOverlayStrong: "bgOverlayStrong",
|
|
45
|
+
strokeGroupDivider: "strokeGroupDivider",
|
|
44
46
|
fgAlertDescription: "fgAlertDescription",
|
|
45
47
|
bgOverlayFrost: "overlayFrost",
|
|
46
48
|
shadowOverlay1: "shadowOverlay1",
|
package/dist/columncalc.css
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
.crisp-columncalc {
|
|
2
|
-
display: flex; align-items: stretch; width: 100%; height: 100%; font-family: var(--crisp-font-sans); /* Menu wraps its trigger in a flex div that sizes to content, which would
|
|
2
|
+
display: flex; align-items: stretch; width: 100%; height: 100%; font-family: var(--crisp-font-sans); /* Menu wraps its trigger in a flex div that sizes to content, which would
|
|
3
|
+
shrink the button back to its text. Make the wrapper fill too, so the
|
|
4
|
+
whole cell stays clickable. */
|
|
3
5
|
& .crisp-menu { width: 100%; height: 100%; }
|
|
4
|
-
/* No radius: the trigger fills the cell, so rounding its own corners
|
|
6
|
+
/* No radius: the trigger fills the cell, so rounding its own corners
|
|
7
|
+
leaves the cell's background showing through at the four corners as
|
|
5
8
|
soon as the hover tint paints. Everything else that fills a grid cell
|
|
6
9
|
agrees -- recordstable-sum-btn, the same summary trigger, declares no
|
|
7
10
|
radius, and datatable-grip and the embedded pickers zero theirs. An 8px
|
|
8
11
|
radius survived the chip-to-full-cell conversion and shipped rounded
|
|
9
|
-
until #282, so the spec check now guards it. */
|
|
10
|
-
/* The hit target is the WHOLE summary cell -- measured 246x36 with
|
|
12
|
+
until #282, so the spec check now guards it. */ /* The hit target is the WHOLE summary cell -- measured 246x36 with
|
|
11
13
|
padding 0 12px, not a content-sized chip. Clicking anywhere in the cell
|
|
12
14
|
opens the aggregation menu.
|
|
13
15
|
No `min-height` (crisp#834, found reproducing the footer-row-38px-
|
|
14
|
-
not-36px bug in an isolated browser test, not table.recipe.ts's own
|
|
16
|
+
not-36px bug in an isolated browser test, not table.recipe.ts's own
|
|
17
|
+
border/box-sizing, the hypothesis the issue itself flagged as
|
|
18
|
+
unconfirmed): the table cell's OWN `height: tableRow` (36px,
|
|
15
19
|
border-box) leaves 34px of content box once its 2px of top+bottom
|
|
16
20
|
border are counted, and `min-height: tableRow` here demanded 36px
|
|
17
21
|
of CONTENT height regardless -- overflowing the cell by 2px, which
|
|
18
22
|
auto-height table layout resolves by growing the whole row to fit,
|
|
19
23
|
landing at exactly the reported 38. `height: 100%` alone already
|
|
20
|
-
fills whatever the cell's real content box is (the doc comment above
|
|
24
|
+
fills whatever the cell's real content box is (the doc comment above
|
|
25
|
+
this rule's own stated intent), with nothing left demanding more. */
|
|
21
26
|
& .crisp-columncalc-trigger { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
22
27
|
& .crisp-columncalc-trigger:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
|
|
23
28
|
& .crisp-columncalc-trigger svg { flex-shrink: 0; opacity: 0.7; }
|
|
24
29
|
& .crisp-columncalc-trigger[data-align="right"] { justify-content: flex-end; }
|
|
25
30
|
& .crisp-columncalc-placeholder { overflow: hidden; text-overflow: ellipsis; }
|
|
26
31
|
& .crisp-columncalc-value { color: var(--crisp-fg-primary); font-variant-numeric: tabular-nums; }
|
|
27
|
-
/* crisp#837: re-measured live against Attio's real footer calc label --
|
|
32
|
+
/* crisp#837: re-measured live against Attio's real footer calc label --
|
|
33
|
+
14px (was 13px, `c.text.md`, fixed on the shared trigger rule above)
|
|
34
|
+
and rgba(0,0,0,.63), the same color-mix(fgPrimary, 63%) figure this
|
|
35
|
+
file's own -op label already should have used instead of the flatter
|
|
28
36
|
`fgMuted` token (a close but not measured match). */
|
|
29
37
|
& .crisp-columncalc-op { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
30
38
|
& .crisp-columncalc-section { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
@layer crisp-components {
|
|
2
2
|
.crisp-columncalc {
|
|
3
|
-
display: flex; align-items: stretch; width: 100%; height: 100%; font-family: var(--crisp-font-sans); /* Menu wraps its trigger in a flex div that sizes to content, which would
|
|
3
|
+
display: flex; align-items: stretch; width: 100%; height: 100%; font-family: var(--crisp-font-sans); /* Menu wraps its trigger in a flex div that sizes to content, which would
|
|
4
|
+
shrink the button back to its text. Make the wrapper fill too, so the
|
|
5
|
+
whole cell stays clickable. */
|
|
4
6
|
& .crisp-menu { width: 100%; height: 100%; }
|
|
5
|
-
/* No radius: the trigger fills the cell, so rounding its own corners
|
|
7
|
+
/* No radius: the trigger fills the cell, so rounding its own corners
|
|
8
|
+
leaves the cell's background showing through at the four corners as
|
|
6
9
|
soon as the hover tint paints. Everything else that fills a grid cell
|
|
7
10
|
agrees -- recordstable-sum-btn, the same summary trigger, declares no
|
|
8
11
|
radius, and datatable-grip and the embedded pickers zero theirs. An 8px
|
|
9
12
|
radius survived the chip-to-full-cell conversion and shipped rounded
|
|
10
|
-
until #282, so the spec check now guards it. */
|
|
11
|
-
/* The hit target is the WHOLE summary cell -- measured 246x36 with
|
|
13
|
+
until #282, so the spec check now guards it. */ /* The hit target is the WHOLE summary cell -- measured 246x36 with
|
|
12
14
|
padding 0 12px, not a content-sized chip. Clicking anywhere in the cell
|
|
13
15
|
opens the aggregation menu.
|
|
14
16
|
No `min-height` (crisp#834, found reproducing the footer-row-38px-
|
|
15
|
-
not-36px bug in an isolated browser test, not table.recipe.ts's own
|
|
17
|
+
not-36px bug in an isolated browser test, not table.recipe.ts's own
|
|
18
|
+
border/box-sizing, the hypothesis the issue itself flagged as
|
|
19
|
+
unconfirmed): the table cell's OWN `height: tableRow` (36px,
|
|
16
20
|
border-box) leaves 34px of content box once its 2px of top+bottom
|
|
17
21
|
border are counted, and `min-height: tableRow` here demanded 36px
|
|
18
22
|
of CONTENT height regardless -- overflowing the cell by 2px, which
|
|
19
23
|
auto-height table layout resolves by growing the whole row to fit,
|
|
20
24
|
landing at exactly the reported 38. `height: 100%` alone already
|
|
21
|
-
fills whatever the cell's real content box is (the doc comment above
|
|
25
|
+
fills whatever the cell's real content box is (the doc comment above
|
|
26
|
+
this rule's own stated intent), with nothing left demanding more. */
|
|
22
27
|
& .crisp-columncalc-trigger { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
23
28
|
& .crisp-columncalc-trigger:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
|
|
24
29
|
& .crisp-columncalc-trigger svg { flex-shrink: 0; opacity: 0.7; }
|
|
25
30
|
& .crisp-columncalc-trigger[data-align="right"] { justify-content: flex-end; }
|
|
26
31
|
& .crisp-columncalc-placeholder { overflow: hidden; text-overflow: ellipsis; }
|
|
27
32
|
& .crisp-columncalc-value { color: var(--crisp-fg-primary); font-variant-numeric: tabular-nums; }
|
|
28
|
-
/* crisp#837: re-measured live against Attio's real footer calc label --
|
|
33
|
+
/* crisp#837: re-measured live against Attio's real footer calc label --
|
|
34
|
+
14px (was 13px, `c.text.md`, fixed on the shared trigger rule above)
|
|
35
|
+
and rgba(0,0,0,.63), the same color-mix(fgPrimary, 63%) figure this
|
|
36
|
+
file's own -op label already should have used instead of the flatter
|
|
29
37
|
`fgMuted` token (a close but not measured match). */
|
|
30
38
|
& .crisp-columncalc-op { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
31
39
|
& .crisp-columncalc-section { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|