@crisp-ui-kit/crisp 0.54.7 → 0.54.8
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 +5 -1
- package/dist/authshell.layered.css +5 -1
- package/dist/badge.css +5 -5
- package/dist/badge.layered.css +5 -5
- package/dist/board.css +13 -9
- package/dist/board.layered.css +13 -9
- package/dist/button.css +3 -1
- package/dist/button.layered.css +3 -1
- package/dist/cjs/components/badge/badge.recipe.js +28 -5
- package/dist/cjs/components/button/button.js +33 -2
- package/dist/cjs/components/button/button.recipe.js +31 -5
- package/dist/cjs/components/datatable/datatable.js +66 -7
- package/dist/cjs/components/datatable/datatable.recipe.js +57 -2
- package/dist/cjs/components/dialog/dialog.js +8 -5
- package/dist/cjs/components/dialog/dialog.recipe.js +15 -1
- package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +12 -3
- package/dist/cjs/components/tabletoolbar/tabletoolbar.js +231 -48
- package/dist/cjs/components/tabletoolbar/tabletoolbar.recipe.js +44 -0
- package/dist/cjs/components/tabs/tabs.recipe.js +11 -2
- package/dist/cjs/components/tooltip/tooltip.js +23 -9
- package/dist/cjs/components/tooltip/tooltip.recipe.js +10 -9
- package/dist/cjs/product/authshell/authshell.js +14 -1
- package/dist/cjs/product/authshell/authshell.recipe.js +13 -1
- package/dist/cjs/product/board/board.js +122 -27
- package/dist/cjs/product/board/board.recipe.js +14 -2
- package/dist/cjs/product/comments/comments.js +23 -10
- package/dist/cjs/product/comments/comments.recipe.js +17 -3
- package/dist/cjs/product/formdialog/formdialog.js +10 -4
- package/dist/cjs/product/navitem/navitem.js +7 -2
- package/dist/cjs/product/navitem/navitem.recipe.js +16 -0
- package/dist/cjs/product/objectsettings/index.js +1 -2
- package/dist/cjs/product/objectsettings/objectsettings.js +3 -13
- package/dist/cjs/product/richtext/richtext.js +76 -1
- package/dist/cjs/product/sidebar/sidebar.js +68 -15
- package/dist/cjs/product/sidebar/sidebar.recipe.js +6 -1
- package/dist/cjs/tokens/palette.js +32 -1
- package/dist/cjs/tokens/semantic.js +11 -0
- package/dist/comments.css +36 -10
- package/dist/comments.layered.css +36 -10
- package/dist/datatable.css +47 -9
- package/dist/datatable.layered.css +47 -9
- package/dist/dialog.css +13 -1
- package/dist/dialog.layered.css +13 -1
- package/dist/esm/components/badge/badge.recipe.js +28 -5
- package/dist/esm/components/button/button.js +34 -3
- package/dist/esm/components/button/button.recipe.js +31 -5
- package/dist/esm/components/datatable/datatable.js +67 -8
- package/dist/esm/components/datatable/datatable.recipe.js +57 -2
- package/dist/esm/components/dialog/dialog.js +8 -5
- package/dist/esm/components/dialog/dialog.recipe.js +15 -1
- package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +12 -3
- package/dist/esm/components/tabletoolbar/tabletoolbar.js +231 -48
- package/dist/esm/components/tabletoolbar/tabletoolbar.recipe.js +44 -0
- package/dist/esm/components/tabs/tabs.recipe.js +11 -2
- package/dist/esm/components/tooltip/tooltip.js +23 -9
- package/dist/esm/components/tooltip/tooltip.recipe.js +10 -9
- package/dist/esm/product/authshell/authshell.js +15 -2
- package/dist/esm/product/authshell/authshell.recipe.js +13 -1
- package/dist/esm/product/authshell/index.js +1 -1
- package/dist/esm/product/board/board.js +122 -27
- package/dist/esm/product/board/board.recipe.js +14 -2
- package/dist/esm/product/comments/comments.js +23 -10
- package/dist/esm/product/comments/comments.recipe.js +17 -3
- package/dist/esm/product/formdialog/formdialog.js +10 -4
- package/dist/esm/product/navitem/index.js +1 -1
- package/dist/esm/product/navitem/navitem.js +7 -2
- package/dist/esm/product/navitem/navitem.recipe.js +16 -0
- package/dist/esm/product/objectsettings/index.js +1 -1
- package/dist/esm/product/objectsettings/objectsettings.js +2 -12
- package/dist/esm/product/richtext/richtext.js +76 -1
- package/dist/esm/product/sidebar/sidebar.js +69 -16
- package/dist/esm/product/sidebar/sidebar.recipe.js +6 -1
- package/dist/esm/tokens/palette.js +32 -1
- package/dist/esm/tokens/semantic.js +11 -0
- package/dist/native/tokens.d.ts +1 -1
- package/dist/native/tokens.js +16 -2
- package/dist/navitem.css +7 -0
- package/dist/navitem.layered.css +7 -0
- package/dist/recordstable.css +1 -1
- package/dist/recordstable.layered.css +1 -1
- package/dist/sidebar.css +6 -1
- package/dist/sidebar.layered.css +6 -1
- package/dist/styles.css +163 -42
- package/dist/styles.layered.css +163 -42
- package/dist/tabletoolbar.css +16 -1
- package/dist/tabletoolbar.layered.css +16 -1
- package/dist/tabs.css +1 -1
- package/dist/tabs.layered.css +1 -1
- package/dist/tokens.css +9 -1
- package/dist/tokens.json +16 -2
- package/dist/tooltip.css +1 -1
- package/dist/tooltip.layered.css +1 -1
- package/dist/types/components/badge/badge.recipe.d.ts +5 -1
- package/dist/types/components/button/button.recipe.d.ts +18 -5
- package/dist/types/components/datatable/datatable.d.ts +9 -0
- package/dist/types/components/dialog/dialog.d.ts +25 -2
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +43 -3
- package/dist/types/components/tooltip/tooltip.d.ts +12 -4
- package/dist/types/components/tooltip/tooltip.recipe.d.ts +1 -1
- package/dist/types/product/authshell/authshell.d.ts +26 -2
- package/dist/types/product/authshell/index.d.ts +1 -1
- package/dist/types/product/board/board.d.ts +5 -4
- package/dist/types/product/comments/comments.d.ts +10 -2
- package/dist/types/product/formdialog/formdialog.d.ts +2 -1
- package/dist/types/product/navitem/index.d.ts +1 -1
- package/dist/types/product/navitem/navitem.d.ts +23 -0
- package/dist/types/product/objectsettings/index.d.ts +1 -1
- package/dist/types/product/objectsettings/objectsettings.d.ts +0 -10
- package/dist/types/product/sidebar/sidebar.d.ts +33 -5
- package/dist/types/tokens/contract.d.ts +4 -0
- package/dist/types/tokens/palette.d.ts +13 -1
- package/dist/types/tokens/semantic.d.ts +11 -0
- package/package.json +1 -1
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AuthShell = AuthShell;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
5
6
|
const authshell_recipe_1 = require("./authshell.recipe");
|
|
7
|
+
/** A plain `{ icon, title }` object (not a React element) — the shape
|
|
8
|
+
* `logo` renders as `AuthShell`'s own icon-badge + wordmark layout, as
|
|
9
|
+
* opposed to a caller-supplied node it just centers as-is. Same test
|
|
10
|
+
* `sidebar.tsx`'s `isSidebarFooterCopy` already uses for its own "plain
|
|
11
|
+
* shape vs. any node" prop. */
|
|
12
|
+
function isAuthShellBrand(value) {
|
|
13
|
+
return (typeof value === "object" &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
!(0, react_1.isValidElement)(value) &&
|
|
16
|
+
"icon" in value &&
|
|
17
|
+
"title" in value);
|
|
18
|
+
}
|
|
6
19
|
/**
|
|
7
20
|
* The welcome/auth layout — measured live.
|
|
8
21
|
* A centered page frame: an optional top progress bar, a logo, a two-pane
|
|
@@ -16,6 +29,6 @@ function AuthShell({ progress, logo, title, children, preview, footer, className
|
|
|
16
29
|
const pct = hasProgress
|
|
17
30
|
? Math.round(Math.max(0, Math.min(1, progress)) * 100)
|
|
18
31
|
: 0;
|
|
19
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, authshell_recipe_1.authshellRecipe)({ className }), "data-single-pane": preview == null ? "" : undefined, ...rest, children: [hasProgress && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-progress", role: "progressbar", "aria-valuenow": pct, "aria-valuemin": 0, "aria-valuemax": 100, children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-progress-fill", style: { width: `${pct}%` } }) })), logo != null && (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-logo", children: logo }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-authshell-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-pane", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-authshell-body", children: [title != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-title", children: title })), (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-form", children: children })] }) }), preview != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-preview", children: preview }))] }), footer != null && (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-footer", children: footer })] }));
|
|
32
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, authshell_recipe_1.authshellRecipe)({ className }), "data-single-pane": preview == null ? "" : undefined, ...rest, children: [hasProgress && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-progress", role: "progressbar", "aria-valuenow": pct, "aria-valuemin": 0, "aria-valuemax": 100, children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-progress-fill", style: { width: `${pct}%` } }) })), logo != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-logo", children: isAuthShellBrand(logo) ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-logo-badge", children: logo.icon }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-authshell-logo-text", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-logo-title", children: logo.title }), logo.subtitle != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-logo-subtitle", children: logo.subtitle }))] })] })) : (logo) })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-authshell-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-pane", children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-authshell-body", children: [title != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-title", children: title })), (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-form", children: children })] }) }), preview != null && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-preview", children: preview }))] }), footer != null && (0, jsx_runtime_1.jsx)("div", { className: "crisp-authshell-footer", children: footer })] }));
|
|
20
33
|
}
|
|
21
34
|
AuthShell.displayName = "AuthShell";
|
|
@@ -23,6 +23,14 @@ const tokens_1 = require("../../tokens");
|
|
|
23
23
|
// roughly centred in the viewport rather than pinned near the top.
|
|
24
24
|
// `data-single-pane` now drops the card chrome and narrows the body to
|
|
25
25
|
// match; the two-pane card is unchanged.
|
|
26
|
+
//
|
|
27
|
+
// your-moon/crisp#722: `.crisp-authshell-logo` is `min-height: 24px`, not
|
|
28
|
+
// `height` -- Attio's own mark (a single flat 96x24 SVG, measured live on
|
|
29
|
+
// the logged-out `/login` page) fits exactly at 24px, but a fixed height
|
|
30
|
+
// clipped any consumer logo taller than that. Found via internal/grc's real
|
|
31
|
+
// lockup (an icon badge beside a two-line TECH/tagline wordmark, ~36px
|
|
32
|
+
// tall), silently cut down to a bare one-line span rather than reported as
|
|
33
|
+
// not fitting.
|
|
26
34
|
const config = (0, core_1.defineRecipe)({
|
|
27
35
|
name: "authshell",
|
|
28
36
|
base: `min-height: 100%; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; position: relative;
|
|
@@ -34,7 +42,11 @@ const config = (0, core_1.defineRecipe)({
|
|
|
34
42
|
& .crisp-authshell-progress { position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: ${tokens_1.contract.borderDefault}; }
|
|
35
43
|
& .crisp-authshell-progress-fill { height: 2px; background: ${tokens_1.contract.fgPrimary}; border-radius: 4px; transition: width .2s; }
|
|
36
44
|
|
|
37
|
-
& .crisp-authshell-logo { margin-top: ${tokens_1.contract.space["8"]}; height: 24px; display: flex; align-items: center; }
|
|
45
|
+
& .crisp-authshell-logo { margin-top: ${tokens_1.contract.space["8"]}; min-height: 24px; display: flex; align-items: center; gap: ${tokens_1.contract.space["2.5"]}; }
|
|
46
|
+
& .crisp-authshell-logo-badge { flex-shrink: 0; box-sizing: border-box; width: 32px; height: 32px; border-radius: ${tokens_1.contract.radius.md}; background: ${tokens_1.contract.bgBrandSolid}; color: #fff; display: flex; align-items: center; justify-content: center; }
|
|
47
|
+
& .crisp-authshell-logo-text { display: flex; flex-direction: column; line-height: 1.2; }
|
|
48
|
+
& .crisp-authshell-logo-title { font-size: ${tokens_1.contract.text.xl}; font-weight: ${tokens_1.contract.weight.bold}; letter-spacing: -0.2px; color: ${tokens_1.contract.fgPrimary}; }
|
|
49
|
+
& .crisp-authshell-logo-subtitle { font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; }
|
|
38
50
|
|
|
39
51
|
& .crisp-authshell-card { margin-top: ${tokens_1.contract.space["6"]}; display: flex; height: 692px; border-radius: 20px; border: 1px solid ${tokens_1.contract.borderSubtle}; overflow: hidden; }
|
|
40
52
|
&[data-single-pane] .crisp-authshell-card { height: auto; border: none; border-radius: 0; overflow: visible; }
|
|
@@ -91,10 +91,11 @@ function computeBoardAgg(agg, values) {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
|
-
* A kanban board with
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
94
|
+
* A kanban board with pointer-events drag-and-drop between columns (#674 —
|
|
95
|
+
* Attio's own mechanism, confirmed live: mousedown, several mousemoves,
|
|
96
|
+
* mouseup, no `[draggable]` anywhere). Dropping a card on a column reparents
|
|
97
|
+
* it via `onCardsChange` (the parent owns the cards, so the move is a
|
|
98
|
+
* controlled state update). Measured from a deals pipeline.
|
|
98
99
|
*/
|
|
99
100
|
function Board({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLabel: newCardLabelProp, getCardLabel, announceMove: announceMoveProp, calc, className, ...rest }) {
|
|
100
101
|
// crisp/#471: same resolution order as every other component's own —
|
|
@@ -112,11 +113,37 @@ function Board({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLa
|
|
|
112
113
|
: `${crispMessages["Moved to"] ?? "Moved to"} ${column}`);
|
|
113
114
|
const [dragId, setDragId] = React.useState(null);
|
|
114
115
|
const [overCol, setOverCol] = React.useState(null);
|
|
116
|
+
const [ghost, setGhost] = React.useState(null);
|
|
115
117
|
const [announcement, setAnnouncement] = React.useState("");
|
|
116
118
|
// the card a keyboard move just sent to another column; React unmounts and
|
|
117
119
|
// remounts it under the new parent, so focus has to be put back by hand
|
|
118
120
|
const [refocusId, setRefocusId] = React.useState(null);
|
|
119
121
|
const rootRef = React.useRef(null);
|
|
122
|
+
const colRefs = React.useRef(new Map());
|
|
123
|
+
// #674: which column a client point is over, read off each column's own
|
|
124
|
+
// rect at drag time rather than `elementFromPoint` -- the fixed-position
|
|
125
|
+
// ghost sits on top of everything (deliberately, so it never itself
|
|
126
|
+
// becomes the hit) and this is the one MEASURED interaction a test has a
|
|
127
|
+
// real handle on (`elementFromPoint` needs an actual layout engine bun
|
|
128
|
+
// test's happy-dom doesn't run).
|
|
129
|
+
//
|
|
130
|
+
// X only, not a full box: `.crisp-board`'s columns are a single
|
|
131
|
+
// non-wrapping row (`display: flex`, no `flex-wrap`), so X alone already
|
|
132
|
+
// identifies the column unambiguously. Checking Y against each column's
|
|
133
|
+
// OWN rect looked more precise but was actually a bug caught driving this
|
|
134
|
+
// in a real headed browser (Playwright), not by the tests passing --
|
|
135
|
+
// `align-items: flex-start` on the row means a short/empty column's own
|
|
136
|
+
// box ends where its content does, well short of a taller neighbour's, so
|
|
137
|
+
// a drop below that point silently found no column at all even while
|
|
138
|
+
// visually still inside the board.
|
|
139
|
+
const columnAt = (x) => {
|
|
140
|
+
for (const [id, el] of colRefs.current) {
|
|
141
|
+
const r = el.getBoundingClientRect();
|
|
142
|
+
if (x >= r.left && x <= r.right)
|
|
143
|
+
return id;
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
};
|
|
120
147
|
const move = (cardId, toColumn) => {
|
|
121
148
|
const card = cards.find((c) => c.id === cardId);
|
|
122
149
|
if (!card || card.columnId === toColumn)
|
|
@@ -132,8 +159,77 @@ function Board({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLa
|
|
|
132
159
|
setRefocusId(null);
|
|
133
160
|
}, [refocusId]);
|
|
134
161
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
162
|
+
* #674: Attio's own board drag is driven by pointer events (mousedown ->
|
|
163
|
+
* several mousemoves -> mouseup) -- confirmed live, no `[draggable]`
|
|
164
|
+
* anywhere -- not native HTML5 `draggable`/`onDragStart`, which is
|
|
165
|
+
* pointer-only by specification (no touch/pen support) and fires its own
|
|
166
|
+
* separate, browser-chrome-owned drag session crisp never controlled: no
|
|
167
|
+
* custom drag image, no way to redraw the dragged card while it moves.
|
|
168
|
+
* Pointer events give the board its own tracked drag state instead, the
|
|
169
|
+
* same primitive `resizeHandle`/`recordstable`'s own column-resize already
|
|
170
|
+
* use elsewhere in crisp.
|
|
171
|
+
*
|
|
172
|
+
* A drag doesn't "start" the instant the pointer goes down on a card --
|
|
173
|
+
* only once it has moved past a small threshold (4px). Below that, the
|
|
174
|
+
* gesture reads as a click/tap that never happened here (the card carries
|
|
175
|
+
* no click handler of its own today, but a future one would otherwise
|
|
176
|
+
* fire through a phantom near-zero-distance "drag").
|
|
177
|
+
*/
|
|
178
|
+
const dragStateRef = React.useRef(null);
|
|
179
|
+
const DRAG_THRESHOLD = 4;
|
|
180
|
+
const onCardPointerDown = (e, card) => {
|
|
181
|
+
if (!e.isPrimary)
|
|
182
|
+
return;
|
|
183
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
184
|
+
dragStateRef.current = {
|
|
185
|
+
id: card.id,
|
|
186
|
+
pointerId: e.pointerId,
|
|
187
|
+
startX: e.clientX,
|
|
188
|
+
startY: e.clientY,
|
|
189
|
+
active: false,
|
|
190
|
+
grabDx: e.clientX - r.left,
|
|
191
|
+
grabDy: e.clientY - r.top,
|
|
192
|
+
width: r.width,
|
|
193
|
+
height: r.height,
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
const onCardPointerMove = (e) => {
|
|
197
|
+
const st = dragStateRef.current;
|
|
198
|
+
if (!st || st.pointerId !== e.pointerId)
|
|
199
|
+
return;
|
|
200
|
+
if (!st.active) {
|
|
201
|
+
const dx = e.clientX - st.startX;
|
|
202
|
+
const dy = e.clientY - st.startY;
|
|
203
|
+
if (Math.hypot(dx, dy) < DRAG_THRESHOLD)
|
|
204
|
+
return;
|
|
205
|
+
st.active = true;
|
|
206
|
+
setDragId(st.id);
|
|
207
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
208
|
+
}
|
|
209
|
+
setGhost({
|
|
210
|
+
x: e.clientX - st.grabDx,
|
|
211
|
+
y: e.clientY - st.grabDy,
|
|
212
|
+
width: st.width,
|
|
213
|
+
height: st.height,
|
|
214
|
+
});
|
|
215
|
+
setOverCol(columnAt(e.clientX));
|
|
216
|
+
};
|
|
217
|
+
const endCardDrag = (e, commit) => {
|
|
218
|
+
const st = dragStateRef.current;
|
|
219
|
+
if (!st || st.pointerId !== e.pointerId)
|
|
220
|
+
return;
|
|
221
|
+
if (commit && st.active && overCol)
|
|
222
|
+
move(st.id, overCol);
|
|
223
|
+
dragStateRef.current = null;
|
|
224
|
+
setDragId(null);
|
|
225
|
+
setOverCol(null);
|
|
226
|
+
setGhost(null);
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Neither drag mechanism the board has used (the old native HTML5 kind,
|
|
230
|
+
* this file's own pointer-events one now) is reachable from a keyboard, so
|
|
231
|
+
* the board's primary action needs its own key model or it has none at
|
|
232
|
+
* all.
|
|
137
233
|
*
|
|
138
234
|
* Ctrl/Cmd + Left/Right rather than plain arrows: a screen reader owns the
|
|
139
235
|
* bare arrow keys in browse mode, and a board scrolls horizontally, so plain
|
|
@@ -151,27 +247,14 @@ function Board({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLa
|
|
|
151
247
|
};
|
|
152
248
|
return ((0, jsx_runtime_1.jsxs)("div", { ref: rootRef, className: (0, board_recipe_1.boardRecipe)({ className }), ...rest, children: [columns.map((col) => {
|
|
153
249
|
const colCards = cards.filter((c) => c.columnId === col.id);
|
|
154
|
-
return ((0, jsx_runtime_1.jsxs)("div", {
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
},
|
|
160
|
-
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
161
|
-
setOverCol((v) => (v === col.id ? null : v));
|
|
162
|
-
}
|
|
163
|
-
}, onDrop: (e) => {
|
|
164
|
-
e.preventDefault();
|
|
165
|
-
if (dragId)
|
|
166
|
-
move(dragId, col.id);
|
|
167
|
-
setDragId(null);
|
|
168
|
-
setOverCol(null);
|
|
169
|
-
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-board-col-header", children: [col.accent && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-dot", style: { background: col.accent } })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-title", children: col.title }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-count", children: colCards.length }), onNewCard && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-board-col-add", "aria-label": `${crispMessages["Add to"] ?? "Add to"} ${col.title}`, onClick: () => onNewCard(col.id), children: "+" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-board-col-body", role: "list", "aria-label": col.title, children: [onNewCard && ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-board-newcard", onClick: () => onNewCard(col.id), children: ["+ ", newCardLabel] })), colCards.map((card) => ((0, jsx_runtime_1.jsx)("div", { className: "crisp-board-card", role: "listitem",
|
|
250
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ref: (el) => {
|
|
251
|
+
if (el)
|
|
252
|
+
colRefs.current.set(col.id, el);
|
|
253
|
+
else
|
|
254
|
+
colRefs.current.delete(col.id);
|
|
255
|
+
}, className: "crisp-board-col", "data-over": overCol === col.id ? "" : undefined, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-board-col-header", children: [col.accent && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-dot", style: { background: col.accent } })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-title", children: col.title }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-count", children: colCards.length }), onNewCard && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-board-col-add", "aria-label": `${crispMessages["Add to"] ?? "Add to"} ${col.title}`, onClick: () => onNewCard(col.id), children: "+" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-board-col-body", role: "list", "aria-label": col.title, children: [onNewCard && ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-board-newcard", onClick: () => onNewCard(col.id), children: ["+ ", newCardLabel] })), colCards.map((card) => ((0, jsx_runtime_1.jsx)("div", { className: "crisp-board-card", role: "listitem",
|
|
170
256
|
// biome-ignore lint/a11y/noNoninteractiveTabindex: the rule assumes a listitem cannot be operated. This one carries the board's only keyboard path to move a card, so it has to be reachable by Tab
|
|
171
|
-
tabIndex: 0, "aria-label": getCardLabel?.(card), "data-card-id": card.id,
|
|
172
|
-
setDragId(null);
|
|
173
|
-
setOverCol(null);
|
|
174
|
-
}, onKeyDown: (e) => {
|
|
257
|
+
tabIndex: 0, "aria-label": getCardLabel?.(card), "data-card-id": card.id, "data-dragging": dragId === card.id ? "" : undefined, onPointerDown: (e) => onCardPointerDown(e, card), onPointerMove: onCardPointerMove, onPointerUp: (e) => endCardDrag(e, true), onPointerCancel: (e) => endCardDrag(e, false), onKeyDown: (e) => {
|
|
175
258
|
if (!(e.ctrlKey || e.metaKey))
|
|
176
259
|
return;
|
|
177
260
|
// the columns are a flex row, so under RTL the next one
|
|
@@ -187,6 +270,18 @@ function Board({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLa
|
|
|
187
270
|
}, children: renderCard(card) }, card.id)))] }), calc && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-board-col-footer", children: (0, jsx_runtime_1.jsx)(menu_1.Menu, { align: "start", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-board-col-calc", "data-empty": colAgg[col.id] ? undefined : "", children: colAgg[col.id] ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-calc-label", children: crispMessages[AGG_LABEL[colAgg[col.id]]] ??
|
|
188
271
|
AGG_LABEL[colAgg[col.id]] }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-board-col-calc-value", children: computeBoardAgg(colAgg[col.id], colCards.map((c) => calc.getValue(c))) })] })) : ((crispMessages["+ Add calculation"] ??
|
|
189
272
|
"+ Add calculation")) }), children: BOARD_AGG_ORDER.map((a) => ((0, jsx_runtime_1.jsxs)(menu_1.MenuItem, { onSelect: () => setColAgg((prev) => ({ ...prev, [col.id]: a })), children: [crispMessages[AGG_LABEL[a]] ?? AGG_LABEL[a], colAgg[col.id] === a ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 15, strokeWidth: 1.75 })) : null] }, a))) }) }))] }, col.id));
|
|
190
|
-
}),
|
|
273
|
+
}), dragId &&
|
|
274
|
+
ghost &&
|
|
275
|
+
(() => {
|
|
276
|
+
const draggedCard = cards.find((c) => c.id === dragId);
|
|
277
|
+
if (!draggedCard)
|
|
278
|
+
return null;
|
|
279
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-board-card crisp-board-ghost", style: {
|
|
280
|
+
left: ghost.x,
|
|
281
|
+
top: ghost.y,
|
|
282
|
+
width: ghost.width,
|
|
283
|
+
height: ghost.height,
|
|
284
|
+
}, children: renderCard(draggedCard) }));
|
|
285
|
+
})(), (0, jsx_runtime_1.jsx)("div", { className: "crisp-board-live", role: "status", "aria-live": "assertive", children: announcement })] }));
|
|
191
286
|
}
|
|
192
287
|
Board.displayName = "Board";
|
|
@@ -23,18 +23,30 @@ const config = (0, core_1.defineRecipe)({
|
|
|
23
23
|
& .crisp-board-col-header { display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: 36px; padding: 0 ${tokens_1.contract.space["1"]}; flex-shrink: 0; }
|
|
24
24
|
& .crisp-board-col-dot { width: 12px; height: 12px; border-radius: ${tokens_1.contract.radius.full}; flex-shrink: 0; }
|
|
25
25
|
& .crisp-board-col-title { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; }
|
|
26
|
-
|
|
26
|
+
/* crisp#697: HANDOFF's #472 note claimed the count pill's
|
|
27
|
+
color-mix(fgPrimary, 63%, transparent) reproduced the measured
|
|
28
|
+
rgb(80,81,85) -- it doesn't; 63% of fgPrimary composited on white
|
|
29
|
+
paints rgb(104,105,105), visibly lighter. Text now reads
|
|
30
|
+
fgNeutralSoft directly (the same rgb(80,81,85) token Badge's neutral
|
|
31
|
+
tone uses, #696), and the ring the pill was also missing
|
|
32
|
+
(inset 0 0 0 1px borderSubtle, measured rgb(238,239,241)) is added. */
|
|
33
|
+
& .crisp-board-col-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.sm}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 4%, transparent); box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}; font-size: ${tokens_1.contract.text.sm}; line-height: 16px; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgNeutralSoft}; }
|
|
27
34
|
& .crisp-board-col-add { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-inline-start: auto; padding: 0; border: none; border-radius: ${tokens_1.contract.radius.sm}; background: none; color: ${tokens_1.contract.fgMuted}; font-family: inherit; cursor: pointer; }
|
|
28
35
|
& .crisp-board-col-add:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent); color: ${tokens_1.contract.fgPrimary}; }
|
|
29
36
|
& .crisp-board-col-body { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; flex: 1; min-height: 48px; padding: ${tokens_1.contract.space["1"]}; border-radius: ${tokens_1.contract.radius.lg}; overflow-y: auto; transition: background 0.12s; }
|
|
30
37
|
& .crisp-board-col[data-over] .crisp-board-col-body { background: color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 7%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.bgBrandSolid} 30%, transparent); }
|
|
31
38
|
& .crisp-board-newcard { display: flex; align-items: center; justify-content: center; gap: ${tokens_1.contract.space["1.5"]}; height: 32px; flex-shrink: 0; border: none; border-radius: ${tokens_1.contract.radius.md}; background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 4%, transparent); color: ${tokens_1.contract.fgMuted}; font-family: inherit; font-size: ${tokens_1.contract.text.md}; font-weight: ${tokens_1.contract.weight.medium}; cursor: pointer; }
|
|
32
39
|
& .crisp-board-newcard:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 7%, transparent); color: ${tokens_1.contract.fgPrimary}; }
|
|
33
|
-
& .crisp-board-card { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; box-sizing: border-box; padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["3"]}; border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}; cursor: grab; }
|
|
40
|
+
& .crisp-board-card { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["2"]}; box-sizing: border-box; padding: ${tokens_1.contract.space["2.5"]} ${tokens_1.contract.space["3"]}; border-radius: ${tokens_1.contract.radius.xl}; background: ${tokens_1.contract.bgSurface}; box-shadow: inset 0 0 0 1px ${tokens_1.contract.borderSubtle}; cursor: grab; touch-action: none; }
|
|
34
41
|
& .crisp-board-card:active { cursor: grabbing; }
|
|
35
42
|
& .crisp-board-card[data-dragging] { opacity: 0.4; }
|
|
36
43
|
& .crisp-board-card:focus { outline: none; }
|
|
37
44
|
& .crisp-board-card:focus-visible { outline: 2px solid ${tokens_1.contract.bgBrandSolid}; outline-offset: 1px; }
|
|
45
|
+
/* #674: the pointer-events drag's own drag image -- the same card
|
|
46
|
+
surface above, just pinned to the pointer instead of the flex flow.
|
|
47
|
+
No shadow lift or scale: neither was measured against Attio, and this
|
|
48
|
+
is the same card, momentarily somewhere else, not a new look. */
|
|
49
|
+
& .crisp-board-ghost { position: fixed; z-index: 1; pointer-events: none; cursor: grabbing; }
|
|
38
50
|
/* #604: a per-column calc footer, mirroring the table's own (measured
|
|
39
51
|
live, Deals pipeline). Sits below the scrollable card body, not
|
|
40
52
|
inside it or pinned to it -- Attio's own is position: static, not
|
|
@@ -304,8 +304,8 @@ const Composer = React.forwardRef(function Composer({ placeholder, postLabel, me
|
|
|
304
304
|
close: closeMention,
|
|
305
305
|
})] }));
|
|
306
306
|
});
|
|
307
|
-
function CommentRow({ comment, replyLabel, reactLabel, resolveLabel, moreLabel, copyLinkLabel, deleteLabel, addReactionLabel, reactionSearchLabel, emojiOptions, resolvable, resolved, resolvedLabel, onReply, onReact, onResolve, onCopyLink, onDeleteRequest, }) {
|
|
308
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row", children: [(0, jsx_runtime_1.jsx)(AuthorAvatar, { author: comment.author }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row-main", children: [resolvedLabel != null && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-resolved-label", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 12, strokeWidth: 2.5, "aria-hidden": "true" }), resolvedLabel] })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-comments-author", children: comment.author.name }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-comments-time", children: comment.time })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-comments-body-text", children: comment.body }), comment.reactions && comment.reactions.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-reactions", children: [comment.reactions.map((r) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-comments-reaction", "data-reacted": r.reactedByMe ? "" : undefined, onClick: () => onReact(r.emoji), children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: r.emoji }), r.count] }, r.emoji))), (0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "start", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-reaction-add", "aria-label": addReactionLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SmilePlus, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }) }), children: (0, jsx_runtime_1.jsx)(ReactionPicker, { options: emojiOptions, searchLabel: reactionSearchLabel, onPick: onReact }) })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row-actions", children: [onReply && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": replyLabel, onClick: onReply, children: (0, jsx_runtime_1.jsx)(lucide_react_1.CornerUpLeft, { "data-rtl-flip": "", size: 16, strokeWidth: 2, "aria-hidden": "true" }) })), (0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "end", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": reactLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SmilePlus, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), children: (0, jsx_runtime_1.jsx)(ReactionPicker, { options: emojiOptions, searchLabel: reactionSearchLabel, onPick: onReact }) }), resolvable && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": resolveLabel, "aria-pressed": !!resolved, "data-active": resolved ? "" : undefined, onClick: onResolve, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": moreLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { onSelect: onCopyLink, children: copyLinkLabel }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { danger: true, onSelect: onDeleteRequest, children: deleteLabel })] })] })] }));
|
|
307
|
+
function CommentRow({ comment, replyLabel, reactLabel, resolveLabel, moreLabel, copyLinkLabel, deleteLabel, addReactionLabel, reactionSearchLabel, emojiOptions, resolvable, resolved, resolvedLabel, reactable, onReply, onReact, onResolve, onCopyLink, onDeleteRequest, }) {
|
|
308
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row", children: [(0, jsx_runtime_1.jsx)(AuthorAvatar, { author: comment.author }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row-main", children: [resolvedLabel != null && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-resolved-label", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 12, strokeWidth: 2.5, "aria-hidden": "true" }), resolvedLabel] })), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-comments-author", children: comment.author.name }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-comments-time", children: comment.time })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-comments-body-text", children: comment.body }), comment.reactions && comment.reactions.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-reactions", children: [comment.reactions.map((r) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-comments-reaction", "data-reacted": r.reactedByMe ? "" : undefined, onClick: () => onReact?.(r.emoji), children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: r.emoji }), r.count] }, r.emoji))), (0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "start", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-reaction-add", "aria-label": addReactionLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SmilePlus, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }) }), children: (0, jsx_runtime_1.jsx)(ReactionPicker, { options: emojiOptions, searchLabel: reactionSearchLabel, onPick: (emoji) => onReact?.(emoji) }) })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-comments-row-actions", children: [onReply && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": replyLabel, onClick: onReply, children: (0, jsx_runtime_1.jsx)(lucide_react_1.CornerUpLeft, { "data-rtl-flip": "", size: 16, strokeWidth: 2, "aria-hidden": "true" }) })), reactable && ((0, jsx_runtime_1.jsx)(popover_1.Popover, { align: "end", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": reactLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SmilePlus, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), children: (0, jsx_runtime_1.jsx)(ReactionPicker, { options: emojiOptions, searchLabel: reactionSearchLabel, onPick: (emoji) => onReact?.(emoji) }) })), resolvable && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": resolveLabel, "aria-pressed": !!resolved, "data-active": resolved ? "" : undefined, onClick: onResolve, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-comments-action", "aria-label": moreLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { onSelect: onCopyLink, children: copyLinkLabel }), onDeleteRequest && ((0, jsx_runtime_1.jsx)(menu_1.MenuItem, { danger: true, onSelect: onDeleteRequest, children: deleteLabel }))] })] })] }));
|
|
309
309
|
}
|
|
310
310
|
/**
|
|
311
311
|
* Per-record comment threads (crisp#625) — measured live on app.attio.com's
|
|
@@ -375,23 +375,36 @@ function CommentsPanel({ threads, currentUserId, subject, subjectIcon, showResol
|
|
|
375
375
|
? resolvedByYouLabel
|
|
376
376
|
: (resolvedByLabel?.(activeThread.resolvedBy.name) ??
|
|
377
377
|
`Resolved by ${activeThread.resolvedBy.name}`)
|
|
378
|
-
: undefined,
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
378
|
+
: undefined, reactable: !!onReact, onReact: onReact
|
|
379
|
+
? (emoji) => onReact(activeThread.id, activeThread.root.id, emoji)
|
|
380
|
+
: undefined, onResolve: onResolve ? () => onResolve(activeThread.id) : undefined, onCopyLink: () => copyLink(activeThread.id, activeThread.root.id), onDeleteRequest: onDelete
|
|
381
|
+
? () => setDeleteTarget({
|
|
382
382
|
threadId: activeThread.id,
|
|
383
|
-
commentId:
|
|
384
|
-
})
|
|
383
|
+
commentId: activeThread.root.id,
|
|
384
|
+
})
|
|
385
|
+
: undefined }), activeThread.replies && activeThread.replies.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-comments-replies", children: activeThread.replies.map((reply) => ((0, jsx_runtime_1.jsx)(CommentRow, { comment: reply, currentUserId: currentUserId, replyLabel: replyActionLabel, reactLabel: reactActionLabel, resolveLabel: resolveActionLabel, moreLabel: moreActionsLabel, copyLinkLabel: copyLinkLabel, deleteLabel: deleteLabel, addReactionLabel: addReactionLabel, reactionSearchLabel: reactionSearchLabel, emojiOptions: emojiOptions, reactable: !!onReact, onReact: onReact
|
|
386
|
+
? (emoji) => onReact(activeThread.id, reply.id, emoji)
|
|
387
|
+
: undefined, onCopyLink: () => copyLink(activeThread.id, reply.id), onDeleteRequest: onDelete
|
|
388
|
+
? () => setDeleteTarget({
|
|
389
|
+
threadId: activeThread.id,
|
|
390
|
+
commentId: reply.id,
|
|
391
|
+
})
|
|
392
|
+
: undefined }, reply.id))) }))] })) : visibleThreads.length === 0 && emptyLabel != null ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-comments-empty", children: emptyLabel })) : (visibleThreads.map((t) => ((0, jsx_runtime_1.jsx)(CommentRow, { comment: t.root, currentUserId: currentUserId, replyLabel: replyActionLabel, reactLabel: reactActionLabel, resolveLabel: resolveActionLabel, moreLabel: moreActionsLabel, copyLinkLabel: copyLinkLabel, deleteLabel: deleteLabel, addReactionLabel: addReactionLabel, reactionSearchLabel: reactionSearchLabel, emojiOptions: emojiOptions, resolvable: !!onResolve, resolved: t.resolved, resolvedLabel: t.resolved
|
|
385
393
|
? t.resolvedBy?.id === currentUserId || !t.resolvedBy
|
|
386
394
|
? resolvedByYouLabel
|
|
387
395
|
: (resolvedByLabel?.(t.resolvedBy.name) ??
|
|
388
396
|
`Resolved by ${t.resolvedBy.name}`)
|
|
389
|
-
: undefined, onReply: () => setActiveThreadId(t.id), onReact: (emoji) => onReact(t.id, t.root.id, emoji), onResolve: onResolve ? () => onResolve(t.id) : undefined, onCopyLink: () => copyLink(t.id, t.root.id), onDeleteRequest:
|
|
397
|
+
: undefined, onReply: () => setActiveThreadId(t.id), reactable: !!onReact, onReact: onReact ? (emoji) => onReact(t.id, t.root.id, emoji) : undefined, onResolve: onResolve ? () => onResolve(t.id) : undefined, onCopyLink: () => copyLink(t.id, t.root.id), onDeleteRequest: onDelete
|
|
398
|
+
? () => setDeleteTarget({ threadId: t.id, commentId: t.root.id })
|
|
399
|
+
: undefined }, t.id)))) }), (0, jsx_runtime_1.jsx)(Composer, { placeholder: activeThread ? replyPlaceholder : composerPlaceholder, postLabel: activeThread ? replyPostLabel : postLabel, mentionTrigger: mentionTrigger, renderMentionPicker: renderMentionPicker, mentionToolLabel: composerMentionToolLabel, onSubmit: (text) => onPost(text, activeThread ? activeThread.id : null) }, activeThread ? activeThread.id : "root"), (0, jsx_runtime_1.jsxs)(dialog_1.Dialog, { open: deleteTarget != null, onOpenChange: (open) => {
|
|
390
400
|
if (!open)
|
|
391
401
|
setDeleteTarget(null);
|
|
392
402
|
}, title: deleteConfirmTitle, children: [(0, jsx_runtime_1.jsx)(dialog_1.DialogBody, { children: deleteConfirmBody }), (0, jsx_runtime_1.jsxs)(dialog_1.DialogFooter, { children: [(0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", intent: "neutral", size: "md", onClick: () => setDeleteTarget(null), children: cancelLabel }), (0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", intent: "danger", size: "md", onClick: () => {
|
|
403
|
+
// `deleteTarget` can only ever be set via `onDeleteRequest`
|
|
404
|
+
// (above), which itself only exists when `onDelete` was
|
|
405
|
+
// given -- this call is never reached otherwise.
|
|
393
406
|
if (deleteTarget)
|
|
394
|
-
onDelete(deleteTarget.threadId, deleteTarget.commentId);
|
|
407
|
+
onDelete?.(deleteTarget.threadId, deleteTarget.commentId);
|
|
395
408
|
setDeleteTarget(null);
|
|
396
409
|
}, children: deleteConfirmActionLabel })] })] })] }));
|
|
397
410
|
}
|
|
@@ -36,12 +36,26 @@ const config = (0, core_1.defineRecipe)({
|
|
|
36
36
|
|
|
37
37
|
/* One comment row -- avatar 16px (Avatar size="sm"), 6px gap to the
|
|
38
38
|
name/time line, 14px/600 name + 12px/500 63%-muted time, 14px/400 body
|
|
39
|
-
two lines below. Hover actions fade in flush with the name line.
|
|
39
|
+
two lines below. Hover actions fade in flush with the name line.
|
|
40
|
+
.crisp-comments-row-head's own height: 20px (above) is a single
|
|
41
|
+
text-line's worth, on the same assumption .crisp-comments-title/
|
|
42
|
+
.crisp-comments-breadcrumb already act on higher up in this same
|
|
43
|
+
recipe -- a name that doesn't fit wraps to two lines with nothing
|
|
44
|
+
reserving room for the second one, overflowing straight into the
|
|
45
|
+
body text underneath (found live: this app's own dev-bypass author
|
|
46
|
+
name, an email long enough to wrap, sat on top of the comment's own
|
|
47
|
+
body text). .crisp-comments-author gets the identical nowrap-
|
|
48
|
+
ellipsis treatment those two already have, plus min-width: 0 so a
|
|
49
|
+
flex item is actually allowed to shrink below its own text's natural
|
|
50
|
+
width in the first place; .crisp-comments-time gets flex-shrink: 0
|
|
51
|
+
so it's the name that gives, never the timestamp -- the same "one
|
|
52
|
+
side shrinks, the other one doesn't" split PersonChip's own name/
|
|
53
|
+
avatar pair already uses (crisp#668/#671). */
|
|
40
54
|
& .crisp-comments-row { position: relative; display: flex; gap: ${tokens_1.contract.space["1.5"]}; }
|
|
41
55
|
& .crisp-comments-row-main { flex: 1; min-width: 0; }
|
|
42
56
|
& .crisp-comments-row-head { display: flex; align-items: baseline; gap: ${tokens_1.contract.space["1.5"]}; height: 20px; }
|
|
43
|
-
& .crisp-comments-author { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; }
|
|
44
|
-
& .crisp-comments-time { font-size: 12px; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); white-space: nowrap; }
|
|
57
|
+
& .crisp-comments-author { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.semibold}; color: ${tokens_1.contract.fgPrimary}; }
|
|
58
|
+
& .crisp-comments-time { flex-shrink: 0; font-size: 12px; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); white-space: nowrap; }
|
|
45
59
|
& .crisp-comments-resolved-label { display: flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; margin-bottom: ${tokens_1.contract.space["1"]}; font-size: 12px; font-weight: ${tokens_1.contract.weight.medium}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
|
|
46
60
|
& .crisp-comments-body-text { font-size: ${tokens_1.contract.text.lg}; line-height: 20px; font-weight: ${tokens_1.contract.weight.regular}; color: ${tokens_1.contract.fgPrimary}; white-space: pre-wrap; word-break: break-word; }
|
|
47
61
|
|
|
@@ -69,13 +69,19 @@ function useFormDialogOptional(required) {
|
|
|
69
69
|
* per-field wiring). A record needs several fields at once to be valid,
|
|
70
70
|
* which is why records are not created by inline editing.
|
|
71
71
|
*/
|
|
72
|
-
function FormDialog({ title, submitLabel, onSubmit, onClose, busy, error, children, wide = false, size, createMode = false, createMoreLabel: createMoreLabelProp, cancelLabel: cancelLabelProp, discardTitle: discardTitleProp, discardConfirmLabel: discardConfirmLabelProp, discardCancelLabel: discardCancelLabelProp, className, ...rest }) {
|
|
72
|
+
function FormDialog({ title, submitLabel, onSubmit, onClose, busy, error, children, wide = false, size, createMode = false, createMoreLabel: createMoreLabelProp, cancelLabel: cancelLabelProp, discardTitle: discardTitleProp, discardDescription: discardDescriptionProp, discardConfirmLabel: discardConfirmLabelProp, discardCancelLabel: discardCancelLabelProp, className, ...rest }) {
|
|
73
73
|
const createMoreLabel = (0, core_1.useCrispMessage)(createMoreLabelProp, "Create more");
|
|
74
74
|
const createRecordLabel = (0, core_1.useCrispMessage)(undefined, "Create record");
|
|
75
75
|
const cancelLabel = (0, core_1.useCrispMessage)(cancelLabelProp, "Cancel");
|
|
76
|
-
|
|
76
|
+
// crisp#677: Attio's own confirm is two lines (a title, then a separate
|
|
77
|
+
// sentence), not one combined string — measured live, both quoted
|
|
78
|
+
// verbatim off app.attio.com's create-attribute dialog's own discard
|
|
79
|
+
// confirm. The buttons read "Cancel"/"Discard" there too, not crisp's
|
|
80
|
+
// prior "Keep editing" (a paraphrase, never independently measured).
|
|
81
|
+
const discardTitle = (0, core_1.useCrispMessage)(discardTitleProp, "Discard changes");
|
|
82
|
+
const discardDescription = (0, core_1.useCrispMessage)(discardDescriptionProp, "Are you sure you want to discard these changes?");
|
|
77
83
|
const discardConfirmLabel = (0, core_1.useCrispMessage)(discardConfirmLabelProp, "Discard");
|
|
78
|
-
const discardCancelLabel = (0, core_1.useCrispMessage)(discardCancelLabelProp, "
|
|
84
|
+
const discardCancelLabel = (0, core_1.useCrispMessage)(discardCancelLabelProp, "Cancel");
|
|
79
85
|
const formId = React.useId();
|
|
80
86
|
const formRef = React.useRef(null);
|
|
81
87
|
const switchId = React.useId();
|
|
@@ -163,7 +169,7 @@ function FormDialog({ title, submitLabel, onSubmit, onClose, busy, error, childr
|
|
|
163
169
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(dialog_1.Dialog, { open: true, onOpenChange: (open) => !open && requestClose(), title: title, width: size ?? (wide ? 760 : 640), className: (0, formdialog_recipe_1.formdialogRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)(dialog_1.DialogBody, { children: [(0, jsx_runtime_1.jsx)(OptionalLabelsContext.Provider, { value: createMode, children: (0, jsx_runtime_1.jsx)("form", { ref: formRef, id: formId, className: "crisp-formdialog-form", onSubmit: (e) => {
|
|
164
170
|
e.preventDefault();
|
|
165
171
|
onSubmit(createMore);
|
|
166
|
-
}, onChange: markDirty, onInput: markDirty, onClick: markDirty, children: children }) }), error != null && (0, jsx_runtime_1.jsx)("p", { className: "crisp-formdialog-error", children: error })] }), (0, jsx_runtime_1.jsx)(dialog_1.DialogFooter, { children: createMode ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-formdialog-createfoot", children: [(0, jsx_runtime_1.jsxs)("span", { className: "crisp-dialog-more", children: [(0, jsx_runtime_1.jsx)(switch_1.Switch, { id: switchId, checked: createMore, onCheckedChange: setCreateMore, "aria-label": createMoreLabel }), (0, jsx_runtime_1.jsx)("label", { className: "crisp-formdialog-more-label", htmlFor: switchId, children: createMoreLabel })] }), (0, jsx_runtime_1.jsxs)("button", { type: "submit", form: formId, className: "crisp-dialog-submit", disabled: busy, children: [createRecordLabel, (0, jsx_runtime_1.jsxs)("span", { className: "crisp-dialog-submit-key", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("kbd", { children: "\u2318" }), (0, jsx_runtime_1.jsx)("kbd", { children: "\u21B5" })] })] })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", intent: "neutral", onClick: requestClose, children: cancelLabel }), (0, jsx_runtime_1.jsx)(button_1.Button, { type: "submit", form: formId, intent: "primary", loading: busy, children: submitLabel })] })) })] }), (0, jsx_runtime_1.jsx)(dialog_1.Dialog, { open: confirmingDiscard, onOpenChange: (open) => !open && setConfirmingDiscard(false), title: discardTitle, width:
|
|
172
|
+
}, onChange: markDirty, onInput: markDirty, onClick: markDirty, children: children }) }), error != null && (0, jsx_runtime_1.jsx)("p", { className: "crisp-formdialog-error", children: error })] }), (0, jsx_runtime_1.jsx)(dialog_1.DialogFooter, { children: createMode ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-formdialog-createfoot", children: [(0, jsx_runtime_1.jsxs)("span", { className: "crisp-dialog-more", children: [(0, jsx_runtime_1.jsx)(switch_1.Switch, { id: switchId, checked: createMore, onCheckedChange: setCreateMore, "aria-label": createMoreLabel }), (0, jsx_runtime_1.jsx)("label", { className: "crisp-formdialog-more-label", htmlFor: switchId, children: createMoreLabel })] }), (0, jsx_runtime_1.jsxs)("button", { type: "submit", form: formId, className: "crisp-dialog-submit", disabled: busy, children: [createRecordLabel, (0, jsx_runtime_1.jsxs)("span", { className: "crisp-dialog-submit-key", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("kbd", { children: "\u2318" }), (0, jsx_runtime_1.jsx)("kbd", { children: "\u21B5" })] })] })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", intent: "neutral", onClick: requestClose, children: cancelLabel }), (0, jsx_runtime_1.jsx)(button_1.Button, { type: "submit", form: formId, intent: "primary", loading: busy, children: submitLabel })] })) })] }), (0, jsx_runtime_1.jsx)(dialog_1.Dialog, { open: confirmingDiscard, onOpenChange: (open) => !open && setConfirmingDiscard(false), variant: "alert", title: discardTitle, description: discardDescription, width: 440, children: (0, jsx_runtime_1.jsxs)(dialog_1.DialogFooter, { variant: "alert", children: [(0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", intent: "neutral", onClick: () => setConfirmingDiscard(false), children: discardCancelLabel }), (0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", intent: "danger", onClick: () => {
|
|
167
173
|
setConfirmingDiscard(false);
|
|
168
174
|
onClose();
|
|
169
175
|
}, children: discardConfirmLabel })] }) })] }));
|
|
@@ -36,9 +36,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.NavItem = void 0;
|
|
37
37
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
38
|
const React = __importStar(require("react"));
|
|
39
|
+
const kbd_1 = require("../../components/kbd");
|
|
40
|
+
const tooltip_1 = require("../../components/tooltip");
|
|
39
41
|
const core_1 = require("../../core");
|
|
40
42
|
const navitem_recipe_1 = require("./navitem.recipe");
|
|
41
|
-
exports.NavItem = React.forwardRef(({ active, icon, trailing, className, children, ...props }, ref) => {
|
|
42
|
-
|
|
43
|
+
exports.NavItem = React.forwardRef(({ active, icon, trailing, shortcut, className, children, ...props }, ref) => {
|
|
44
|
+
const row = ((0, jsx_runtime_1.jsxs)(core_1.Primitive.a, { ref: ref, "data-active": active || undefined, className: (0, navitem_recipe_1.navitemRecipe)({ className }), ...props, children: [icon, (0, jsx_runtime_1.jsx)("span", { className: "crisp-navitem-label", children: children }), trailing != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-navitem-trailing", children: trailing }))] }));
|
|
45
|
+
if (!shortcut)
|
|
46
|
+
return row;
|
|
47
|
+
return ((0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { asChild: true, side: "right", delay: 500, content: (0, jsx_runtime_1.jsxs)("span", { className: "crisp-navitem-shortcut", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-navitem-shortcut-desc", children: shortcut.description }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-navitem-shortcut-chord", children: shortcut.keys.map((key, i) => ((0, jsx_runtime_1.jsxs)(React.Fragment, { children: [i > 0 && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-navitem-shortcut-then", children: "then" })), (0, jsx_runtime_1.jsx)(kbd_1.Kbd, { children: key })] }, i))) })] }), children: row }));
|
|
43
48
|
});
|
|
44
49
|
exports.NavItem.displayName = "NavItem";
|
|
@@ -21,6 +21,22 @@ const config = (0, core_1.defineRecipe)({
|
|
|
21
21
|
variants: {},
|
|
22
22
|
defaultVariants: {},
|
|
23
23
|
compoundVariants: [],
|
|
24
|
+
// Tooltip portals its content to document.body (same reason sidebar.recipe.ts's
|
|
25
|
+
// menu content lives in globalCss, not a `&`-nested rule): a shortcut hint
|
|
26
|
+
// never sits inside `.crisp-navitem` in the live DOM, so it needs an
|
|
27
|
+
// unscoped rule to be reached at all. Values measured live on
|
|
28
|
+
// app.attio.com's own "G then <letter>" hint (crisp#633): the description
|
|
29
|
+
// inherits Tooltip's own #eeeff1 text colour for free (it's the same hex),
|
|
30
|
+
// but "then" and the Kbd chip are their own greys, hardcoded raw rather
|
|
31
|
+
// than through a token -- same call tooltip.recipe.ts already made for
|
|
32
|
+
// this exact bubble, which is always dark regardless of the app's theme.
|
|
33
|
+
globalCss: `
|
|
34
|
+
.crisp-navitem-shortcut { display: flex; align-items: baseline; justify-content: space-between; gap: ${tokens_1.contract.space["3"]}; }
|
|
35
|
+
.crisp-navitem-shortcut-desc { font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; line-height: 16px; white-space: nowrap; }
|
|
36
|
+
.crisp-navitem-shortcut-chord { display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1"]}; flex-shrink: 0; }
|
|
37
|
+
.crisp-navitem-shortcut-then { font-size: ${tokens_1.contract.text.xs}; font-weight: ${tokens_1.contract.weight.medium}; color: #898a8d; }
|
|
38
|
+
.crisp-navitem-shortcut-chord .crisp-kbd { text-transform: uppercase; font-weight: ${tokens_1.contract.weight.regular}; color: #a2a4a7; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2); }
|
|
39
|
+
`,
|
|
24
40
|
});
|
|
25
41
|
exports.navitemRecipe = Object.assign((0, core_1.resolveRecipe)(config), {
|
|
26
42
|
config,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.objectsettingsRecipe = exports.ObjectsList = exports.
|
|
3
|
+
exports.objectsettingsRecipe = exports.ObjectsList = exports.ObjectGeneralSection = exports.ObjectDetailPage = exports.ObjectAppearanceSection = exports.CreateAttributeDialog = exports.AttributeTypeSelect = exports.AttributesTable = exports.ATTRIBUTE_TYPE_OPTIONS = exports.ATTRIBUTE_AI_AUTOFILL_OPTIONS = void 0;
|
|
4
4
|
var objectsettings_1 = require("./objectsettings");
|
|
5
5
|
Object.defineProperty(exports, "ATTRIBUTE_AI_AUTOFILL_OPTIONS", { enumerable: true, get: function () { return objectsettings_1.ATTRIBUTE_AI_AUTOFILL_OPTIONS; } });
|
|
6
6
|
Object.defineProperty(exports, "ATTRIBUTE_TYPE_OPTIONS", { enumerable: true, get: function () { return objectsettings_1.ATTRIBUTE_TYPE_OPTIONS; } });
|
|
@@ -10,7 +10,6 @@ Object.defineProperty(exports, "CreateAttributeDialog", { enumerable: true, get:
|
|
|
10
10
|
Object.defineProperty(exports, "ObjectAppearanceSection", { enumerable: true, get: function () { return objectsettings_1.ObjectAppearanceSection; } });
|
|
11
11
|
Object.defineProperty(exports, "ObjectDetailPage", { enumerable: true, get: function () { return objectsettings_1.ObjectDetailPage; } });
|
|
12
12
|
Object.defineProperty(exports, "ObjectGeneralSection", { enumerable: true, get: function () { return objectsettings_1.ObjectGeneralSection; } });
|
|
13
|
-
Object.defineProperty(exports, "ObjectSettings", { enumerable: true, get: function () { return objectsettings_1.ObjectSettings; } });
|
|
14
13
|
Object.defineProperty(exports, "ObjectsList", { enumerable: true, get: function () { return objectsettings_1.ObjectsList; } });
|
|
15
14
|
var objectsettings_recipe_1 = require("./objectsettings.recipe");
|
|
16
15
|
Object.defineProperty(exports, "objectsettingsRecipe", { enumerable: true, get: function () { return objectsettings_recipe_1.objectsettingsRecipe; } });
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
36
|
+
exports.ATTRIBUTE_AI_AUTOFILL_OPTIONS = exports.ATTRIBUTE_TYPE_OPTIONS = void 0;
|
|
37
37
|
exports.ObjectsList = ObjectsList;
|
|
38
38
|
exports.ObjectDetailPage = ObjectDetailPage;
|
|
39
39
|
exports.ObjectGeneralSection = ObjectGeneralSection;
|
|
@@ -157,7 +157,7 @@ function ObjectDetailPage({ icon, iconColor, name, typeLabel, description, tab,
|
|
|
157
157
|
setInternalTab(next);
|
|
158
158
|
onTabChange?.(next);
|
|
159
159
|
};
|
|
160
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: (0, objectsettings_recipe_1.objectsettingsRecipe)(), children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-objectsettings-page", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-objectsettings-head", children: (0, jsx_runtime_1.jsxs)("div", { style: { display: "flex", alignItems: "flex-start", gap: 12 }, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-objectsettings-icon crisp-objectsettings-icon--lg", style: { background: iconColor ?? "currentColor" }, children: icon }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-objectsettings-heading", children: [(0, jsx_runtime_1.jsxs)("h1", { className: "crisp-objectsettings-title", children: [name, typeLabel != null && ((0, jsx_runtime_1.jsx)(badge_1.Badge, { tone: "neutral", size: "
|
|
160
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: (0, objectsettings_recipe_1.objectsettingsRecipe)(), children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-objectsettings-page", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-objectsettings-head", children: (0, jsx_runtime_1.jsxs)("div", { style: { display: "flex", alignItems: "flex-start", gap: 12 }, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-objectsettings-icon crisp-objectsettings-icon--lg", style: { background: iconColor ?? "currentColor" }, children: icon }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-objectsettings-heading", children: [(0, jsx_runtime_1.jsxs)("h1", { className: "crisp-objectsettings-title", children: [name, typeLabel != null && ((0, jsx_runtime_1.jsx)(badge_1.Badge, { tone: "neutral", size: "medium", children: typeLabel }))] }), description != null && ((0, jsx_runtime_1.jsx)("p", { className: "crisp-objectsettings-subtitle", children: description }))] })] }) }), (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { value: active, onValueChange: setTab, tabs: [
|
|
161
161
|
{ value: "configuration", label: configurationLabel },
|
|
162
162
|
{
|
|
163
163
|
value: "attributes",
|
|
@@ -245,7 +245,7 @@ function AttributesTable({ attributes, onOpenAttribute, onEditAttribute, onArchi
|
|
|
245
245
|
{
|
|
246
246
|
key: "properties",
|
|
247
247
|
header: propertiesColumnLabel,
|
|
248
|
-
render: (_v, row) => ((0, jsx_runtime_1.jsxs)("span", { style: { display: "flex", gap: 6 }, children: [row.system && ((0, jsx_runtime_1.jsx)(badge_1.Badge, { tone: "neutral", size: "
|
|
248
|
+
render: (_v, row) => ((0, jsx_runtime_1.jsxs)("span", { style: { display: "flex", gap: 6 }, children: [row.system && ((0, jsx_runtime_1.jsx)(badge_1.Badge, { tone: "neutral", size: "medium", children: systemLabel })), row.enriched && ((0, jsx_runtime_1.jsx)(badge_1.Badge, { tone: "purple", size: "medium", children: enrichedLabel }))] })),
|
|
249
249
|
},
|
|
250
250
|
{
|
|
251
251
|
key: "actions",
|
|
@@ -353,13 +353,3 @@ function CreateAttributeDialog({ type, onTypeChange, typeOptions, aiAutofillType
|
|
|
353
353
|
return ((0, jsx_runtime_1.jsxs)(formdialog_1.FormDialog, { title: title, submitLabel: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [createLabel, (0, jsx_runtime_1.jsxs)("span", { className: "crisp-objectsettings-kbd", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("kbd", { children: "\u2318" }), (0, jsx_runtime_1.jsx)("kbd", { children: "\u21B5" })] })] }), onSubmit: onSubmit, onClose: onClose, busy: busy, error: error, size: 520, className: (0, objectsettings_recipe_1.objectsettingsRecipe)(), children: [(0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: attributeTypeLabel, children: (0, jsx_runtime_1.jsx)(AttributeTypeSelect, { value: type, onValueChange: onTypeChange, options: typeOptions, aiAutofillOptions: aiAutofillTypeOptions }) }), (0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: nameLabel, htmlFor: nameId, children: (0, jsx_runtime_1.jsx)(input_1.Input, { id: nameId, autoFocus: true, value: name, onChange: (e) => onNameChange(e.target.value) }) }), (0, jsx_runtime_1.jsx)(formfield_1.FormField, { label: descriptionLabel, optional: true, children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { placeholder: descriptionPlaceholder, value: description, onChange: (e) => onDescriptionChange(e.target.value) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-objectsettings-aiautofill", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-objectsettings-aiautofill-label", children: aiAutofillLabel }), (0, jsx_runtime_1.jsxs)("label", { className: "crisp-objectsettings-aiautofill-row", htmlFor: switchId, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14 }), (0, jsx_runtime_1.jsx)("span", { children: setUpAiAutofillLabel }), (0, jsx_runtime_1.jsx)(switch_1.Switch, { id: switchId, checked: aiAutofillEnabled, onCheckedChange: onAiAutofillChange })] })] })] }));
|
|
354
354
|
}
|
|
355
355
|
CreateAttributeDialog.displayName = "CreateAttributeDialog";
|
|
356
|
-
/**
|
|
357
|
-
* This folder holds several components (`ObjectsList`, `ObjectDetailPage`,
|
|
358
|
-
* `AttributesTable`, `CreateAttributeDialog`, …), not one named after the
|
|
359
|
-
* slug — unlike every other product dir, whose docs `<ManualInstallation>`
|
|
360
|
-
* resolves an import binding from the folder slug ("avatargroup" →
|
|
361
|
-
* `AvatarGroup`) by reading this file's exports. This alias exists only so
|
|
362
|
-
* that resolver finds a match for "objectsettings"; consumers should import
|
|
363
|
-
* the real names above, never this one.
|
|
364
|
-
*/
|
|
365
|
-
exports.ObjectSettings = ObjectsList;
|