@crisp-ui-kit/crisp 0.55.1 → 0.55.3
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/cjs/components/columncalc/columncalc.recipe.js +20 -4
- package/dist/cjs/components/datatable/datatable.js +109 -16
- package/dist/cjs/components/datatable/datatable.recipe.js +63 -2
- package/dist/cjs/components/select/select.js +1 -1
- package/dist/cjs/components/table/table.recipe.js +20 -3
- package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +24 -3
- package/dist/columncalc.css +14 -4
- package/dist/columncalc.layered.css +14 -4
- package/dist/datatable.css +87 -59
- package/dist/datatable.layered.css +87 -59
- package/dist/esm/components/columncalc/columncalc.recipe.js +20 -4
- package/dist/esm/components/datatable/datatable.js +110 -17
- package/dist/esm/components/datatable/datatable.recipe.js +63 -2
- package/dist/esm/components/select/select.js +1 -1
- package/dist/esm/components/table/table.recipe.js +20 -3
- package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +24 -3
- package/dist/styles.css +144 -75
- package/dist/styles.layered.css +144 -75
- package/dist/table.css +11 -3
- package/dist/table.layered.css +11 -3
- package/dist/tabletoolbar.css +32 -9
- package/dist/tabletoolbar.layered.css +32 -9
- package/dist/types/components/datatable/datatable.d.ts +40 -4
- package/dist/types/components/select/select.d.ts +5 -0
- package/package.json +1 -1
package/dist/datatable.css
CHANGED
|
@@ -40,54 +40,58 @@
|
|
|
40
40
|
class + one element) -- a bare `& th` here only won by source
|
|
41
41
|
order, which flipped the moment table.recipe.ts's own CSS file happened to land after datatable's in the build (alphabetical:
|
|
42
42
|
datatable < table), silently reinstating 12px on every header cell
|
|
43
|
-
in the whole product and making every interactive column's button double it to 24px. Scoping through `.crisp-table` adds a second class to the selector (0,2,1 beats 0,1,1) so this can never lose a specificity tie to source order again.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
in the whole product and making every interactive column's button double it to 24px. Scoping through `.crisp-table` adds a second class to the selector (0,2,1 beats 0,1,1) so this can never lose a specificity tie to source order again. `thead th`, not a bare `th` (crisp#829): #779 made the primary column's BODY cell a real `<th scope="row">` for a11y, and a bare
|
|
44
|
+
`th` here matches that one too, zeroing an inset nothing else
|
|
45
|
+
supplies -- the primary column's text sat flush left, one column's
|
|
46
|
+
cell no longer matching its own header or any sibling `<td>`. Only
|
|
47
|
+
the header row's own `<th>` needs zero padding (its sort BUTTON owns the inset); the body row's `<th scope="row">` has no button,
|
|
48
|
+
and needs the SAME base 12px (table.recipe.ts, #465) every other
|
|
49
|
+
cell already gets. */
|
|
50
|
+
& .crisp-table thead th { padding: 0; }
|
|
51
|
+
/* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger): Menu wraps its trigger in a flex div that sizes to its content, so a long header grew past the column instead of filling it -- with nothing left to squeeze, the label's own ellipsis CSS (below) had no properly
|
|
52
|
+
-sized box to truncate against, and the th's own overflow hard-clipped it with no "...". Fill the wrapper, scoped to th so Menu's default
|
|
53
|
+
(correct everywhere else) is untouched. */
|
|
50
54
|
& th .crisp-menu { width: 100%; height: 100%; }
|
|
51
55
|
& .crisp-datatable-th-inner { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; }
|
|
52
56
|
& .crisp-datatable-th-inner > svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
53
|
-
/* crisp/#605 follow-up: a header with neither a Menu nor a sort button
|
|
54
|
-
columnMenu/sortable at all) renders .crisp-datatable-th-inner as a
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
plain sort `button` both put >=1 more level between `th` and this
|
|
60
|
-
span, so their own 12px (already on the button) isn't doubled. */
|
|
57
|
+
/* crisp/#605 follow-up: a header with neither a Menu nor a sort button
|
|
58
|
+
(the primary/entity column's now-inert path, or any column with no columnMenu/sortable at all) renders .crisp-datatable-th-inner as a DIRECT child of th instead of nested inside a button -- and loses the button's own 12px inset, drifting left of the td's 12px base inset. Measured live on Attio's own Companies grid: the header label
|
|
59
|
+
and the cell's own text land at the exact same x (335px from the viewport, both 40px from the column's left edge) via two different
|
|
60
|
+
padding+icon+gap combinations -- Attio does not leave the inert
|
|
61
|
+
primary header flush left either. The `>` combinator targets only
|
|
62
|
+
the button-less case: Menu's own wrapper (`.crisp-menu`) and the plain sort `button` both put >=1 more level between `th` and this span, so their own 12px (already on the button) isn't doubled. */
|
|
61
63
|
& th > .crisp-datatable-th-inner { box-sizing: border-box; padding: 0 var(--crisp-space-3); }
|
|
62
|
-
|
|
64
|
+
/* The summary cell has NO padding of its own -- the calculation trigger
|
|
65
|
+
owns the whole 246x37 area so a click anywhere in the cell opens the
|
|
66
|
+
menu. Zero the cell's inset and let ColumnCalc supply the 12px. */
|
|
63
67
|
& tfoot td { padding: 0; }
|
|
64
|
-
/* Group heading row -- a view is grouped under a subtle label with the
|
|
65
|
-
|
|
66
|
-
& .crisp-datatable-viewsettings { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
68
|
+
/* Group heading row -- a view is grouped under a subtle label with the bucket's count beside it. */
|
|
69
|
+
& .crisp-datatable-viewsettings { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
67
70
|
& .crisp-datatable-viewsettings:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
|
|
68
71
|
& .crisp-datatable-group-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
69
|
-
|
|
72
|
+
& .crisp-datatable-group { height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-3); background: var(--crisp-bg-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
70
73
|
& .crisp-datatable-group-count { margin-inline-start: var(--crisp-space-1-5); color: var(--crisp-fg-muted); font-variant-numeric: tabular-nums; }
|
|
71
74
|
& .crisp-datatable-th-rename { width: 100%; min-width: 0; height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-1); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); outline: none; }
|
|
72
75
|
& .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
73
76
|
& .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
74
|
-
/* #465: 12px per the comment above (and Attio's measured header cell
|
|
75
|
-
padding: 0 12px) -- was still c.space["2"] (8px), drifted from its
|
|
76
|
-
own documented value. */
|
|
77
|
+
/* #465: 12px per the comment above (and Attio's measured header cell padding: 0 12px) -- was still c.space["2"] (8px), drifted from its own documented value. */
|
|
77
78
|
& .crisp-datatable-sort { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
|
|
78
|
-
/* A right-aligned column's header keeps its field-icon + label packed at
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
/* A right-aligned column's header keeps its field-icon + label packed at
|
|
80
|
+
the START, matching its own values only in that the VALUES right-align
|
|
81
|
+
-- Attio's own right-aligned header (measured live: "Twitter follower
|
|
82
|
+
count") keeps the icon+label left and only the trailing column-menu icon sits pinned to the right edge, independent of the label's width
|
|
83
|
+
(#406, reversing #393's own justify-content: flex-end here). The chevron's own margin-inline-start: auto below already pins IT to the
|
|
84
|
+
end of a flex-start row with no override needed -- that's what pins the trailing icon on Attio too. */
|
|
83
85
|
& .crisp-datatable-chevron { margin-inline-start: auto; flex-shrink: 0; color: var(--crisp-fg-muted); opacity: 0; transition: opacity .12s; }
|
|
84
86
|
& .crisp-datatable-sort:hover .crisp-datatable-chevron { opacity: 0.6; }
|
|
85
87
|
& .crisp-datatable-sort[data-sorted] .crisp-datatable-chevron { opacity: 1; color: var(--crisp-fg-primary); }
|
|
86
88
|
/* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
|
|
87
89
|
& th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: var(--crisp-bg-surface); }
|
|
88
|
-
& th[data-sticky] { z-index: 3;
|
|
89
|
-
/* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
90
|
-
`tfoot td { z-index: 2 }
|
|
90
|
+
& th[data-sticky] { z-index: 3;
|
|
91
|
+
} /* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
92
|
+
`tfoot td { z-index: 2 }
|
|
93
|
+
`), which `td[data-sticky]`'s own higher-specificity
|
|
94
|
+
`z-index: 1` would otherwise undercut -- keep it level with the row it's in. */
|
|
91
95
|
& tfoot td[data-sticky] { z-index: 2; }
|
|
92
96
|
& tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
|
|
93
97
|
& tbody tr:hover td[data-sticky] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
|
|
@@ -104,36 +108,41 @@
|
|
|
104
108
|
& tbody tr[data-selected] td { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
|
|
105
109
|
& tbody tr[data-selected]:hover td { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface))); }
|
|
106
110
|
& .crisp-datatable-editable:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); cursor: text; }
|
|
107
|
-
/* crisp/#758: AI-enriched column marker, ported from RecordsTable's own
|
|
108
|
-
|
|
109
|
-
composited OVER whatever row-state background the cell already has
|
|
110
|
-
(hover, selected), which is why it's an ::after overlay and not a plain background. */
|
|
111
|
+
/* crisp/#758: AI-enriched column marker, ported from RecordsTable's own already-measured value -- a full-bleed #9b69ff (bgPurple) wash at 4%, composited OVER whatever row-state background the cell already has (hover, selected), which is why it's an ::after overlay and not a
|
|
112
|
+
plain background. */
|
|
111
113
|
& td[data-enriched]::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: color-mix(in srgb, var(--crisp-bg-purple) 4%, transparent); }
|
|
112
114
|
& .crisp-datatable-edit { width: 100%; height: 28px; margin: 0; padding: 0 var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; vertical-align: middle; }
|
|
113
115
|
& .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
114
|
-
/* An async onEdit's in-flight state (#385) -- the field/picker dims and
|
|
115
|
-
stops accepting input rather than disappearing, so the just-typed or
|
|
116
|
-
just-chosen value stays visible while its commit is pending. Same
|
|
117
|
-
treatment Input already gives its own disabled state. */
|
|
116
|
+
/* An async onEdit's in-flight state (#385) -- the field/picker dims and stops accepting input rather than disappearing, so the just-typed or just-chosen value stays visible while its commit is pending. Same treatment Input already gives its own disabled state. */
|
|
118
117
|
& .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
119
118
|
& .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
|
|
120
|
-
/* The rejection's message, beside the cell's own content -- a sibling in
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
the row below, so it can never end up clipped by the scroll
|
|
124
|
-
container's overflow the way a position:fixed escape would need guarding against. */
|
|
119
|
+
/* The rejection's message, beside the cell's own content -- a sibling in the TableCell, never nested inside a column's own render output, so a
|
|
120
|
+
hover-only wrapper (a Tooltip, say) around a custom render can't hide it. Block-level: the row grows to fit it rather than floating over the row below, so it can never end up clipped by the scroll container's overflow the way a position:fixed escape would need
|
|
121
|
+
guarding against. */
|
|
125
122
|
& .crisp-datatable-edit-error { display: block; padding: var(--crisp-space-0-5) 0 0; font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
126
|
-
/* editor: "select"/"switch" -- always live, no separate edit mode, so
|
|
127
|
-
|
|
123
|
+
/* editor: "select"/"switch" -- always live, no separate edit mode, so
|
|
124
|
+
the cell IS the picker: same chromeless-fill treatment as
|
|
125
|
+
RecordsTable's own --picker cells (measured there already; DataTable shares RecordsTable's grid, Golden Rule 0). */
|
|
128
126
|
& .crisp-datatable-td--picker { padding: 0; }
|
|
129
127
|
& .crisp-datatable-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
130
128
|
& .crisp-datatable-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; height: 100%; min-height: 0; border-radius: 0; box-shadow: none; padding: 0; }
|
|
131
129
|
& .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
|
|
132
|
-
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
130
|
+
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
131
|
+
"Create X" row when the consumer supplies one (#449) -- same measured
|
|
132
|
+
values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
133
133
|
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
134
134
|
& .crisp-datatable-refoption-avatar { flex-shrink: 0; }
|
|
135
135
|
& .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
|
|
136
136
|
& .crisp-datatable-empty { padding: var(--crisp-space-8) var(--crisp-space-3); text-align: center; color: var(--crisp-fg-muted); font-size: var(--crisp-text-lg); }
|
|
137
|
+
/* #826 -- the full-body loading state (a filter/sort re-query, or a fresh page boot), measured live on Attio's Companies grid on both
|
|
138
|
+
triggers: icon+text centred in the row-body area, 10px gap, 14px/500
|
|
139
|
+
weight/20px line-height, both icon and text in the SAME muted
|
|
140
|
+
rgba(0,0,0,0.63) -- the same color-mix figure this file already uses
|
|
141
|
+
for other muted text (e.g. -phone-dial). Distinct from the cold
|
|
142
|
+
in-place row load (blank, no indicator) and the warm-navigation
|
|
143
|
+
per-cell shimmer (#599) -- neither of those swaps the whole body. */
|
|
144
|
+
& .crisp-datatable-loading { display: flex; align-items: center; justify-content: center; gap: 10px; padding: var(--crisp-space-8) var(--crisp-space-3); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); line-height: 20px; }
|
|
145
|
+
& .crisp-datatable-loading .crisp-spinner { border-top-color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
137
146
|
/* #579: click-to-expand overlay for a truncated cell -- a read-only,
|
|
138
147
|
full-value card, settled live as click (not Attio's usual hover-expand) and measured position: absolute, unlike this file's
|
|
139
148
|
floating chrome (Menu/Select popovers) which portals and escapes the
|
|
@@ -208,6 +217,9 @@
|
|
|
208
217
|
& .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)); }
|
|
209
218
|
& .crisp-datatable-num { font-variant-numeric: tabular-nums; }
|
|
210
219
|
& .crisp-datatable-muted { color: var(--crisp-fg-muted); }
|
|
220
|
+
/* crisp#822 -- a date/datetime cell's danger/overdue tone: same token as
|
|
221
|
+
TasksTable's own overdue due-date (crisp#462), plain text colour, no fill/weight change. */
|
|
222
|
+
& .crisp-datatable-danger { color: var(--crisp-fg-danger); }
|
|
211
223
|
/* url/email cell types (#654) -- same measured values as RecordsTable's
|
|
212
224
|
own .crisp-recordstable-link, which this mirrors: no underline at
|
|
213
225
|
rest, underline on hover, own-colour text rather than a browser-blue
|
|
@@ -221,26 +233,42 @@
|
|
|
221
233
|
& .crisp-datatable-phone-dial { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
222
234
|
& .crisp-datatable-phone-editor { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
223
235
|
& .crisp-datatable-phone-editor input { flex: 1; min-width: 0; }
|
|
236
|
+
/* country-picker option row (#842) -- confirmed live: Attio's own popover is plain text, no flag anywhere (not the option row, not the closed trigger), name opaque + dial code muted rgba(0,0,0,0.63) -- the SAME color-mix figure as -phone-dial above. The internal name/dial gap wasn't independently measured this pass (Attio's own two <div>s gave no exact number); reused space["1"], the same gap -phone already uses for its own flag/dial/digits row. */
|
|
237
|
+
& .crisp-datatable-country-option { display: flex; align-items: center; gap: var(--crisp-space-1); }
|
|
238
|
+
& .crisp-datatable-country-dial { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
239
|
+
/* multi-value phone (#816) -- confirmed live (a real custom "Multiple
|
|
240
|
+
values" Phone Number attribute, and the built-in People "Phone
|
|
241
|
+
numbers" field): the collapsed cell is a 4px-gap flex row of real tel: links in a measured link blue (~rgb(59,108,232) pixel-sampled; reused as the closest already-tokened blue, brand600, rather than adding a third blue token for a delta this small), underlined, UNLIKE the single-value cell above (plain text, no link, no underline) -- multi-value is the one shape Attio makes into a real link. The cell hard-clips on overflow (no ellipsis -- confirmed live, a second value can end mid-digit with no "..."). */
|
|
242
|
+
& .crisp-datatable-phone-multi { display: inline-flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
|
|
243
|
+
& .crisp-datatable-phone-link { color: var(--crisp-bg-brand-solid); text-decoration: underline; white-space: nowrap; }
|
|
244
|
+
/* multi-value editor (#816) -- confirmed live: a stack of committed- value rows (32px = size.menuRow, 5px 8px padding, 8px gap between the grip/value/actions, 16px icons) above one ALWAYS-blank trailing DataPhoneEditor-shaped row -- that blank row is the only "add
|
|
245
|
+
another" affordance, there's no separate button for it. The
|
|
246
|
+
copy/delete pair reuses .crisp-datatable-entity-action's own hover-reveal chrome (not independently re-measured as its own hit target this pass, only the 16px icon glyphs were). */
|
|
247
|
+
& .crisp-datatable-phone-multi-editor { display: flex; flex-direction: column; }
|
|
248
|
+
& .crisp-datatable-phone-multi-row { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); padding: 5px var(--crisp-space-2); }
|
|
249
|
+
& .crisp-datatable-phone-multi-row .crisp-datatable-phone-link { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
250
|
+
& .crisp-datatable-phone-multi-grip { color: var(--crisp-fg-muted); flex-shrink: 0; cursor: grab; }
|
|
251
|
+
& .crisp-datatable-phone-multi-actions { display: flex; align-items: center; gap: var(--crisp-space-1); margin-inline-start: auto; flex-shrink: 0; opacity: 0; }
|
|
252
|
+
& .crisp-datatable-phone-multi-row:hover .crisp-datatable-phone-multi-actions, & .crisp-datatable-phone-multi-actions:focus-within { opacity: 1; }
|
|
253
|
+
& .crisp-datatable-phone-multi-action { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; font-family: inherit; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); cursor: pointer; flex-shrink: 0; }
|
|
254
|
+
& .crisp-datatable-phone-multi-action:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
|
|
224
255
|
/* datetime cell editor (#762) -- DatePickerField + TimePicker side by side. */
|
|
225
256
|
& .crisp-datatable-datetime-editor { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
226
|
-
/* rating cell type/editor (#760) -- measured live: 16px stars on an
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
-- rgb(33,91,196) -- that's close to but NOT brand700/bgBrandSolidPressed (#1f5fd6); kept as its own literal rather than forced onto that token, since the two were measured stable and different. The read-only svg and the editable button's own inner svg both carry the
|
|
231
|
-
crisp-datatable-rating-star class on the svg itself (not the
|
|
232
|
-
button), so one set of fill rules covers both -- the button only
|
|
233
|
-
adds its own reset + cursor via a separate -btn class. */
|
|
257
|
+
/* rating cell type/editor (#760) -- measured live: 16px stars on an 18px pitch (a 2px gap), an empty star at rgba(0,0,0,0.1), a committed/filled star at brand600 (--crisp-bg-brand-solid, an exact match to the measured #266df0), and a distinct hover-preview colour -- rgb(33,91,196) -- that's close to but NOT brand700/bgBrandSolidPressed
|
|
258
|
+
(#1f5fd6); kept as its own literal rather than forced onto that token,
|
|
259
|
+
since the two were measured stable and different. The read-only svg
|
|
260
|
+
and the editable button's own inner svg both carry the crisp-datatable-rating-star class on the svg itself (not the button), so one set of fill rules covers both -- the button only adds its own reset + cursor via a separate -btn class. */
|
|
234
261
|
& .crisp-datatable-rating { display: inline-flex; align-items: center; gap: 2px; }
|
|
235
262
|
& .crisp-datatable-rating-star { display: block; }
|
|
236
263
|
& .crisp-datatable-rating-star path { fill: rgba(0, 0, 0, 0.1); }
|
|
237
264
|
& .crisp-datatable-rating-star[data-filled] path { fill: var(--crisp-bg-brand-solid); }
|
|
238
265
|
& .crisp-datatable-rating-star[data-hovering] path { fill: #215bc4; }
|
|
239
266
|
& .crisp-datatable-rating-star-btn { display: inline-flex; padding: 0; margin: 0; border: none; background: none; font-family: inherit; cursor: pointer; }
|
|
240
|
-
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
(RecordsTable's reorderColumn) -- not a proprietary
|
|
267
|
+
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures a leading 20px grip column, a 16px grip icon, and the row's own
|
|
268
|
+
hairline doubling as the drop indicator (it tints toward the brand
|
|
269
|
+
colour as the active drop target). The affordance + geometry are
|
|
270
|
+
measured; the drag MECHANISM is crisp's existing house idiom -- HTML5 draggable + dataTransfer, the same one column reorder already uses (RecordsTable's reorderColumn) -- not a proprietary
|
|
271
|
+
pointer-events implementation. */
|
|
244
272
|
& .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
|
|
245
273
|
& .crisp-datatable-grip { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 0; border: none; border-radius: 0; background: none; font-family: inherit; color: var(--crisp-fg-muted); cursor: grab; }
|
|
246
274
|
& .crisp-datatable-grip:active { cursor: grabbing; }
|
|
@@ -41,54 +41,58 @@
|
|
|
41
41
|
class + one element) -- a bare `& th` here only won by source
|
|
42
42
|
order, which flipped the moment table.recipe.ts's own CSS file happened to land after datatable's in the build (alphabetical:
|
|
43
43
|
datatable < table), silently reinstating 12px on every header cell
|
|
44
|
-
in the whole product and making every interactive column's button double it to 24px. Scoping through `.crisp-table` adds a second class to the selector (0,2,1 beats 0,1,1) so this can never lose a specificity tie to source order again.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
in the whole product and making every interactive column's button double it to 24px. Scoping through `.crisp-table` adds a second class to the selector (0,2,1 beats 0,1,1) so this can never lose a specificity tie to source order again. `thead th`, not a bare `th` (crisp#829): #779 made the primary column's BODY cell a real `<th scope="row">` for a11y, and a bare
|
|
45
|
+
`th` here matches that one too, zeroing an inset nothing else
|
|
46
|
+
supplies -- the primary column's text sat flush left, one column's
|
|
47
|
+
cell no longer matching its own header or any sibling `<td>`. Only
|
|
48
|
+
the header row's own `<th>` needs zero padding (its sort BUTTON owns the inset); the body row's `<th scope="row">` has no button,
|
|
49
|
+
and needs the SAME base 12px (table.recipe.ts, #465) every other
|
|
50
|
+
cell already gets. */
|
|
51
|
+
& .crisp-table thead th { padding: 0; }
|
|
52
|
+
/* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger): Menu wraps its trigger in a flex div that sizes to its content, so a long header grew past the column instead of filling it -- with nothing left to squeeze, the label's own ellipsis CSS (below) had no properly
|
|
53
|
+
-sized box to truncate against, and the th's own overflow hard-clipped it with no "...". Fill the wrapper, scoped to th so Menu's default
|
|
54
|
+
(correct everywhere else) is untouched. */
|
|
51
55
|
& th .crisp-menu { width: 100%; height: 100%; }
|
|
52
56
|
& .crisp-datatable-th-inner { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; }
|
|
53
57
|
& .crisp-datatable-th-inner > svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
54
|
-
/* crisp/#605 follow-up: a header with neither a Menu nor a sort button
|
|
55
|
-
columnMenu/sortable at all) renders .crisp-datatable-th-inner as a
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
plain sort `button` both put >=1 more level between `th` and this
|
|
61
|
-
span, so their own 12px (already on the button) isn't doubled. */
|
|
58
|
+
/* crisp/#605 follow-up: a header with neither a Menu nor a sort button
|
|
59
|
+
(the primary/entity column's now-inert path, or any column with no columnMenu/sortable at all) renders .crisp-datatable-th-inner as a DIRECT child of th instead of nested inside a button -- and loses the button's own 12px inset, drifting left of the td's 12px base inset. Measured live on Attio's own Companies grid: the header label
|
|
60
|
+
and the cell's own text land at the exact same x (335px from the viewport, both 40px from the column's left edge) via two different
|
|
61
|
+
padding+icon+gap combinations -- Attio does not leave the inert
|
|
62
|
+
primary header flush left either. The `>` combinator targets only
|
|
63
|
+
the button-less case: Menu's own wrapper (`.crisp-menu`) and the plain sort `button` both put >=1 more level between `th` and this span, so their own 12px (already on the button) isn't doubled. */
|
|
62
64
|
& th > .crisp-datatable-th-inner { box-sizing: border-box; padding: 0 var(--crisp-space-3); }
|
|
63
|
-
|
|
65
|
+
/* The summary cell has NO padding of its own -- the calculation trigger
|
|
66
|
+
owns the whole 246x37 area so a click anywhere in the cell opens the
|
|
67
|
+
menu. Zero the cell's inset and let ColumnCalc supply the 12px. */
|
|
64
68
|
& tfoot td { padding: 0; }
|
|
65
|
-
/* Group heading row -- a view is grouped under a subtle label with the
|
|
66
|
-
|
|
67
|
-
& .crisp-datatable-viewsettings { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
69
|
+
/* Group heading row -- a view is grouped under a subtle label with the bucket's count beside it. */
|
|
70
|
+
& .crisp-datatable-viewsettings { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-muted); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
68
71
|
& .crisp-datatable-viewsettings:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
|
|
69
72
|
& .crisp-datatable-group-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
70
|
-
|
|
73
|
+
& .crisp-datatable-group { height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-3); background: var(--crisp-bg-subtle); border-bottom: 1px solid var(--crisp-border-subtle); font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
71
74
|
& .crisp-datatable-group-count { margin-inline-start: var(--crisp-space-1-5); color: var(--crisp-fg-muted); font-variant-numeric: tabular-nums; }
|
|
72
75
|
& .crisp-datatable-th-rename { width: 100%; min-width: 0; height: var(--crisp-size-row); margin: 0; padding: 0 var(--crisp-space-1); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); outline: none; }
|
|
73
76
|
& .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
74
77
|
& .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
75
|
-
/* #465: 12px per the comment above (and Attio's measured header cell
|
|
76
|
-
padding: 0 12px) -- was still c.space["2"] (8px), drifted from its
|
|
77
|
-
own documented value. */
|
|
78
|
+
/* #465: 12px per the comment above (and Attio's measured header cell padding: 0 12px) -- was still c.space["2"] (8px), drifted from its own documented value. */
|
|
78
79
|
& .crisp-datatable-sort { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0 var(--crisp-space-3); border: none; background: none; font: inherit; letter-spacing: inherit; color: inherit; text-align: start; cursor: pointer; }
|
|
79
|
-
/* A right-aligned column's header keeps its field-icon + label packed at
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
/* A right-aligned column's header keeps its field-icon + label packed at
|
|
81
|
+
the START, matching its own values only in that the VALUES right-align
|
|
82
|
+
-- Attio's own right-aligned header (measured live: "Twitter follower
|
|
83
|
+
count") keeps the icon+label left and only the trailing column-menu icon sits pinned to the right edge, independent of the label's width
|
|
84
|
+
(#406, reversing #393's own justify-content: flex-end here). The chevron's own margin-inline-start: auto below already pins IT to the
|
|
85
|
+
end of a flex-start row with no override needed -- that's what pins the trailing icon on Attio too. */
|
|
84
86
|
& .crisp-datatable-chevron { margin-inline-start: auto; flex-shrink: 0; color: var(--crisp-fg-muted); opacity: 0; transition: opacity .12s; }
|
|
85
87
|
& .crisp-datatable-sort:hover .crisp-datatable-chevron { opacity: 0.6; }
|
|
86
88
|
& .crisp-datatable-sort[data-sorted] .crisp-datatable-chevron { opacity: 1; color: var(--crisp-fg-primary); }
|
|
87
89
|
/* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
|
|
88
90
|
& th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: var(--crisp-bg-surface); }
|
|
89
|
-
& th[data-sticky] { z-index: 3;
|
|
90
|
-
/* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
91
|
-
`tfoot td { z-index: 2 }
|
|
91
|
+
& th[data-sticky] { z-index: 3;
|
|
92
|
+
} /* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
93
|
+
`tfoot td { z-index: 2 }
|
|
94
|
+
`), which `td[data-sticky]`'s own higher-specificity
|
|
95
|
+
`z-index: 1` would otherwise undercut -- keep it level with the row it's in. */
|
|
92
96
|
& tfoot td[data-sticky] { z-index: 2; }
|
|
93
97
|
& tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
|
|
94
98
|
& tbody tr:hover td[data-sticky] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
|
|
@@ -105,36 +109,41 @@
|
|
|
105
109
|
& tbody tr[data-selected] td { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
|
|
106
110
|
& tbody tr[data-selected]:hover td { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface))); }
|
|
107
111
|
& .crisp-datatable-editable:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); cursor: text; }
|
|
108
|
-
/* crisp/#758: AI-enriched column marker, ported from RecordsTable's own
|
|
109
|
-
|
|
110
|
-
composited OVER whatever row-state background the cell already has
|
|
111
|
-
(hover, selected), which is why it's an ::after overlay and not a plain background. */
|
|
112
|
+
/* crisp/#758: AI-enriched column marker, ported from RecordsTable's own already-measured value -- a full-bleed #9b69ff (bgPurple) wash at 4%, composited OVER whatever row-state background the cell already has (hover, selected), which is why it's an ::after overlay and not a
|
|
113
|
+
plain background. */
|
|
112
114
|
& td[data-enriched]::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: color-mix(in srgb, var(--crisp-bg-purple) 4%, transparent); }
|
|
113
115
|
& .crisp-datatable-edit { width: 100%; height: 28px; margin: 0; padding: 0 var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; vertical-align: middle; }
|
|
114
116
|
& .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
115
|
-
/* An async onEdit's in-flight state (#385) -- the field/picker dims and
|
|
116
|
-
stops accepting input rather than disappearing, so the just-typed or
|
|
117
|
-
just-chosen value stays visible while its commit is pending. Same
|
|
118
|
-
treatment Input already gives its own disabled state. */
|
|
117
|
+
/* An async onEdit's in-flight state (#385) -- the field/picker dims and stops accepting input rather than disappearing, so the just-typed or just-chosen value stays visible while its commit is pending. Same treatment Input already gives its own disabled state. */
|
|
119
118
|
& .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
120
119
|
& .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
|
|
121
|
-
/* The rejection's message, beside the cell's own content -- a sibling in
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
the row below, so it can never end up clipped by the scroll
|
|
125
|
-
container's overflow the way a position:fixed escape would need guarding against. */
|
|
120
|
+
/* The rejection's message, beside the cell's own content -- a sibling in the TableCell, never nested inside a column's own render output, so a
|
|
121
|
+
hover-only wrapper (a Tooltip, say) around a custom render can't hide it. Block-level: the row grows to fit it rather than floating over the row below, so it can never end up clipped by the scroll container's overflow the way a position:fixed escape would need
|
|
122
|
+
guarding against. */
|
|
126
123
|
& .crisp-datatable-edit-error { display: block; padding: var(--crisp-space-0-5) 0 0; font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
127
|
-
/* editor: "select"/"switch" -- always live, no separate edit mode, so
|
|
128
|
-
|
|
124
|
+
/* editor: "select"/"switch" -- always live, no separate edit mode, so
|
|
125
|
+
the cell IS the picker: same chromeless-fill treatment as
|
|
126
|
+
RecordsTable's own --picker cells (measured there already; DataTable shares RecordsTable's grid, Golden Rule 0). */
|
|
129
127
|
& .crisp-datatable-td--picker { padding: 0; }
|
|
130
128
|
& .crisp-datatable-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
131
129
|
& .crisp-datatable-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; height: 100%; min-height: 0; border-radius: 0; box-shadow: none; padding: 0; }
|
|
132
130
|
& .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
|
|
133
|
-
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
131
|
+
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
132
|
+
"Create X" row when the consumer supplies one (#449) -- same measured
|
|
133
|
+
values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
134
134
|
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
135
135
|
& .crisp-datatable-refoption-avatar { flex-shrink: 0; }
|
|
136
136
|
& .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
|
|
137
137
|
& .crisp-datatable-empty { padding: var(--crisp-space-8) var(--crisp-space-3); text-align: center; color: var(--crisp-fg-muted); font-size: var(--crisp-text-lg); }
|
|
138
|
+
/* #826 -- the full-body loading state (a filter/sort re-query, or a fresh page boot), measured live on Attio's Companies grid on both
|
|
139
|
+
triggers: icon+text centred in the row-body area, 10px gap, 14px/500
|
|
140
|
+
weight/20px line-height, both icon and text in the SAME muted
|
|
141
|
+
rgba(0,0,0,0.63) -- the same color-mix figure this file already uses
|
|
142
|
+
for other muted text (e.g. -phone-dial). Distinct from the cold
|
|
143
|
+
in-place row load (blank, no indicator) and the warm-navigation
|
|
144
|
+
per-cell shimmer (#599) -- neither of those swaps the whole body. */
|
|
145
|
+
& .crisp-datatable-loading { display: flex; align-items: center; justify-content: center; gap: 10px; padding: var(--crisp-space-8) var(--crisp-space-3); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); line-height: 20px; }
|
|
146
|
+
& .crisp-datatable-loading .crisp-spinner { border-top-color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
138
147
|
/* #579: click-to-expand overlay for a truncated cell -- a read-only,
|
|
139
148
|
full-value card, settled live as click (not Attio's usual hover-expand) and measured position: absolute, unlike this file's
|
|
140
149
|
floating chrome (Menu/Select popovers) which portals and escapes the
|
|
@@ -209,6 +218,9 @@
|
|
|
209
218
|
& .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)); }
|
|
210
219
|
& .crisp-datatable-num { font-variant-numeric: tabular-nums; }
|
|
211
220
|
& .crisp-datatable-muted { color: var(--crisp-fg-muted); }
|
|
221
|
+
/* crisp#822 -- a date/datetime cell's danger/overdue tone: same token as
|
|
222
|
+
TasksTable's own overdue due-date (crisp#462), plain text colour, no fill/weight change. */
|
|
223
|
+
& .crisp-datatable-danger { color: var(--crisp-fg-danger); }
|
|
212
224
|
/* url/email cell types (#654) -- same measured values as RecordsTable's
|
|
213
225
|
own .crisp-recordstable-link, which this mirrors: no underline at
|
|
214
226
|
rest, underline on hover, own-colour text rather than a browser-blue
|
|
@@ -222,26 +234,42 @@
|
|
|
222
234
|
& .crisp-datatable-phone-dial { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
223
235
|
& .crisp-datatable-phone-editor { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
224
236
|
& .crisp-datatable-phone-editor input { flex: 1; min-width: 0; }
|
|
237
|
+
/* country-picker option row (#842) -- confirmed live: Attio's own popover is plain text, no flag anywhere (not the option row, not the closed trigger), name opaque + dial code muted rgba(0,0,0,0.63) -- the SAME color-mix figure as -phone-dial above. The internal name/dial gap wasn't independently measured this pass (Attio's own two <div>s gave no exact number); reused space["1"], the same gap -phone already uses for its own flag/dial/digits row. */
|
|
238
|
+
& .crisp-datatable-country-option { display: flex; align-items: center; gap: var(--crisp-space-1); }
|
|
239
|
+
& .crisp-datatable-country-dial { color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
240
|
+
/* multi-value phone (#816) -- confirmed live (a real custom "Multiple
|
|
241
|
+
values" Phone Number attribute, and the built-in People "Phone
|
|
242
|
+
numbers" field): the collapsed cell is a 4px-gap flex row of real tel: links in a measured link blue (~rgb(59,108,232) pixel-sampled; reused as the closest already-tokened blue, brand600, rather than adding a third blue token for a delta this small), underlined, UNLIKE the single-value cell above (plain text, no link, no underline) -- multi-value is the one shape Attio makes into a real link. The cell hard-clips on overflow (no ellipsis -- confirmed live, a second value can end mid-digit with no "..."). */
|
|
243
|
+
& .crisp-datatable-phone-multi { display: inline-flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
|
|
244
|
+
& .crisp-datatable-phone-link { color: var(--crisp-bg-brand-solid); text-decoration: underline; white-space: nowrap; }
|
|
245
|
+
/* multi-value editor (#816) -- confirmed live: a stack of committed- value rows (32px = size.menuRow, 5px 8px padding, 8px gap between the grip/value/actions, 16px icons) above one ALWAYS-blank trailing DataPhoneEditor-shaped row -- that blank row is the only "add
|
|
246
|
+
another" affordance, there's no separate button for it. The
|
|
247
|
+
copy/delete pair reuses .crisp-datatable-entity-action's own hover-reveal chrome (not independently re-measured as its own hit target this pass, only the 16px icon glyphs were). */
|
|
248
|
+
& .crisp-datatable-phone-multi-editor { display: flex; flex-direction: column; }
|
|
249
|
+
& .crisp-datatable-phone-multi-row { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); padding: 5px var(--crisp-space-2); }
|
|
250
|
+
& .crisp-datatable-phone-multi-row .crisp-datatable-phone-link { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
251
|
+
& .crisp-datatable-phone-multi-grip { color: var(--crisp-fg-muted); flex-shrink: 0; cursor: grab; }
|
|
252
|
+
& .crisp-datatable-phone-multi-actions { display: flex; align-items: center; gap: var(--crisp-space-1); margin-inline-start: auto; flex-shrink: 0; opacity: 0; }
|
|
253
|
+
& .crisp-datatable-phone-multi-row:hover .crisp-datatable-phone-multi-actions, & .crisp-datatable-phone-multi-actions:focus-within { opacity: 1; }
|
|
254
|
+
& .crisp-datatable-phone-multi-action { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; font-family: inherit; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); cursor: pointer; flex-shrink: 0; }
|
|
255
|
+
& .crisp-datatable-phone-multi-action:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); color: var(--crisp-fg-primary); }
|
|
225
256
|
/* datetime cell editor (#762) -- DatePickerField + TimePicker side by side. */
|
|
226
257
|
& .crisp-datatable-datetime-editor { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
227
|
-
/* rating cell type/editor (#760) -- measured live: 16px stars on an
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
-- rgb(33,91,196) -- that's close to but NOT brand700/bgBrandSolidPressed (#1f5fd6); kept as its own literal rather than forced onto that token, since the two were measured stable and different. The read-only svg and the editable button's own inner svg both carry the
|
|
232
|
-
crisp-datatable-rating-star class on the svg itself (not the
|
|
233
|
-
button), so one set of fill rules covers both -- the button only
|
|
234
|
-
adds its own reset + cursor via a separate -btn class. */
|
|
258
|
+
/* rating cell type/editor (#760) -- measured live: 16px stars on an 18px pitch (a 2px gap), an empty star at rgba(0,0,0,0.1), a committed/filled star at brand600 (--crisp-bg-brand-solid, an exact match to the measured #266df0), and a distinct hover-preview colour -- rgb(33,91,196) -- that's close to but NOT brand700/bgBrandSolidPressed
|
|
259
|
+
(#1f5fd6); kept as its own literal rather than forced onto that token,
|
|
260
|
+
since the two were measured stable and different. The read-only svg
|
|
261
|
+
and the editable button's own inner svg both carry the crisp-datatable-rating-star class on the svg itself (not the button), so one set of fill rules covers both -- the button only adds its own reset + cursor via a separate -btn class. */
|
|
235
262
|
& .crisp-datatable-rating { display: inline-flex; align-items: center; gap: 2px; }
|
|
236
263
|
& .crisp-datatable-rating-star { display: block; }
|
|
237
264
|
& .crisp-datatable-rating-star path { fill: rgba(0, 0, 0, 0.1); }
|
|
238
265
|
& .crisp-datatable-rating-star[data-filled] path { fill: var(--crisp-bg-brand-solid); }
|
|
239
266
|
& .crisp-datatable-rating-star[data-hovering] path { fill: #215bc4; }
|
|
240
267
|
& .crisp-datatable-rating-star-btn { display: inline-flex; padding: 0; margin: 0; border: none; background: none; font-family: inherit; cursor: pointer; }
|
|
241
|
-
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
(RecordsTable's reorderColumn) -- not a proprietary
|
|
268
|
+
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures a leading 20px grip column, a 16px grip icon, and the row's own
|
|
269
|
+
hairline doubling as the drop indicator (it tints toward the brand
|
|
270
|
+
colour as the active drop target). The affordance + geometry are
|
|
271
|
+
measured; the drag MECHANISM is crisp's existing house idiom -- HTML5 draggable + dataTransfer, the same one column reorder already uses (RecordsTable's reorderColumn) -- not a proprietary
|
|
272
|
+
pointer-events implementation. */
|
|
245
273
|
& .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
|
|
246
274
|
& .crisp-datatable-grip { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 0; border: none; border-radius: 0; background: none; font-family: inherit; color: var(--crisp-fg-muted); cursor: grab; }
|
|
247
275
|
& .crisp-datatable-grip:active { cursor: grabbing; }
|
|
@@ -18,16 +18,32 @@ const config = defineRecipe({
|
|
|
18
18
|
radius, and datatable-grip and the embedded pickers zero theirs. An 8px
|
|
19
19
|
radius survived the chip-to-full-cell conversion and shipped rounded
|
|
20
20
|
until #282, so the spec check now guards it. */
|
|
21
|
-
/* The hit target is the WHOLE summary cell -- measured
|
|
21
|
+
/* The hit target is the WHOLE summary cell -- measured 246x36 with
|
|
22
22
|
padding 0 12px, not a content-sized chip. Clicking anywhere in the cell
|
|
23
|
-
opens the aggregation menu.
|
|
24
|
-
|
|
23
|
+
opens the aggregation menu.
|
|
24
|
+
No \`min-height\` (crisp#834, found reproducing the footer-row-38px-
|
|
25
|
+
not-36px bug in an isolated browser test, not table.recipe.ts's own
|
|
26
|
+
border/box-sizing, the hypothesis the issue itself flagged as
|
|
27
|
+
unconfirmed): the table cell's OWN \`height: tableRow\` (36px,
|
|
28
|
+
border-box) leaves 34px of content box once its 2px of top+bottom
|
|
29
|
+
border are counted, and \`min-height: tableRow\` here demanded 36px
|
|
30
|
+
of CONTENT height regardless -- overflowing the cell by 2px, which
|
|
31
|
+
auto-height table layout resolves by growing the whole row to fit,
|
|
32
|
+
landing at exactly the reported 38. \`height: 100%\` alone already
|
|
33
|
+
fills whatever the cell's real content box is (the doc comment above
|
|
34
|
+
this rule's own stated intent), with nothing left demanding more. */
|
|
35
|
+
& .crisp-columncalc-trigger { display: flex; align-items: center; gap: ${c.space["1"]}; width: 100%; height: 100%; margin: 0; padding: 0 ${c.space["3"]}; border: none; background: transparent; color: ${c.fgMuted}; font-family: inherit; font-size: ${c.text.lg}; font-weight: ${c.weight.medium}; white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
25
36
|
& .crisp-columncalc-trigger:hover { background: color-mix(in srgb, ${c.fgPrimary} 4%, transparent); color: ${c.fgPrimary}; }
|
|
26
37
|
& .crisp-columncalc-trigger svg { flex-shrink: 0; opacity: 0.7; }
|
|
27
38
|
& .crisp-columncalc-trigger[data-align="right"] { justify-content: flex-end; }
|
|
28
39
|
& .crisp-columncalc-placeholder { overflow: hidden; text-overflow: ellipsis; }
|
|
29
40
|
& .crisp-columncalc-value { color: ${c.fgPrimary}; font-variant-numeric: tabular-nums; }
|
|
30
|
-
|
|
41
|
+
/* crisp#837: re-measured live against Attio's real footer calc label --
|
|
42
|
+
14px (was 13px, \`c.text.md\`, fixed on the shared trigger rule above)
|
|
43
|
+
and rgba(0,0,0,.63), the same color-mix(fgPrimary, 63%) figure this
|
|
44
|
+
file's own -op label already should have used instead of the flatter
|
|
45
|
+
\`fgMuted\` token (a close but not measured match). */
|
|
46
|
+
& .crisp-columncalc-op { color: color-mix(in srgb, ${c.fgPrimary} 63%, transparent); }
|
|
31
47
|
& .crisp-columncalc-section { padding: ${c.space["1.5"]} ${c.space["2"]} ${c.space["1"]}; font-size: ${c.text.sm}; font-weight: ${c.weight.medium}; color: ${c.fgMuted}; }`,
|
|
32
48
|
variants: {},
|
|
33
49
|
defaultVariants: {},
|