@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
|
@@ -0,0 +1,159 @@
|
|
|
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.TaskEditPopover = TaskEditPopover;
|
|
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 popover_1 = require("../../components/popover");
|
|
41
|
+
const core_1 = require("../../core");
|
|
42
|
+
const assigneepicker_1 = require("../assigneepicker/assigneepicker");
|
|
43
|
+
const recordpicker_1 = require("../recordpicker/recordpicker");
|
|
44
|
+
const taskeditpopover_recipe_1 = require("./taskeditpopover.recipe");
|
|
45
|
+
/**
|
|
46
|
+
* A task's "Edit task" popover -- measured live on app.attio.com's Tasks
|
|
47
|
+
* page: a checkbox + editable title, then a chip row (due date / assigned /
|
|
48
|
+
* add record), a "more actions" kebab, and Cancel/Save. Composes
|
|
49
|
+
* `AssigneePicker` and `RecordPicker` (both crisp#626) behind their own
|
|
50
|
+
* chips, using the same core floating primitives `Popover` itself is built
|
|
51
|
+
* on rather than `Popover` directly (its content hardcodes a 360px max
|
|
52
|
+
* width, well under this popover's own measured 800px).
|
|
53
|
+
*/
|
|
54
|
+
function TaskEditPopover({ trigger, open: openProp, defaultOpen, onOpenChange, title, onTitleChange, done = false, onToggleDone, dueDateLabel, dueDatePicker, assignee = null, users = [], onAssigneeChange, linkedRecordCount = 0, recordCandidates = [], recordCandidatesLoading, onRecordQueryChange, onSelectRecord, menu, onCancel, onSave, headingLabel: headingLabelProp, closeLabel: closeLabelProp, dueDatePlaceholder: dueDatePlaceholderProp, assignLabel: assignLabelProp, assignedToLabel: assignedToLabelProp, addRecordLabel: addRecordLabelProp, linkedRecordLabel: linkedRecordLabelProp, moreActionsLabel: moreActionsLabelProp, cancelLabel: cancelLabelProp, cancelKeyLabel: cancelKeyLabelProp, saveLabel: saveLabelProp, className, }) {
|
|
55
|
+
const headingLabel = (0, core_1.useCrispMessage)(headingLabelProp, "Edit task");
|
|
56
|
+
const closeLabel = (0, core_1.useCrispMessage)(closeLabelProp, "Close");
|
|
57
|
+
const dueDatePlaceholder = (0, core_1.useCrispMessage)(dueDatePlaceholderProp, "Set due date");
|
|
58
|
+
const assignLabel = (0, core_1.useCrispMessage)(assignLabelProp, "Assign");
|
|
59
|
+
const assignedToLabel = (0, core_1.useCrispMessage)(assignedToLabelProp, "Assigned to");
|
|
60
|
+
const addRecordLabel = (0, core_1.useCrispMessage)(addRecordLabelProp, "Add record");
|
|
61
|
+
const linkedRecordLabel = (0, core_1.useCrispMessage)(linkedRecordLabelProp, linkedRecordCount === 1
|
|
62
|
+
? "1 linked record"
|
|
63
|
+
: `${linkedRecordCount} linked records`);
|
|
64
|
+
const moreActionsLabel = (0, core_1.useCrispMessage)(moreActionsLabelProp, "More actions");
|
|
65
|
+
const cancelLabel = (0, core_1.useCrispMessage)(cancelLabelProp, "Cancel");
|
|
66
|
+
const cancelKeyLabel = (0, core_1.useCrispMessage)(cancelKeyLabelProp, "Esc");
|
|
67
|
+
const saveLabel = (0, core_1.useCrispMessage)(saveLabelProp, "Save");
|
|
68
|
+
const surfaceId = React.useId();
|
|
69
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false);
|
|
70
|
+
const open = openProp ?? internalOpen;
|
|
71
|
+
const rootRef = React.useRef(null);
|
|
72
|
+
const triggerRef = React.useRef(null);
|
|
73
|
+
const contentRef = React.useRef(null);
|
|
74
|
+
const [pos, setPos] = React.useState({});
|
|
75
|
+
const setOpen = React.useCallback((next) => {
|
|
76
|
+
if (openProp === undefined)
|
|
77
|
+
setInternalOpen(next);
|
|
78
|
+
onOpenChange?.(next);
|
|
79
|
+
}, [openProp, onOpenChange]);
|
|
80
|
+
const place = () => {
|
|
81
|
+
const el = triggerRef.current;
|
|
82
|
+
if (!el)
|
|
83
|
+
return;
|
|
84
|
+
const { style } = (0, core_1.placeFloating)({
|
|
85
|
+
rect: el.getBoundingClientRect(),
|
|
86
|
+
align: "start",
|
|
87
|
+
gap: 6,
|
|
88
|
+
flipBelow: 300,
|
|
89
|
+
anchor: el,
|
|
90
|
+
});
|
|
91
|
+
setPos(style);
|
|
92
|
+
};
|
|
93
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: reposition each time it opens
|
|
94
|
+
React.useLayoutEffect(() => {
|
|
95
|
+
if (open)
|
|
96
|
+
place();
|
|
97
|
+
}, [open]);
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
if (!open || !contentRef.current)
|
|
100
|
+
return;
|
|
101
|
+
return (0, core_1.registerFloatingLayer)(contentRef.current);
|
|
102
|
+
}, [open]);
|
|
103
|
+
React.useEffect(() => {
|
|
104
|
+
if (!open)
|
|
105
|
+
return;
|
|
106
|
+
const onDown = (e) => {
|
|
107
|
+
const target = e.target;
|
|
108
|
+
if (rootRef.current?.contains(target))
|
|
109
|
+
return;
|
|
110
|
+
if (contentRef.current?.contains(target))
|
|
111
|
+
return;
|
|
112
|
+
if ((0, core_1.isInsideLaterFloatingLayer)(target, contentRef.current))
|
|
113
|
+
return;
|
|
114
|
+
setOpen(false);
|
|
115
|
+
onCancel?.();
|
|
116
|
+
};
|
|
117
|
+
document.addEventListener("pointerdown", onDown);
|
|
118
|
+
return () => document.removeEventListener("pointerdown", onDown);
|
|
119
|
+
}, [open, setOpen, onCancel]);
|
|
120
|
+
const cancel = () => {
|
|
121
|
+
setOpen(false);
|
|
122
|
+
onCancel?.();
|
|
123
|
+
};
|
|
124
|
+
const save = () => {
|
|
125
|
+
setOpen(false);
|
|
126
|
+
onSave?.();
|
|
127
|
+
};
|
|
128
|
+
const triggerEl = React.cloneElement(trigger, {
|
|
129
|
+
ref: triggerRef,
|
|
130
|
+
"aria-haspopup": "dialog",
|
|
131
|
+
"aria-expanded": open,
|
|
132
|
+
"aria-controls": open ? surfaceId : undefined,
|
|
133
|
+
onClick: (e) => {
|
|
134
|
+
trigger.props.onClick?.(e);
|
|
135
|
+
setOpen(!open);
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ref: rootRef, style: { display: "contents" }, children: [triggerEl, open && ((0, jsx_runtime_1.jsx)(core_1.FloatingPortal, { sourceRef: rootRef, children: (0, jsx_runtime_1.jsxs)("div", { ref: contentRef, id: surfaceId, role: "dialog", "aria-label": headingLabel, className: (0, taskeditpopover_recipe_1.taskeditpopoverRecipe)({ className }), style: pos, onKeyDown: (e) => {
|
|
139
|
+
if (e.key === "Escape") {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
cancel();
|
|
142
|
+
}
|
|
143
|
+
if (e.key === "Enter" &&
|
|
144
|
+
e.metaKey === false &&
|
|
145
|
+
e.ctrlKey === false &&
|
|
146
|
+
e.target.tagName !== "TEXTAREA") {
|
|
147
|
+
// Enter saves, same as Attio's own "Save ⏎" -- but never
|
|
148
|
+
// steals it from a nested picker's own Enter-to-commit.
|
|
149
|
+
if (!(0, core_1.isInsideLaterFloatingLayer)(e.target, contentRef.current)) {
|
|
150
|
+
save();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-taskeditpopover-header", children: [(0, jsx_runtime_1.jsxs)("span", { className: "crisp-taskeditpopover-heading", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleCheckBig, { size: 16, strokeWidth: 1.75 }), headingLabel] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-taskeditpopover-close", "aria-label": closeLabel, onClick: cancel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 16, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-taskeditpopover-body", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", className: "crisp-taskeditpopover-check", checked: done, "aria-label": title, onChange: (e) => onToggleDone?.(e.target.checked) }), (0, jsx_runtime_1.jsx)("input", { type: "text", className: "crisp-taskeditpopover-title", value: title, onChange: (e) => onTitleChange?.(e.target.value) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-taskeditpopover-footer", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-taskeditpopover-chips", children: [(0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "start", "aria-label": dueDatePlaceholder, trigger: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-taskeditpopover-chip", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CalendarDays, { size: 14, strokeWidth: 1.75 }), dueDateLabel ?? dueDatePlaceholder] }), children: dueDatePicker }), (0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "start", "aria-label": assignedToLabel, trigger: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-taskeditpopover-chip", children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: "@" }), assignee != null
|
|
154
|
+
? `${assignedToLabel} ${assignee.name}`
|
|
155
|
+
: assignLabel] }), children: (0, jsx_runtime_1.jsx)(assigneepicker_1.AssigneePicker, { users: users, assignee: assignee, onAssigneeChange: onAssigneeChange }) }), (0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "start", "aria-label": addRecordLabel, trigger: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-taskeditpopover-chip", children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: "\u2197" }), linkedRecordCount > 0
|
|
156
|
+
? linkedRecordLabel
|
|
157
|
+
: addRecordLabel] }), children: (0, jsx_runtime_1.jsx)(recordpicker_1.RecordPicker, { records: recordCandidates, loading: recordCandidatesLoading, onQueryChange: onRecordQueryChange, onSelect: onSelectRecord }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-taskeditpopover-actions", children: [menu != null && ((0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "end", "aria-label": moreActionsLabel, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-taskeditpopover-kebab", "aria-label": moreActionsLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: menu })), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-taskeditpopover-cancel", onClick: cancel, children: [cancelLabel, (0, jsx_runtime_1.jsx)("kbd", { className: "crisp-taskeditpopover-key", children: cancelKeyLabel })] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-taskeditpopover-save", onClick: save, children: [saveLabel, (0, jsx_runtime_1.jsx)("kbd", { className: "crisp-taskeditpopover-key", children: "\u23CE" })] })] })] })] }) }))] }));
|
|
158
|
+
}
|
|
159
|
+
TaskEditPopover.displayName = "TaskEditPopover";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskeditpopoverRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
// The "Edit task" popover -- measured live on app.attio.com's Tasks page
|
|
7
|
+
// (click a task row): an 800px-wide floating card, radius 12, a single
|
|
8
|
+
// subtle 1px ring shadow (no blur/offset layer -- lighter than
|
|
9
|
+
// `elevation.floating`, which every other crisp overlay uses; this one
|
|
10
|
+
// really does measure as just the ring, confirmed by walking every
|
|
11
|
+
// ancestor up to the floating root). Same core floating primitives
|
|
12
|
+
// `Popover`/`savedviews` already use directly (this doesn't reuse
|
|
13
|
+
// `Popover` itself: its own `.crisp-popover-content` hardcodes a
|
|
14
|
+
// max-width of min(360px, 92vw), far under this popover's measured width).
|
|
15
|
+
//
|
|
16
|
+
// Three rows: a 44px header (icon+"Edit task", a bottom hairline divider,
|
|
17
|
+
// a close button), a body row (checkbox + editable title), and a 44px
|
|
18
|
+
// footer (the due-date/assigned/add-record chip row on the left, the
|
|
19
|
+
// kebab + Cancel/Save on the right). The chip row's own 10px/400 muted
|
|
20
|
+
// caption size and the footer buttons' matching 10px labels don't fit any
|
|
21
|
+
// existing text-scale token (closest is `text.xs` at 11px) -- raw px per
|
|
22
|
+
// Golden Rule 3's "genuinely intrinsic size" exception, same as
|
|
23
|
+
// `dialog.recipe.ts`'s own submit-key glyphs.
|
|
24
|
+
const config = (0, core_1.defineRecipe)({
|
|
25
|
+
name: "taskeditpopover",
|
|
26
|
+
// Portaled root: position/z-index/the open transition live here as raw
|
|
27
|
+
// literal CSS (not `base`, which lightningcss nests under `.${prefixed}`
|
|
28
|
+
// at BUILD time -- fine for the plain declarations below, but this exact
|
|
29
|
+
// selector text has to exist as source text for `spec-check.mjs`'s
|
|
30
|
+
// overlay-escape/animation scan, the same reason Popover/Menu/Select
|
|
31
|
+
// declare their own portaled root in `globalCss` rather than `base`).
|
|
32
|
+
globalCss: `.crisp-taskeditpopover { position: fixed; z-index: 70; pointer-events: auto; opacity: 1; transform: scale(1); transition: opacity 0.08s ease, transform 0.08s ease; @starting-style { opacity: 0; transform: scale(0.97) translateY(-4px); } }`,
|
|
33
|
+
base: `display: flex; flex-direction: column; box-sizing: border-box; width: 800px; max-width: 92vw; border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgSurface}; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.07); font-family: ${tokens_1.contract.font.sans};
|
|
34
|
+
-webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
35
|
+
|
|
36
|
+
& .crisp-taskeditpopover-header { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["2"]}; height: 44px; box-sizing: border-box; padding: 0 ${tokens_1.contract.space["2"]} 0 ${tokens_1.contract.space["3"]}; border-bottom: 1px solid ${tokens_1.contract.borderSubtle}; }
|
|
37
|
+
& .crisp-taskeditpopover-heading { display: flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
|
|
38
|
+
& .crisp-taskeditpopover-heading svg { flex-shrink: 0; color: ${tokens_1.contract.fgMuted}; }
|
|
39
|
+
& .crisp-taskeditpopover-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: ${tokens_1.contract.fgMuted}; font-family: inherit; cursor: pointer; }
|
|
40
|
+
& .crisp-taskeditpopover-close:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
|
|
41
|
+
|
|
42
|
+
& .crisp-taskeditpopover-body { display: flex; align-items: center; gap: ${tokens_1.contract.space["2.5"]}; min-height: 52px; box-sizing: border-box; padding: ${tokens_1.contract.space["3"]}; }
|
|
43
|
+
& .crisp-taskeditpopover-check { appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: ${tokens_1.contract.radius.full}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 9%, transparent); cursor: pointer; }
|
|
44
|
+
& .crisp-taskeditpopover-check:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 30%, transparent); }
|
|
45
|
+
& .crisp-taskeditpopover-check:checked { background: ${tokens_1.contract.bgBrandSolid} center / 10px no-repeat; box-shadow: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E"); }
|
|
46
|
+
& .crisp-taskeditpopover-title { flex: 1; min-width: 0; border: none; border-radius: ${tokens_1.contract.radius.sm}; outline: none; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgPrimary}; }
|
|
47
|
+
& .crisp-taskeditpopover-title:focus-visible { outline: 2px solid ${tokens_1.contract.strokeFocusRing}; outline-offset: 2px; }
|
|
48
|
+
|
|
49
|
+
& .crisp-taskeditpopover-footer { display: flex; align-items: center; justify-content: space-between; gap: ${tokens_1.contract.space["2"]}; height: 44px; box-sizing: border-box; padding: 0 ${tokens_1.contract.space["2"]} 0 ${tokens_1.contract.space["3"]}; }
|
|
50
|
+
& .crisp-taskeditpopover-chips { display: flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; min-width: 0; }
|
|
51
|
+
& .crisp-taskeditpopover-chip { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; height: 28px; box-sizing: border-box; padding: 4px 8px 4px 6px; 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; font-size: 10px; white-space: nowrap; cursor: pointer; }
|
|
52
|
+
& .crisp-taskeditpopover-chip svg { flex-shrink: 0; }
|
|
53
|
+
& .crisp-taskeditpopover-chip:hover { background: ${tokens_1.contract.bgRaised}; }
|
|
54
|
+
|
|
55
|
+
& .crisp-taskeditpopover-actions { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; flex-shrink: 0; }
|
|
56
|
+
& .crisp-taskeditpopover-kebab { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin: 0; padding: 6px; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; cursor: pointer; }
|
|
57
|
+
& .crisp-taskeditpopover-kebab:hover { background: ${tokens_1.contract.bgRaised}; }
|
|
58
|
+
& .crisp-taskeditpopover-cancel { display: inline-flex; align-items: center; gap: 6px; height: 28px; box-sizing: border-box; padding: 4px 6px 4px 8px; border: none; border-radius: ${tokens_1.contract.radius.md}; background: none; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; font-size: 10px; cursor: pointer; }
|
|
59
|
+
& .crisp-taskeditpopover-cancel:hover { background: ${tokens_1.contract.bgRaised}; }
|
|
60
|
+
& .crisp-taskeditpopover-save { display: inline-flex; align-items: center; gap: 6px; height: 28px; box-sizing: border-box; padding: 4px 6px 4px 8px; border: none; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgBrandSolid}; color: ${tokens_1.contract.fgOnBrand}; font-family: inherit; font-size: 10px; cursor: pointer; }
|
|
61
|
+
& .crisp-taskeditpopover-save:hover { background: ${tokens_1.contract.bgBrandSolidPressed}; }
|
|
62
|
+
& .crisp-taskeditpopover-key { color: color-mix(in srgb, currentColor 55%, transparent); font-size: 10px; }`,
|
|
63
|
+
variants: {},
|
|
64
|
+
defaultVariants: {},
|
|
65
|
+
compoundVariants: [],
|
|
66
|
+
});
|
|
67
|
+
exports.taskeditpopoverRecipe = (0, core_1.resolveRecipe)(config);
|
|
68
|
+
exports.default = config;
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./workspaceswitchermenu"), exports);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkspaceSwitcherMenu = WorkspaceSwitcherMenu;
|
|
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 menu_1 = require("../../components/menu");
|
|
8
|
+
const core_1 = require("../../core");
|
|
9
|
+
/**
|
|
10
|
+
* The FIXED content of Attio's own workspace-switcher popover (crisp#632) —
|
|
11
|
+
* live-measured off app.attio.com/techpartners: each workspace as a
|
|
12
|
+
* checked/unchecked row, then New workspace, then Account settings /
|
|
13
|
+
* Workspace settings, then Invite members / Upgrade Attio / Refer another
|
|
14
|
+
* team, then Apps and integrations, then Sign out — each group separated by
|
|
15
|
+
* a hairline, matching a 280px-wide popover.
|
|
16
|
+
*
|
|
17
|
+
* This is CONTENT, not a component with its own trigger/popover: pass it as
|
|
18
|
+
* `Sidebar`'s own `workspaceMenu` prop (crisp#415 already builds the real
|
|
19
|
+
* menu-button trigger/popover machinery around whatever children it's
|
|
20
|
+
* given — the workspace switcher itself has no fixed content of its own by
|
|
21
|
+
* design, since which settings exist is the consumer's; this is that fixed
|
|
22
|
+
* content, ready-made, the same way `defaultCommandItems` is for `Command`).
|
|
23
|
+
*/
|
|
24
|
+
function WorkspaceSwitcherMenu({ workspaces, currentWorkspaceId, onSelectWorkspace, onNewWorkspace, onAccountSettings, onWorkspaceSettings, onInviteMembers, onUpgradeAttio, onReferAnotherTeam, onAppsAndIntegrations, onSignOut, newWorkspaceLabel, accountSettingsLabel, workspaceSettingsLabel, inviteMembersLabel, upgradeAttioLabel, referAnotherTeamLabel, appsAndIntegrationsLabel, signOutLabel, }) {
|
|
25
|
+
const newWorkspace = (0, core_1.useCrispMessage)(newWorkspaceLabel, "New workspace");
|
|
26
|
+
const accountSettings = (0, core_1.useCrispMessage)(accountSettingsLabel, "Account settings");
|
|
27
|
+
const workspaceSettings = (0, core_1.useCrispMessage)(workspaceSettingsLabel, "Workspace settings");
|
|
28
|
+
const inviteMembers = (0, core_1.useCrispMessage)(inviteMembersLabel, "Invite members");
|
|
29
|
+
const upgradeAttio = (0, core_1.useCrispMessage)(upgradeAttioLabel, "Upgrade Attio");
|
|
30
|
+
const referAnotherTeam = (0, core_1.useCrispMessage)(referAnotherTeamLabel, "Refer another team");
|
|
31
|
+
const appsAndIntegrations = (0, core_1.useCrispMessage)(appsAndIntegrationsLabel, "Apps and integrations");
|
|
32
|
+
const signOut = (0, core_1.useCrispMessage)(signOutLabel, "Sign out");
|
|
33
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [workspaces.map((ws) => {
|
|
34
|
+
const checked = ws.id === currentWorkspaceId;
|
|
35
|
+
return ((0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "sm", shape: "rounded", tone: ws.avatarTone, children: ws.avatarLabel }), trailingIcon: checked ? ((0, jsx_runtime_1.jsx)(lucide_react_1.CircleCheck, { size: 16, strokeWidth: 1.75, className: "crisp-workspaceswitchermenu-check" })) : undefined, "aria-checked": checked, onSelect: () => onSelectWorkspace?.(ws.id), children: ws.name }, ws.id));
|
|
36
|
+
}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 16, strokeWidth: 1.75 }), onSelect: onNewWorkspace, children: newWorkspace }), (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.User, { size: 16, strokeWidth: 1.75 }), onSelect: onAccountSettings, children: accountSettings }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 16, strokeWidth: 1.75 }), onSelect: onWorkspaceSettings, children: workspaceSettings }), (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.UserPlus, { size: 16, strokeWidth: 1.75 }), onSelect: onInviteMembers, children: inviteMembers }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.CircleArrowUp, { size: 16, strokeWidth: 1.75 }), onSelect: onUpgradeAttio, children: upgradeAttio }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.HeartHandshake, { size: 16, strokeWidth: 1.75 }), onSelect: onReferAnotherTeam, children: referAnotherTeam }), (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.Grid2x2, { size: 16, strokeWidth: 1.75 }), onSelect: onAppsAndIntegrations, children: appsAndIntegrations }), (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.LogOut, { "data-rtl-flip": "", size: 16, strokeWidth: 1.75 }), onSelect: onSignOut, children: signOut })] }));
|
|
37
|
+
}
|
|
38
|
+
WorkspaceSwitcherMenu.displayName = "WorkspaceSwitcherMenu";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.workspaceswitchermenuRecipe = void 0;
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const tokens_1 = require("../../tokens");
|
|
6
|
+
/**
|
|
7
|
+
* `WorkspaceSwitcherMenu` owns almost no styling of its own — every visible
|
|
8
|
+
* pixel besides the two rules below is `Menu`/`MenuItem`'s own
|
|
9
|
+
* already-measured recipe (crisp#632):
|
|
10
|
+
* - The RTL mirror for its "Sign out" icon: `LogOut` is treated as
|
|
11
|
+
* direction-bearing (`build/spec-check.mjs`'s own DIRECTIONAL set), so
|
|
12
|
+
* it's marked and mirrored the same way ObjectPageMenu's Notifications
|
|
13
|
+
* chevron is (crisp#616) — see that file's identical recipe for why this
|
|
14
|
+
* is a plain absolute selector, not `${rtlFlipCss}`'s `&`-nesting form.
|
|
15
|
+
* - The current-workspace checkmark's colour: `.crisp-menu-item svg` already
|
|
16
|
+
* sets every menu icon to `fgMuted` (menu.recipe.ts), which is deliberate
|
|
17
|
+
* there but wrong for THIS one glyph — Attio's own is brand-coloured, not
|
|
18
|
+
* muted, to read as a status rather than a plain icon. `svg` doubled in
|
|
19
|
+
* the selector (not just the class) so it outranks that rule under equal
|
|
20
|
+
* source order instead of depending on file concatenation order.
|
|
21
|
+
*/
|
|
22
|
+
const config = (0, core_1.defineRecipe)({
|
|
23
|
+
name: "workspaceswitchermenu",
|
|
24
|
+
base: "",
|
|
25
|
+
globalCss: `
|
|
26
|
+
[dir="rtl"] .crisp-menu-item svg[data-rtl-flip] { transform: scaleX(-1); }
|
|
27
|
+
.crisp-menu-item svg.crisp-workspaceswitchermenu-check { color: ${tokens_1.contract.fgBrandContrast}; }
|
|
28
|
+
`,
|
|
29
|
+
variants: {},
|
|
30
|
+
defaultVariants: {},
|
|
31
|
+
compoundVariants: [],
|
|
32
|
+
});
|
|
33
|
+
exports.workspaceswitchermenuRecipe = (0, core_1.resolveRecipe)(config);
|
|
34
|
+
exports.default = config;
|
|
@@ -277,4 +277,31 @@ exports.palette = {
|
|
|
277
277
|
// s3 (shadow.yaml) -- the listbox's single-layer floating shadow, in place
|
|
278
278
|
// of crisp's own multi-layer `elevation.floating` for this component only.
|
|
279
279
|
selectShadow: { light: "#0000001f", dark: "#000000cc" },
|
|
280
|
+
// your-moon/crisp#998: the 12-colour tag/option-colour palette a workspace
|
|
281
|
+
// admin picks for a Select/MultiSelect option, measured live off
|
|
282
|
+
// app.attio.com's Categories multi-select field (table-cell/column-editor
|
|
283
|
+
// pill, not the larger tinted-text activity-feed variant -- see
|
|
284
|
+
// ~/grc-parity/attio-tag-palette.md). All 12 are near-white pastels with
|
|
285
|
+
// flat black text regardless of which one -- Attio's theme toggle is
|
|
286
|
+
// off-limits (same restriction every other raw entry in this file notes),
|
|
287
|
+
// so no dark variant was reachable; light is reused for dark, same as
|
|
288
|
+
// `cyan600`/`purple600`/`orange600` above already do for the same reason.
|
|
289
|
+
// Numbered 1-12 rather than named: Attio assigns them by an internal hash
|
|
290
|
+
// of the option's id, not by any hue name a consumer would recognise.
|
|
291
|
+
tagSwatch1: { light: "#fff3cc", dark: "#fff3cc" },
|
|
292
|
+
tagSwatch2: { light: "#f4fbcb", dark: "#f4fbcb" },
|
|
293
|
+
tagSwatch3: { light: "#fdf7c4", dark: "#fdf7c4" },
|
|
294
|
+
tagSwatch4: { light: "#feecf3", dark: "#feecf3" },
|
|
295
|
+
tagSwatch5: { light: "#e0fced", dark: "#e0fced" },
|
|
296
|
+
tagSwatch6: { light: "#ddf7ff", dark: "#ddf7ff" },
|
|
297
|
+
tagSwatch7: { light: "#f6f7f7", dark: "#f6f7f7" },
|
|
298
|
+
tagSwatch8: { light: "#ffebeb", dark: "#ffebeb" },
|
|
299
|
+
tagSwatch9: { light: "#feeee1", dark: "#feeee1" },
|
|
300
|
+
tagSwatch10: { light: "#e5eeff", dark: "#e5eeff" },
|
|
301
|
+
tagSwatch11: { light: "#f5f0ff", dark: "#f5f0ff" },
|
|
302
|
+
tagSwatch12: { light: "#fdedff", dark: "#fdedff" },
|
|
303
|
+
// measured alongside the palette above: flat opaque black, not `ink`
|
|
304
|
+
// (#101112) -- a genuinely different, slightly darker hex Attio uses only
|
|
305
|
+
// for this one pill's text, regardless of which of the 12 backgrounds.
|
|
306
|
+
tagSwatchInk: { light: "#000000", dark: "#000000" },
|
|
280
307
|
};
|
|
@@ -129,4 +129,24 @@ exports.semantic = {
|
|
|
129
129
|
strokeSelectDivider: "selectDivider",
|
|
130
130
|
fgSelectPlaceholder: "selectPlaceholder",
|
|
131
131
|
shadowSelect: "selectShadow",
|
|
132
|
+
/** your-moon/crisp#998: a Select/MultiSelect option's fixed tag colour
|
|
133
|
+
* (`swatch`, 1-12) -- see palette.ts's own comment on `tagSwatch1` for
|
|
134
|
+
* the measurement. Distinct from `Select`'s existing `color` (an
|
|
135
|
+
* arbitrary-CSS status dot) and `MultiSelect`'s existing `tone` (crisp's
|
|
136
|
+
* own semantic 7-tone chip family): this is Attio's own enumerable,
|
|
137
|
+
* workspace-admin-assigned palette, reproduced verbatim rather than
|
|
138
|
+
* mapped onto either existing mechanism. */
|
|
139
|
+
bgTagSwatch1: "tagSwatch1",
|
|
140
|
+
bgTagSwatch2: "tagSwatch2",
|
|
141
|
+
bgTagSwatch3: "tagSwatch3",
|
|
142
|
+
bgTagSwatch4: "tagSwatch4",
|
|
143
|
+
bgTagSwatch5: "tagSwatch5",
|
|
144
|
+
bgTagSwatch6: "tagSwatch6",
|
|
145
|
+
bgTagSwatch7: "tagSwatch7",
|
|
146
|
+
bgTagSwatch8: "tagSwatch8",
|
|
147
|
+
bgTagSwatch9: "tagSwatch9",
|
|
148
|
+
bgTagSwatch10: "tagSwatch10",
|
|
149
|
+
bgTagSwatch11: "tagSwatch11",
|
|
150
|
+
bgTagSwatch12: "tagSwatch12",
|
|
151
|
+
fgTagSwatch: "tagSwatchInk",
|
|
132
152
|
};
|
package/dist/datatable.css
CHANGED
|
@@ -290,14 +290,29 @@
|
|
|
290
290
|
Avatar's own already-shipped shape="rounded" value, not a new number.
|
|
291
291
|
shape="circle" reuses Avatar's own shape="circle" value (radius.full)
|
|
292
292
|
the same way, measured live on a real Attio person avatar. */
|
|
293
|
-
& .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: 30%; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-
|
|
293
|
+
& .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: 30%; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-tone); background: var(--crisp-bg-brand-solid); }
|
|
294
294
|
& .crisp-datatable-avatar[data-shape="circle"] { border-radius: var(--crisp-radius-full); }
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
295
|
+
/* your-moon/crisp#891: every data-tone override painted ONLY a
|
|
296
|
+
background, inheriting the base rule's white fgOnBrand -- white
|
|
297
|
+
clears AA against none of these seven fills (brand 3.23:1, success
|
|
298
|
+
3.96, warning 4.12, danger 3.76, purple 3.58, cyan 2.30, orange
|
|
299
|
+
2.77). fgOnTone (ink, #101112 -- semantic.ts's own comment: "dark ink
|
|
300
|
+
clears AA on every tone in both themes") clears 4.5:1+ on every fill
|
|
301
|
+
here with a comfortable margin (brand 5.85, success 4.77/6.29,
|
|
302
|
+
danger 5.03/6.19, purple 5.27, cyan 8.23, orange 6.83, light/dark),
|
|
303
|
+
so the base rule's colour moves there and every override keeps it --
|
|
304
|
+
EXCEPT warning, whose raw fill (bgWarning) only clears 4.59:1 in
|
|
305
|
+
light, too thin a margin to rely on: it takes bgWarningSolid instead,
|
|
306
|
+
the same solid-warning-plus-ink pair Badge's own solid variant
|
|
307
|
+
already established (13.98/7.83), for the same reason (see
|
|
308
|
+
tokens/palette.ts's amberSolid comment). No background changes
|
|
309
|
+
otherwise -- the fills themselves are unaffected, only the text. */
|
|
310
|
+
& .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); color: var(--crisp-fg-on-tone); }
|
|
311
|
+
& .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning-solid); color: var(--crisp-fg-on-tone); }
|
|
312
|
+
& .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); color: var(--crisp-fg-on-tone); }
|
|
313
|
+
& .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); color: var(--crisp-fg-on-tone); }
|
|
314
|
+
& .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); color: var(--crisp-fg-on-tone); }
|
|
315
|
+
& .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); color: var(--crisp-fg-on-tone); }
|
|
301
316
|
& .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
|
|
302
317
|
& .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
|
|
303
318
|
& .crisp-datatable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
@@ -308,6 +323,24 @@
|
|
|
308
323
|
& .crisp-datatable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); }
|
|
309
324
|
& .crisp-datatable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); }
|
|
310
325
|
& .crisp-datatable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); }
|
|
326
|
+
/* your-moon/crisp#998: Attio's own 12-colour tag palette (measured
|
|
327
|
+
live, see tokens/palette.ts's tagSwatch1 comment) -- flat black
|
|
328
|
+
text, no ring, unlike the tone family above. 7px radius/10px text
|
|
329
|
+
are measured literals (no matching step in the shared scale, same
|
|
330
|
+
as Select's own .crisp-select-swatch). */
|
|
331
|
+
& .crisp-datatable-swatch { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: 7px; font-size: 10px; font-weight: var(--crisp-weight-regular); white-space: nowrap; color: var(--crisp-fg-tag-swatch); }
|
|
332
|
+
& .crisp-datatable-swatch[data-swatch="1"] { background: var(--crisp-bg-tag-swatch1); }
|
|
333
|
+
& .crisp-datatable-swatch[data-swatch="2"] { background: var(--crisp-bg-tag-swatch2); }
|
|
334
|
+
& .crisp-datatable-swatch[data-swatch="3"] { background: var(--crisp-bg-tag-swatch3); }
|
|
335
|
+
& .crisp-datatable-swatch[data-swatch="4"] { background: var(--crisp-bg-tag-swatch4); }
|
|
336
|
+
& .crisp-datatable-swatch[data-swatch="5"] { background: var(--crisp-bg-tag-swatch5); }
|
|
337
|
+
& .crisp-datatable-swatch[data-swatch="6"] { background: var(--crisp-bg-tag-swatch6); }
|
|
338
|
+
& .crisp-datatable-swatch[data-swatch="7"] { background: var(--crisp-bg-tag-swatch7); }
|
|
339
|
+
& .crisp-datatable-swatch[data-swatch="8"] { background: var(--crisp-bg-tag-swatch8); }
|
|
340
|
+
& .crisp-datatable-swatch[data-swatch="9"] { background: var(--crisp-bg-tag-swatch9); }
|
|
341
|
+
& .crisp-datatable-swatch[data-swatch="10"] { background: var(--crisp-bg-tag-swatch10); }
|
|
342
|
+
& .crisp-datatable-swatch[data-swatch="11"] { background: var(--crisp-bg-tag-swatch11); }
|
|
343
|
+
& .crisp-datatable-swatch[data-swatch="12"] { background: var(--crisp-bg-tag-swatch12); }
|
|
311
344
|
& .crisp-datatable-num { font-variant-numeric: tabular-nums; }
|
|
312
345
|
& .crisp-datatable-muted { color: var(--crisp-fg-muted); }
|
|
313
346
|
/* crisp#822 -- a date/datetime cell's danger/overdue tone: same token as
|
|
@@ -291,14 +291,29 @@
|
|
|
291
291
|
Avatar's own already-shipped shape="rounded" value, not a new number.
|
|
292
292
|
shape="circle" reuses Avatar's own shape="circle" value (radius.full)
|
|
293
293
|
the same way, measured live on a real Attio person avatar. */
|
|
294
|
-
& .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: 30%; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-
|
|
294
|
+
& .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: 30%; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-tone); background: var(--crisp-bg-brand-solid); }
|
|
295
295
|
& .crisp-datatable-avatar[data-shape="circle"] { border-radius: var(--crisp-radius-full); }
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
296
|
+
/* your-moon/crisp#891: every data-tone override painted ONLY a
|
|
297
|
+
background, inheriting the base rule's white fgOnBrand -- white
|
|
298
|
+
clears AA against none of these seven fills (brand 3.23:1, success
|
|
299
|
+
3.96, warning 4.12, danger 3.76, purple 3.58, cyan 2.30, orange
|
|
300
|
+
2.77). fgOnTone (ink, #101112 -- semantic.ts's own comment: "dark ink
|
|
301
|
+
clears AA on every tone in both themes") clears 4.5:1+ on every fill
|
|
302
|
+
here with a comfortable margin (brand 5.85, success 4.77/6.29,
|
|
303
|
+
danger 5.03/6.19, purple 5.27, cyan 8.23, orange 6.83, light/dark),
|
|
304
|
+
so the base rule's colour moves there and every override keeps it --
|
|
305
|
+
EXCEPT warning, whose raw fill (bgWarning) only clears 4.59:1 in
|
|
306
|
+
light, too thin a margin to rely on: it takes bgWarningSolid instead,
|
|
307
|
+
the same solid-warning-plus-ink pair Badge's own solid variant
|
|
308
|
+
already established (13.98/7.83), for the same reason (see
|
|
309
|
+
tokens/palette.ts's amberSolid comment). No background changes
|
|
310
|
+
otherwise -- the fills themselves are unaffected, only the text. */
|
|
311
|
+
& .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); color: var(--crisp-fg-on-tone); }
|
|
312
|
+
& .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning-solid); color: var(--crisp-fg-on-tone); }
|
|
313
|
+
& .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); color: var(--crisp-fg-on-tone); }
|
|
314
|
+
& .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); color: var(--crisp-fg-on-tone); }
|
|
315
|
+
& .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); color: var(--crisp-fg-on-tone); }
|
|
316
|
+
& .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); color: var(--crisp-fg-on-tone); }
|
|
302
317
|
& .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
|
|
303
318
|
& .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
|
|
304
319
|
& .crisp-datatable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
@@ -309,6 +324,24 @@
|
|
|
309
324
|
& .crisp-datatable-tag[data-tone="purple"] { background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); }
|
|
310
325
|
& .crisp-datatable-tag[data-tone="cyan"] { background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); }
|
|
311
326
|
& .crisp-datatable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); }
|
|
327
|
+
/* your-moon/crisp#998: Attio's own 12-colour tag palette (measured
|
|
328
|
+
live, see tokens/palette.ts's tagSwatch1 comment) -- flat black
|
|
329
|
+
text, no ring, unlike the tone family above. 7px radius/10px text
|
|
330
|
+
are measured literals (no matching step in the shared scale, same
|
|
331
|
+
as Select's own .crisp-select-swatch). */
|
|
332
|
+
& .crisp-datatable-swatch { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: 7px; font-size: 10px; font-weight: var(--crisp-weight-regular); white-space: nowrap; color: var(--crisp-fg-tag-swatch); }
|
|
333
|
+
& .crisp-datatable-swatch[data-swatch="1"] { background: var(--crisp-bg-tag-swatch1); }
|
|
334
|
+
& .crisp-datatable-swatch[data-swatch="2"] { background: var(--crisp-bg-tag-swatch2); }
|
|
335
|
+
& .crisp-datatable-swatch[data-swatch="3"] { background: var(--crisp-bg-tag-swatch3); }
|
|
336
|
+
& .crisp-datatable-swatch[data-swatch="4"] { background: var(--crisp-bg-tag-swatch4); }
|
|
337
|
+
& .crisp-datatable-swatch[data-swatch="5"] { background: var(--crisp-bg-tag-swatch5); }
|
|
338
|
+
& .crisp-datatable-swatch[data-swatch="6"] { background: var(--crisp-bg-tag-swatch6); }
|
|
339
|
+
& .crisp-datatable-swatch[data-swatch="7"] { background: var(--crisp-bg-tag-swatch7); }
|
|
340
|
+
& .crisp-datatable-swatch[data-swatch="8"] { background: var(--crisp-bg-tag-swatch8); }
|
|
341
|
+
& .crisp-datatable-swatch[data-swatch="9"] { background: var(--crisp-bg-tag-swatch9); }
|
|
342
|
+
& .crisp-datatable-swatch[data-swatch="10"] { background: var(--crisp-bg-tag-swatch10); }
|
|
343
|
+
& .crisp-datatable-swatch[data-swatch="11"] { background: var(--crisp-bg-tag-swatch11); }
|
|
344
|
+
& .crisp-datatable-swatch[data-swatch="12"] { background: var(--crisp-bg-tag-swatch12); }
|
|
312
345
|
& .crisp-datatable-num { font-variant-numeric: tabular-nums; }
|
|
313
346
|
& .crisp-datatable-muted { color: var(--crisp-fg-muted); }
|
|
314
347
|
/* crisp#822 -- a date/datetime cell's danger/overdue tone: same token as
|
|
@@ -132,19 +132,24 @@ const spec = defineSpec({
|
|
|
132
132
|
// shape="icon" already does for every other size, so it needs no
|
|
133
133
|
// extra rule), 4px gap between multiple children.
|
|
134
134
|
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
135
|
+
// Follow-up correction (still #688): the label is 12px/500(medium)/
|
|
136
|
+
// 16px line-height/normal tracking -- NOT #682's 14px button tracking,
|
|
137
|
+
// and NOT the 10px/regular/15px this file shipped with first. That
|
|
138
|
+
// first pass read getComputedStyle on the `<button>` element itself;
|
|
139
|
+
// Attio's actual label lives in an inner `<div>` that overrides
|
|
140
|
+
// font-size/weight/line-height on top of it (confirmed by walking the
|
|
141
|
+
// full child tree, on "View all" AND "Today, <date>", both Home and
|
|
142
|
+
// the savedviews toolbar's own "Save for everyone") -- the outer
|
|
143
|
+
// button's own 10px/400/15px is real but never what's on screen.
|
|
144
|
+
// 12px is already `c.text.sm` and 500 is already the base's own
|
|
145
|
+
// default `fontWeight` (no override needed for either); only
|
|
146
|
+
// line-height and tracking still diverge from the base's 20px/
|
|
147
|
+
// -0.07px and need their own values here.
|
|
142
148
|
xs: {
|
|
143
149
|
height: "20px",
|
|
144
150
|
paddingInline: c.space["1.5"],
|
|
145
|
-
fontSize:
|
|
146
|
-
|
|
147
|
-
lineHeight: "15px",
|
|
151
|
+
fontSize: c.text.sm,
|
|
152
|
+
lineHeight: "16px",
|
|
148
153
|
letterSpacing: "normal",
|
|
149
154
|
borderRadius: c.radius.sm,
|
|
150
155
|
gap: c.space["1"],
|
|
@@ -390,14 +390,17 @@ function renderTyped(col, value, avatarTone, row, display, locale = "en-US", ope
|
|
|
390
390
|
const tags = Array.isArray(value) ? value : [];
|
|
391
391
|
if (!tags.length)
|
|
392
392
|
return empty;
|
|
393
|
-
return (_jsx("span", { className: "crisp-datatable-tags", children: tags.map((t) => (_jsx("span", { className: "crisp-datatable-tag", "data-tone": col.tones?.[t] ?? toneFor(t), children: t }, t))) }));
|
|
393
|
+
return (_jsx("span", { className: "crisp-datatable-tags", children: tags.map((t) => col.swatches?.[t] ? (_jsx("span", { className: "crisp-datatable-swatch", "data-swatch": col.swatches[t], children: t }, t)) : (_jsx("span", { className: "crisp-datatable-tag", "data-tone": col.tones?.[t] ?? toneFor(t), children: t }, t))) }));
|
|
394
394
|
}
|
|
395
395
|
case "status": {
|
|
396
396
|
const s = asText(value);
|
|
397
397
|
if (!s)
|
|
398
398
|
return empty;
|
|
399
|
-
// tone is looked up by the RAW status, so formatting the label
|
|
400
|
-
// translation) can never silently repaint the chip
|
|
399
|
+
// tone/swatch is looked up by the RAW status, so formatting the label
|
|
400
|
+
// (casing, translation) can never silently repaint the chip
|
|
401
|
+
if (col.swatches?.[s]) {
|
|
402
|
+
return (_jsx("span", { className: "crisp-datatable-swatch", "data-swatch": col.swatches[s], children: display || s }));
|
|
403
|
+
}
|
|
401
404
|
return (_jsx("span", { className: "crisp-datatable-tag", "data-tone": col.tones?.[s] ?? toneFor(s), children: display || s }));
|
|
402
405
|
}
|
|
403
406
|
case "rating": {
|