@crisp-ui-kit/crisp 0.57.2 → 0.57.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/button.css +3 -0
- package/dist/button.d.ts +2 -2
- package/dist/button.layered.css +3 -0
- package/dist/chip.css +1 -1
- package/dist/chip.layered.css +1 -1
- package/dist/cjs/components/breadcrumb/breadcrumb.js +1 -1
- package/dist/cjs/components/button/button.recipe.js +28 -0
- package/dist/cjs/components/chip/chip.recipe.js +3 -1
- package/dist/cjs/components/datatable/datatable.recipe.js +10 -4
- package/dist/cjs/components/datepickerfield/datepickerfield.js +2 -2
- package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +16 -3
- package/dist/cjs/components/menu/menu.js +18 -2
- package/dist/cjs/components/table/table.recipe.js +7 -1
- package/dist/cjs/core/floating-portal.js +7 -4
- package/dist/cjs/product/inbox/inbox.js +11 -3
- package/dist/cjs/product/recordpage/index.js +2 -1
- package/dist/cjs/product/recordpage/recordpage.js +49 -3
- package/dist/cjs/product/recordpage/recordpage.recipe.js +25 -0
- package/dist/datatable.css +10 -4
- package/dist/datatable.layered.css +10 -4
- package/dist/datepickerfield.css +8 -2
- package/dist/datepickerfield.d.ts +2 -2
- package/dist/datepickerfield.layered.css +8 -2
- package/dist/esm/components/breadcrumb/breadcrumb.js +1 -1
- package/dist/esm/components/button/button.recipe.js +28 -0
- package/dist/esm/components/chip/chip.recipe.js +3 -1
- package/dist/esm/components/datatable/datatable.recipe.js +10 -4
- package/dist/esm/components/datepickerfield/datepickerfield.js +2 -2
- package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +16 -3
- package/dist/esm/components/menu/menu.js +18 -2
- package/dist/esm/components/table/table.recipe.js +7 -1
- package/dist/esm/core/floating-portal.js +7 -4
- package/dist/esm/product/inbox/inbox.js +11 -3
- package/dist/esm/product/recordpage/index.js +1 -1
- package/dist/esm/product/recordpage/recordpage.js +49 -4
- package/dist/esm/product/recordpage/recordpage.recipe.js +25 -0
- package/dist/recordpage.css +23 -0
- package/dist/recordpage.layered.css +23 -0
- package/dist/styles.css +52 -9
- package/dist/styles.layered.css +52 -9
- package/dist/table.css +7 -2
- package/dist/table.layered.css +7 -2
- package/dist/types/components/breadcrumb/breadcrumb.d.ts +9 -1
- package/dist/types/components/button/button.d.ts +2 -0
- package/dist/types/components/button/button.recipe.d.ts +13 -0
- package/dist/types/components/chip/chip.recipe.d.ts +1 -1
- package/dist/types/components/datepickerfield/datepickerfield.d.ts +4 -1
- package/dist/types/components/datepickerfield/datepickerfield.recipe.d.ts +18 -3
- package/dist/types/core/floating-portal.d.ts +6 -5
- package/dist/types/product/inbox/inbox.d.ts +13 -1
- package/dist/types/product/recordpage/index.d.ts +1 -1
- package/dist/types/product/recordpage/recordpage.d.ts +46 -0
- package/package.json +1 -1
package/dist/styles.css
CHANGED
|
@@ -467,6 +467,9 @@
|
|
|
467
467
|
.crisp-button--size_sm {
|
|
468
468
|
height: 24px; padding-inline: var(--crisp-space-1-5); font-size: var(--crisp-text-md); border-radius: var(--crisp-radius-md);
|
|
469
469
|
}
|
|
470
|
+
.crisp-button--size_xs {
|
|
471
|
+
height: 20px; padding-inline: var(--crisp-space-1-5); font-size: 10px; font-weight: var(--crisp-weight-regular); line-height: 15px; letter-spacing: normal; border-radius: var(--crisp-radius-sm); gap: var(--crisp-space-1);
|
|
472
|
+
}
|
|
470
473
|
.crisp-button--size_md {
|
|
471
474
|
height: 28px; padding-inline: var(--crisp-space-2); font-size: var(--crisp-text-lg); border-radius: var(--crisp-radius-md);
|
|
472
475
|
&[data-icon-start] { padding-inline-start: var(--crisp-space-1-5); }
|
|
@@ -575,7 +578,7 @@
|
|
|
575
578
|
display: inline-flex; align-items: center; gap: 3px; height: var(--crisp-size-chip); min-width: 0; max-width: 100%; padding-inline: var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap;
|
|
576
579
|
}
|
|
577
580
|
.crisp-chip--truncate_true {
|
|
578
|
-
& .crisp-chip-label { min-width: 0; overflow:
|
|
581
|
+
& .crisp-chip-label { min-width: 0; overflow: clip; text-overflow: ellipsis; white-space: nowrap; display: block; }
|
|
579
582
|
}
|
|
580
583
|
.crisp-chip--truncate_false {
|
|
581
584
|
|
|
@@ -851,7 +854,13 @@
|
|
|
851
854
|
& .crisp-datatable-group-count { margin-inline-start: var(--crisp-space-1-5); color: var(--crisp-fg-muted); font-variant-numeric: tabular-nums; }
|
|
852
855
|
& .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; }
|
|
853
856
|
& .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
854
|
-
|
|
857
|
+
/* #719: overflow: clip, not hidden, on every truncation rule below --
|
|
858
|
+
hidden still honours a programmatic scrollLeft assignment (found via
|
|
859
|
+
a screenshot tool that pans anything with scrollWidth > clientWidth),
|
|
860
|
+
blanking or fragmenting the visible text even though real user
|
|
861
|
+
scrolling was already blocked. clip renders the ellipsis identically
|
|
862
|
+
and leaves no scroll position to move. */
|
|
863
|
+
& .crisp-datatable-th-label { overflow: clip; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
855
864
|
/* #465: 12px per the comment above (and Attio's measured header cell
|
|
856
865
|
padding: 0 12px) -- was still c.space["2"] (8px), drifted from its
|
|
857
866
|
own documented value. */
|
|
@@ -938,7 +947,7 @@
|
|
|
938
947
|
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
939
948
|
"Create X" row when the consumer supplies one (#449) -- same measured
|
|
940
949
|
values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
941
|
-
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow:
|
|
950
|
+
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: clip; text-overflow: ellipsis; }
|
|
942
951
|
& .crisp-datatable-refoption-avatar { flex-shrink: 0; }
|
|
943
952
|
& .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
|
|
944
953
|
& .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); }
|
|
@@ -1014,7 +1023,7 @@
|
|
|
1014
1023
|
(#833/#835/#848) that happened to apply the same 500 to every
|
|
1015
1024
|
primary-column body cell regardless of type. Made explicit here so
|
|
1016
1025
|
fixing that leak doesn't also (wrongly) drop entity names to 400. */
|
|
1017
|
-
& .crisp-datatable-entity-name { overflow:
|
|
1026
|
+
& .crisp-datatable-entity-name { overflow: clip; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--crisp-weight-medium); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); }
|
|
1018
1027
|
/* #893: shared by the button (onEntityClick, a different record) and
|
|
1019
1028
|
the anchor (href, the row's own record) -- was button-only, which
|
|
1020
1029
|
silently left a real <a> unstyled the day #893 added one. */
|
|
@@ -1065,7 +1074,7 @@
|
|
|
1065
1074
|
own .crisp-recordstable-link, which this mirrors: no underline at
|
|
1066
1075
|
rest, underline on hover, own-colour text rather than a browser-blue
|
|
1067
1076
|
link. */
|
|
1068
|
-
& .crisp-datatable-link { color: var(--crisp-fg-primary); text-decoration: none; overflow:
|
|
1077
|
+
& .crisp-datatable-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: clip; text-overflow: ellipsis; }
|
|
1069
1078
|
& .crisp-datatable-link:hover { text-decoration: underline; }
|
|
1070
1079
|
/* phone cell type/editor (#765) -- measured live: the dial-code prefix
|
|
1071
1080
|
is a muted rgba(0,0,0,0.63) at 14px, matching every other muted-text
|
|
@@ -1241,10 +1250,10 @@
|
|
|
1241
1250
|
|
|
1242
1251
|
.crisp-datepickerfield {
|
|
1243
1252
|
display: inline-flex; font-family: var(--crisp-font-sans);
|
|
1244
|
-
& .crisp-datepickerfield-box { display: inline-flex; align-items: center; box-sizing: border-box; height: 32px; margin: 0; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); }
|
|
1253
|
+
& .crisp-datepickerfield-box { display: inline-flex; align-items: center; width: 100%; box-sizing: border-box; height: 32px; margin: 0; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); }
|
|
1245
1254
|
& .crisp-datepickerfield-box[data-ghost] { background: transparent; box-shadow: none; }
|
|
1246
1255
|
& .crisp-datepickerfield-box[data-ghost]:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); }
|
|
1247
|
-
& .crisp-datepickerfield-trigger { display: inline-flex; align-items: center; gap: var(--crisp-space-2); height: 100%; padding: 0 var(--crisp-space-2-5); margin: 0; border: none; background: none; color: inherit; font-family: inherit; font-size: inherit; white-space: nowrap; cursor: pointer; }
|
|
1256
|
+
& .crisp-datepickerfield-trigger { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: var(--crisp-space-2); height: 100%; padding: 0 var(--crisp-space-2-5); margin: 0; border: none; background: none; color: inherit; font-family: inherit; font-size: inherit; white-space: nowrap; cursor: pointer; }
|
|
1248
1257
|
& .crisp-datepickerfield-box[data-placeholder] .crisp-datepickerfield-trigger { color: var(--crisp-fg-muted); }
|
|
1249
1258
|
& .crisp-datepickerfield-trigger svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
1250
1259
|
/* Reuses TableToolbar's measured filter-chip remove button
|
|
@@ -1259,6 +1268,12 @@
|
|
|
1259
1268
|
& .crisp-datepickerfield-preset { height: var(--crisp-size-chip); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-chip); background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-sm); cursor: pointer; }
|
|
1260
1269
|
& .crisp-datepickerfield-preset:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); }
|
|
1261
1270
|
}
|
|
1271
|
+
.crisp-datepickerfield--width_full {
|
|
1272
|
+
width: 100%;
|
|
1273
|
+
}
|
|
1274
|
+
.crisp-datepickerfield--width_auto {
|
|
1275
|
+
width: auto;
|
|
1276
|
+
}
|
|
1262
1277
|
|
|
1263
1278
|
.crisp-dialog {
|
|
1264
1279
|
display: contents; font-family: var(--crisp-font-sans);
|
|
@@ -2304,8 +2319,13 @@
|
|
|
2304
2319
|
/* #465: 12px, not crisp's old 8px -- measured on a live header cell
|
|
2305
2320
|
(padding: 0 12px) and independently on a body cell's text inset
|
|
2306
2321
|
(getBoundingClientRect delta from the cell edge). Matches
|
|
2307
|
-
ColumnCalc's own already-correct 12px trigger inset. */
|
|
2308
|
-
|
|
2322
|
+
ColumnCalc's own already-correct 12px trigger inset. */ /* #719: overflow: clip, not hidden -- both render the ellipsis
|
|
2323
|
+
identically, but hidden still honours a programmatic scrollLeft
|
|
2324
|
+
assignment (a screenshot tool, a browser extension) even though it
|
|
2325
|
+
already blocks user-driven wheel/scrollbar input; clip leaves no
|
|
2326
|
+
scroll position for anything to move, so the truncated text can
|
|
2327
|
+
never be panned out of view. */
|
|
2328
|
+
& th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: clip; text-overflow: ellipsis; }
|
|
2309
2329
|
/* #554: sticky on the vertical axis, mirroring RecordsTable's own
|
|
2310
2330
|
`.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
|
|
2311
2331
|
and below a sticky-column corner cell (DataTable's `th[data-sticky]`,
|
|
@@ -3677,6 +3697,29 @@
|
|
|
3677
3697
|
& .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
|
|
3678
3698
|
& .crisp-recordpage-emptycard { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-6) var(--crisp-space-3); border: 1px dashed var(--crisp-border-default); border-radius: var(--crisp-radius-xl); color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-align: center; }
|
|
3679
3699
|
& .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
|
|
3700
|
+
/* #622: the Activity tab's own toolbar -- "Filters" + "+ Add meeting",
|
|
3701
|
+
both the same measured button chrome as the topbar's own action
|
|
3702
|
+
buttons (28px, e.field shadow, 14/500 label). */
|
|
3703
|
+
& .crisp-recordpage-tabtoolbar { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); }
|
|
3704
|
+
/* #622: Files tab's empty state -- measured live on Attio's own record
|
|
3705
|
+
page (a company with no files uploaded). The 138x138 dotted-grid
|
|
3706
|
+
backdrop is the same measured tile EmptyState's records variant uses
|
|
3707
|
+
(crisp/#603), duplicated here rather than composed through that
|
|
3708
|
+
component because this surface's title (16/600) and body (14/500,
|
|
3709
|
+
63%-mixed fgPrimary, not the flat fgMuted EmptyState uses) measure to
|
|
3710
|
+
their own values, matching neither of that component's existing
|
|
3711
|
+
variants. */
|
|
3712
|
+
& .crisp-recordpage-panel--center { flex: 1; align-items: center; justify-content: center; }
|
|
3713
|
+
& .crisp-recordpage-illustrated { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); text-align: center; }
|
|
3714
|
+
& .crisp-recordpage-illustrated-icon { display: flex; align-items: center; justify-content: center; width: 138px; height: 138px; margin-bottom: var(--crisp-space-2); color: color-mix(in srgb, var(--crisp-fg-primary) 22%, transparent); background: radial-gradient(circle, color-mix(in srgb, var(--crisp-fg-primary) 12%, transparent) 1.2px, transparent 1.2px) 0 0 / 16px 16px; }
|
|
3715
|
+
& .crisp-recordpage-illustrated-title { font-size: var(--crisp-text-xl); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); }
|
|
3716
|
+
/* #988: the Calls tab's own gated state measures a larger 20/24 title
|
|
3717
|
+
than Files/Deals' 16/600 -- Attio's own "empty view" pattern (the
|
|
3718
|
+
same 20/600 EmptyState's page/records variants already carry, not a
|
|
3719
|
+
one-off). */
|
|
3720
|
+
& .crisp-recordpage-illustrated-title--lg { font-size: 20px; line-height: 24px; }
|
|
3721
|
+
& .crisp-recordpage-illustrated-desc { max-width: 320px; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
3722
|
+
& .crisp-recordpage-illustrated-actions { display: inline-flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--crisp-space-1-5); margin-top: var(--crisp-space-2); }
|
|
3680
3723
|
& .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
|
|
3681
3724
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
3682
3725
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
package/dist/styles.layered.css
CHANGED
|
@@ -468,6 +468,9 @@
|
|
|
468
468
|
.crisp-button--size_sm {
|
|
469
469
|
height: 24px; padding-inline: var(--crisp-space-1-5); font-size: var(--crisp-text-md); border-radius: var(--crisp-radius-md);
|
|
470
470
|
}
|
|
471
|
+
.crisp-button--size_xs {
|
|
472
|
+
height: 20px; padding-inline: var(--crisp-space-1-5); font-size: 10px; font-weight: var(--crisp-weight-regular); line-height: 15px; letter-spacing: normal; border-radius: var(--crisp-radius-sm); gap: var(--crisp-space-1);
|
|
473
|
+
}
|
|
471
474
|
.crisp-button--size_md {
|
|
472
475
|
height: 28px; padding-inline: var(--crisp-space-2); font-size: var(--crisp-text-lg); border-radius: var(--crisp-radius-md);
|
|
473
476
|
&[data-icon-start] { padding-inline-start: var(--crisp-space-1-5); }
|
|
@@ -576,7 +579,7 @@
|
|
|
576
579
|
display: inline-flex; align-items: center; gap: 3px; height: var(--crisp-size-chip); min-width: 0; max-width: 100%; padding-inline: var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap;
|
|
577
580
|
}
|
|
578
581
|
.crisp-chip--truncate_true {
|
|
579
|
-
& .crisp-chip-label { min-width: 0; overflow:
|
|
582
|
+
& .crisp-chip-label { min-width: 0; overflow: clip; text-overflow: ellipsis; white-space: nowrap; display: block; }
|
|
580
583
|
}
|
|
581
584
|
.crisp-chip--truncate_false {
|
|
582
585
|
|
|
@@ -852,7 +855,13 @@
|
|
|
852
855
|
& .crisp-datatable-group-count { margin-inline-start: var(--crisp-space-1-5); color: var(--crisp-fg-muted); font-variant-numeric: tabular-nums; }
|
|
853
856
|
& .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; }
|
|
854
857
|
& .crisp-datatable-th-rename:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
855
|
-
|
|
858
|
+
/* #719: overflow: clip, not hidden, on every truncation rule below --
|
|
859
|
+
hidden still honours a programmatic scrollLeft assignment (found via
|
|
860
|
+
a screenshot tool that pans anything with scrollWidth > clientWidth),
|
|
861
|
+
blanking or fragmenting the visible text even though real user
|
|
862
|
+
scrolling was already blocked. clip renders the ellipsis identically
|
|
863
|
+
and leaves no scroll position to move. */
|
|
864
|
+
& .crisp-datatable-th-label { overflow: clip; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
856
865
|
/* #465: 12px per the comment above (and Attio's measured header cell
|
|
857
866
|
padding: 0 12px) -- was still c.space["2"] (8px), drifted from its
|
|
858
867
|
own documented value. */
|
|
@@ -939,7 +948,7 @@
|
|
|
939
948
|
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
940
949
|
"Create X" row when the consumer supplies one (#449) -- same measured
|
|
941
950
|
values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
942
|
-
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow:
|
|
951
|
+
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: clip; text-overflow: ellipsis; }
|
|
943
952
|
& .crisp-datatable-refoption-avatar { flex-shrink: 0; }
|
|
944
953
|
& .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
|
|
945
954
|
& .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); }
|
|
@@ -1015,7 +1024,7 @@
|
|
|
1015
1024
|
(#833/#835/#848) that happened to apply the same 500 to every
|
|
1016
1025
|
primary-column body cell regardless of type. Made explicit here so
|
|
1017
1026
|
fixing that leak doesn't also (wrongly) drop entity names to 400. */
|
|
1018
|
-
& .crisp-datatable-entity-name { overflow:
|
|
1027
|
+
& .crisp-datatable-entity-name { overflow: clip; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--crisp-weight-medium); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); }
|
|
1019
1028
|
/* #893: shared by the button (onEntityClick, a different record) and
|
|
1020
1029
|
the anchor (href, the row's own record) -- was button-only, which
|
|
1021
1030
|
silently left a real <a> unstyled the day #893 added one. */
|
|
@@ -1066,7 +1075,7 @@
|
|
|
1066
1075
|
own .crisp-recordstable-link, which this mirrors: no underline at
|
|
1067
1076
|
rest, underline on hover, own-colour text rather than a browser-blue
|
|
1068
1077
|
link. */
|
|
1069
|
-
& .crisp-datatable-link { color: var(--crisp-fg-primary); text-decoration: none; overflow:
|
|
1078
|
+
& .crisp-datatable-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: clip; text-overflow: ellipsis; }
|
|
1070
1079
|
& .crisp-datatable-link:hover { text-decoration: underline; }
|
|
1071
1080
|
/* phone cell type/editor (#765) -- measured live: the dial-code prefix
|
|
1072
1081
|
is a muted rgba(0,0,0,0.63) at 14px, matching every other muted-text
|
|
@@ -1242,10 +1251,10 @@
|
|
|
1242
1251
|
|
|
1243
1252
|
.crisp-datepickerfield {
|
|
1244
1253
|
display: inline-flex; font-family: var(--crisp-font-sans);
|
|
1245
|
-
& .crisp-datepickerfield-box { display: inline-flex; align-items: center; box-sizing: border-box; height: 32px; margin: 0; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); }
|
|
1254
|
+
& .crisp-datepickerfield-box { display: inline-flex; align-items: center; width: 100%; box-sizing: border-box; height: 32px; margin: 0; border-radius: var(--crisp-radius-md); background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 7%, transparent); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); }
|
|
1246
1255
|
& .crisp-datepickerfield-box[data-ghost] { background: transparent; box-shadow: none; }
|
|
1247
1256
|
& .crisp-datepickerfield-box[data-ghost]:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); }
|
|
1248
|
-
& .crisp-datepickerfield-trigger { display: inline-flex; align-items: center; gap: var(--crisp-space-2); height: 100%; padding: 0 var(--crisp-space-2-5); margin: 0; border: none; background: none; color: inherit; font-family: inherit; font-size: inherit; white-space: nowrap; cursor: pointer; }
|
|
1257
|
+
& .crisp-datepickerfield-trigger { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: var(--crisp-space-2); height: 100%; padding: 0 var(--crisp-space-2-5); margin: 0; border: none; background: none; color: inherit; font-family: inherit; font-size: inherit; white-space: nowrap; cursor: pointer; }
|
|
1249
1258
|
& .crisp-datepickerfield-box[data-placeholder] .crisp-datepickerfield-trigger { color: var(--crisp-fg-muted); }
|
|
1250
1259
|
& .crisp-datepickerfield-trigger svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
1251
1260
|
/* Reuses TableToolbar's measured filter-chip remove button
|
|
@@ -1260,6 +1269,12 @@
|
|
|
1260
1269
|
& .crisp-datepickerfield-preset { height: var(--crisp-size-chip); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-chip); background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-sm); cursor: pointer; }
|
|
1261
1270
|
& .crisp-datepickerfield-preset:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); }
|
|
1262
1271
|
}
|
|
1272
|
+
.crisp-datepickerfield--width_full {
|
|
1273
|
+
width: 100%;
|
|
1274
|
+
}
|
|
1275
|
+
.crisp-datepickerfield--width_auto {
|
|
1276
|
+
width: auto;
|
|
1277
|
+
}
|
|
1263
1278
|
|
|
1264
1279
|
.crisp-dialog {
|
|
1265
1280
|
display: contents; font-family: var(--crisp-font-sans);
|
|
@@ -2305,8 +2320,13 @@
|
|
|
2305
2320
|
/* #465: 12px, not crisp's old 8px -- measured on a live header cell
|
|
2306
2321
|
(padding: 0 12px) and independently on a body cell's text inset
|
|
2307
2322
|
(getBoundingClientRect delta from the cell edge). Matches
|
|
2308
|
-
ColumnCalc's own already-correct 12px trigger inset. */
|
|
2309
|
-
|
|
2323
|
+
ColumnCalc's own already-correct 12px trigger inset. */ /* #719: overflow: clip, not hidden -- both render the ellipsis
|
|
2324
|
+
identically, but hidden still honours a programmatic scrollLeft
|
|
2325
|
+
assignment (a screenshot tool, a browser extension) even though it
|
|
2326
|
+
already blocks user-driven wheel/scrollbar input; clip leaves no
|
|
2327
|
+
scroll position for anything to move, so the truncated text can
|
|
2328
|
+
never be panned out of view. */
|
|
2329
|
+
& th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: clip; text-overflow: ellipsis; }
|
|
2310
2330
|
/* #554: sticky on the vertical axis, mirroring RecordsTable's own
|
|
2311
2331
|
`.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
|
|
2312
2332
|
and below a sticky-column corner cell (DataTable's `th[data-sticky]`,
|
|
@@ -3678,6 +3698,29 @@
|
|
|
3678
3698
|
& .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
|
|
3679
3699
|
& .crisp-recordpage-emptycard { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-6) var(--crisp-space-3); border: 1px dashed var(--crisp-border-default); border-radius: var(--crisp-radius-xl); color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-align: center; }
|
|
3680
3700
|
& .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
|
|
3701
|
+
/* #622: the Activity tab's own toolbar -- "Filters" + "+ Add meeting",
|
|
3702
|
+
both the same measured button chrome as the topbar's own action
|
|
3703
|
+
buttons (28px, e.field shadow, 14/500 label). */
|
|
3704
|
+
& .crisp-recordpage-tabtoolbar { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); }
|
|
3705
|
+
/* #622: Files tab's empty state -- measured live on Attio's own record
|
|
3706
|
+
page (a company with no files uploaded). The 138x138 dotted-grid
|
|
3707
|
+
backdrop is the same measured tile EmptyState's records variant uses
|
|
3708
|
+
(crisp/#603), duplicated here rather than composed through that
|
|
3709
|
+
component because this surface's title (16/600) and body (14/500,
|
|
3710
|
+
63%-mixed fgPrimary, not the flat fgMuted EmptyState uses) measure to
|
|
3711
|
+
their own values, matching neither of that component's existing
|
|
3712
|
+
variants. */
|
|
3713
|
+
& .crisp-recordpage-panel--center { flex: 1; align-items: center; justify-content: center; }
|
|
3714
|
+
& .crisp-recordpage-illustrated { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); text-align: center; }
|
|
3715
|
+
& .crisp-recordpage-illustrated-icon { display: flex; align-items: center; justify-content: center; width: 138px; height: 138px; margin-bottom: var(--crisp-space-2); color: color-mix(in srgb, var(--crisp-fg-primary) 22%, transparent); background: radial-gradient(circle, color-mix(in srgb, var(--crisp-fg-primary) 12%, transparent) 1.2px, transparent 1.2px) 0 0 / 16px 16px; }
|
|
3716
|
+
& .crisp-recordpage-illustrated-title { font-size: var(--crisp-text-xl); font-weight: var(--crisp-weight-semibold); color: var(--crisp-fg-primary); }
|
|
3717
|
+
/* #988: the Calls tab's own gated state measures a larger 20/24 title
|
|
3718
|
+
than Files/Deals' 16/600 -- Attio's own "empty view" pattern (the
|
|
3719
|
+
same 20/600 EmptyState's page/records variants already carry, not a
|
|
3720
|
+
one-off). */
|
|
3721
|
+
& .crisp-recordpage-illustrated-title--lg { font-size: 20px; line-height: 24px; }
|
|
3722
|
+
& .crisp-recordpage-illustrated-desc { max-width: 320px; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
3723
|
+
& .crisp-recordpage-illustrated-actions { display: inline-flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--crisp-space-1-5); margin-top: var(--crisp-space-2); }
|
|
3681
3724
|
& .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
|
|
3682
3725
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
3683
3726
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
package/dist/table.css
CHANGED
|
@@ -11,8 +11,13 @@
|
|
|
11
11
|
/* #465: 12px, not crisp's old 8px -- measured on a live header cell
|
|
12
12
|
(padding: 0 12px) and independently on a body cell's text inset
|
|
13
13
|
(getBoundingClientRect delta from the cell edge). Matches
|
|
14
|
-
ColumnCalc's own already-correct 12px trigger inset. */
|
|
15
|
-
|
|
14
|
+
ColumnCalc's own already-correct 12px trigger inset. */ /* #719: overflow: clip, not hidden -- both render the ellipsis
|
|
15
|
+
identically, but hidden still honours a programmatic scrollLeft
|
|
16
|
+
assignment (a screenshot tool, a browser extension) even though it
|
|
17
|
+
already blocks user-driven wheel/scrollbar input; clip leaves no
|
|
18
|
+
scroll position for anything to move, so the truncated text can
|
|
19
|
+
never be panned out of view. */
|
|
20
|
+
& th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: clip; text-overflow: ellipsis; }
|
|
16
21
|
/* #554: sticky on the vertical axis, mirroring RecordsTable's own
|
|
17
22
|
`.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
|
|
18
23
|
and below a sticky-column corner cell (DataTable's `th[data-sticky]`,
|
package/dist/table.layered.css
CHANGED
|
@@ -12,8 +12,13 @@
|
|
|
12
12
|
/* #465: 12px, not crisp's old 8px -- measured on a live header cell
|
|
13
13
|
(padding: 0 12px) and independently on a body cell's text inset
|
|
14
14
|
(getBoundingClientRect delta from the cell edge). Matches
|
|
15
|
-
ColumnCalc's own already-correct 12px trigger inset. */
|
|
16
|
-
|
|
15
|
+
ColumnCalc's own already-correct 12px trigger inset. */ /* #719: overflow: clip, not hidden -- both render the ellipsis
|
|
16
|
+
identically, but hidden still honours a programmatic scrollLeft
|
|
17
|
+
assignment (a screenshot tool, a browser extension) even though it
|
|
18
|
+
already blocks user-driven wheel/scrollbar input; clip leaves no
|
|
19
|
+
scroll position for anything to move, so the truncated text can
|
|
20
|
+
never be panned out of view. */
|
|
21
|
+
& th, & td { position: relative; height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-3); border-bottom: 1px solid var(--crisp-border-subtle); border-inline-end: 1px solid var(--crisp-border-subtle); text-align: start; vertical-align: middle; white-space: nowrap; overflow: clip; text-overflow: ellipsis; }
|
|
17
22
|
/* #554: sticky on the vertical axis, mirroring RecordsTable's own
|
|
18
23
|
`.crisp-recordstable-th`. z-index 2 sits above a plain body cell (auto)
|
|
19
24
|
and below a sticky-column corner cell (DataTable's `th[data-sticky]`,
|
|
@@ -3,7 +3,15 @@ export type BreadcrumbItem = {
|
|
|
3
3
|
label: React.ReactNode;
|
|
4
4
|
href?: string;
|
|
5
5
|
icon?: React.ReactNode;
|
|
6
|
-
|
|
6
|
+
/** Called on a plain left click. With `href` also set, this fires on the
|
|
7
|
+
* real `<a>` rather than replacing it with a `<button>` -- call
|
|
8
|
+
* `event.preventDefault()` yourself for client-side routing (e.g.
|
|
9
|
+
* react-router's `navigate()`), the same division of labour `StatList`'s
|
|
10
|
+
* own `href`+`onClick` pair already uses. Right-click, middle-click,
|
|
11
|
+
* ctrl/cmd-click and the status-bar hover keep working since the
|
|
12
|
+
* element stays a real anchor. Without `href`, this renders a plain
|
|
13
|
+
* button (unchanged). */
|
|
14
|
+
onClick?: (event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>) => void;
|
|
7
15
|
};
|
|
8
16
|
export type BreadcrumbProps = React.ComponentPropsWithoutRef<"nav"> & {
|
|
9
17
|
items: BreadcrumbItem[];
|
|
@@ -15,6 +15,7 @@ export declare const Button: React.ForwardRefExoticComponent<Omit<React.Detailed
|
|
|
15
15
|
};
|
|
16
16
|
readonly size: {
|
|
17
17
|
readonly sm: string;
|
|
18
|
+
readonly xs: string;
|
|
18
19
|
readonly md: string;
|
|
19
20
|
readonly lg: string;
|
|
20
21
|
};
|
|
@@ -36,6 +37,7 @@ export declare const Button: React.ForwardRefExoticComponent<Omit<React.Detailed
|
|
|
36
37
|
};
|
|
37
38
|
readonly size: {
|
|
38
39
|
readonly sm: string;
|
|
40
|
+
readonly xs: string;
|
|
39
41
|
readonly md: string;
|
|
40
42
|
readonly lg: string;
|
|
41
43
|
};
|
|
@@ -99,6 +99,16 @@ declare const spec: {
|
|
|
99
99
|
readonly fontSize: `var(--${string})`;
|
|
100
100
|
readonly borderRadius: `var(--${string})`;
|
|
101
101
|
};
|
|
102
|
+
readonly xs: {
|
|
103
|
+
readonly height: "20px";
|
|
104
|
+
readonly paddingInline: `var(--${string})`;
|
|
105
|
+
readonly fontSize: "10px";
|
|
106
|
+
readonly fontWeight: `var(--${string})`;
|
|
107
|
+
readonly lineHeight: "15px";
|
|
108
|
+
readonly letterSpacing: "normal";
|
|
109
|
+
readonly borderRadius: `var(--${string})`;
|
|
110
|
+
readonly gap: `var(--${string})`;
|
|
111
|
+
};
|
|
102
112
|
readonly md: {
|
|
103
113
|
readonly decls: {
|
|
104
114
|
readonly height: "28px";
|
|
@@ -172,6 +182,7 @@ declare const config: import("../..").RecipeConfig<{
|
|
|
172
182
|
};
|
|
173
183
|
readonly size: {
|
|
174
184
|
readonly sm: string;
|
|
185
|
+
readonly xs: string;
|
|
175
186
|
readonly md: string;
|
|
176
187
|
readonly lg: string;
|
|
177
188
|
};
|
|
@@ -193,6 +204,7 @@ export declare const buttonRecipe: import("../..").RecipeFn<{
|
|
|
193
204
|
};
|
|
194
205
|
readonly size: {
|
|
195
206
|
readonly sm: string;
|
|
207
|
+
readonly xs: string;
|
|
196
208
|
readonly md: string;
|
|
197
209
|
readonly lg: string;
|
|
198
210
|
};
|
|
@@ -214,6 +226,7 @@ export declare const buttonRecipe: import("../..").RecipeFn<{
|
|
|
214
226
|
};
|
|
215
227
|
readonly size: {
|
|
216
228
|
readonly sm: string;
|
|
229
|
+
readonly xs: string;
|
|
217
230
|
readonly md: string;
|
|
218
231
|
readonly lg: string;
|
|
219
232
|
};
|
|
@@ -22,7 +22,7 @@ declare const spec: {
|
|
|
22
22
|
readonly selector: "& .crisp-chip-label";
|
|
23
23
|
readonly decls: {
|
|
24
24
|
readonly minWidth: 0;
|
|
25
|
-
readonly overflow: "
|
|
25
|
+
readonly overflow: "clip";
|
|
26
26
|
readonly textOverflow: "ellipsis";
|
|
27
27
|
readonly whiteSpace: "nowrap";
|
|
28
28
|
readonly display: "block";
|
|
@@ -29,6 +29,9 @@ export type DatePickerFieldProps = Omit<React.ComponentPropsWithoutRef<"div">, "
|
|
|
29
29
|
placeholder?: string;
|
|
30
30
|
/** `default` = outlined trigger; `ghost` = transparent (for table cells). */
|
|
31
31
|
variant?: "default" | "ghost";
|
|
32
|
+
/** `full` (default) fills its container, like `Select`'s own default.
|
|
33
|
+
* `auto` sizes to content, the field's only behaviour before crisp#980. */
|
|
34
|
+
width?: "full" | "auto";
|
|
32
35
|
/** Formats the trigger label (default: e.g. "Jun 3, 2026"). */
|
|
33
36
|
format?: (date: Date) => string;
|
|
34
37
|
/**
|
|
@@ -51,7 +54,7 @@ export type DatePickerFieldProps = Omit<React.ComponentPropsWithoutRef<"div">, "
|
|
|
51
54
|
* popover. This is what `DatePicker` used to be; `DatePicker` is now
|
|
52
55
|
* seed-design's bare calendar, and this composes it.
|
|
53
56
|
*/
|
|
54
|
-
export declare function DatePickerField({ value, defaultValue, onValueChange, onChange, placeholder: placeholderProp, variant, format, clearable, clearLabel: clearLabelProp, presets, calendarProps, "aria-label": ariaLabel, className, ...rest }: DatePickerFieldProps): React.JSX.Element;
|
|
57
|
+
export declare function DatePickerField({ value, defaultValue, onValueChange, onChange, placeholder: placeholderProp, variant, width, format, clearable, clearLabel: clearLabelProp, presets, calendarProps, "aria-label": ariaLabel, className, ...rest }: DatePickerFieldProps): React.JSX.Element;
|
|
55
58
|
export declare namespace DatePickerField {
|
|
56
59
|
var displayName: string;
|
|
57
60
|
}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
declare const config: import("../..").RecipeConfig<{
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
declare const config: import("../..").RecipeConfig<{
|
|
2
|
+
width: {
|
|
3
|
+
full: string;
|
|
4
|
+
auto: string;
|
|
5
|
+
};
|
|
6
|
+
}>;
|
|
7
|
+
export declare const datepickerfieldRecipe: import("../..").RecipeFn<{
|
|
8
|
+
width: {
|
|
9
|
+
full: string;
|
|
10
|
+
auto: string;
|
|
11
|
+
};
|
|
12
|
+
}> & {
|
|
13
|
+
config: import("../..").RecipeConfig<{
|
|
14
|
+
width: {
|
|
15
|
+
full: string;
|
|
16
|
+
auto: string;
|
|
17
|
+
};
|
|
18
|
+
}>;
|
|
4
19
|
};
|
|
5
20
|
export default config;
|
|
@@ -15,10 +15,11 @@ import * as React from "react";
|
|
|
15
15
|
* `Dialog` was rendering offset by the dialog's own box instead of anchored
|
|
16
16
|
* to its trigger.
|
|
17
17
|
*
|
|
18
|
-
* Every caller renders this conditionally on its own `open` state
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Every caller renders this conditionally on its own `open` state. A fixture
|
|
19
|
+
* CAN set that true at mount (crisp#964 needs exactly that, to give Menu's
|
|
20
|
+
* roving-tabindex guard something to inspect), so this checks for `window`
|
|
21
|
+
* itself rather than assuming the caller never does — the same guard
|
|
22
|
+
* `@zag-js/react`'s own `Portal` uses for the identical reason.
|
|
22
23
|
*
|
|
23
24
|
* `sourceRef` is the caller's own root — still in its original DOM position,
|
|
24
25
|
* never portaled — used to carry a `data-theme` set on some ancestor of it
|
|
@@ -36,4 +37,4 @@ import * as React from "react";
|
|
|
36
37
|
export declare function FloatingPortal({ children, sourceRef, }: {
|
|
37
38
|
children: React.ReactElement;
|
|
38
39
|
sourceRef: React.RefObject<HTMLElement | null>;
|
|
39
|
-
}): React.
|
|
40
|
+
}): React.ReactElement;
|
|
@@ -15,6 +15,14 @@ export type InboxTab = {
|
|
|
15
15
|
label: React.ReactNode;
|
|
16
16
|
count?: number;
|
|
17
17
|
disabled?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Empty-state copy for this tab only, e.g. Notifications vs. Requests
|
|
20
|
+
* ("Requests from other users will be displayed here."). Falls back to
|
|
21
|
+
* the instance-level `emptyTitle`/`emptySubtitle`/`emptyAction` when unset.
|
|
22
|
+
*/
|
|
23
|
+
emptyTitle?: React.ReactNode;
|
|
24
|
+
emptySubtitle?: React.ReactNode;
|
|
25
|
+
emptyAction?: React.ReactNode;
|
|
18
26
|
};
|
|
19
27
|
export type InboxProps = Omit<React.ComponentPropsWithoutRef<"div">, "children" | "title"> & {
|
|
20
28
|
notifications?: InboxNotification[];
|
|
@@ -23,7 +31,11 @@ export type InboxProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"
|
|
|
23
31
|
tabs?: InboxTab[];
|
|
24
32
|
activeTab?: string;
|
|
25
33
|
onTabChange?: (id: string) => void;
|
|
26
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Empty-state text (shown when there are no notifications). A tab in
|
|
36
|
+
* `tabs` that sets its own `emptyTitle`/`emptySubtitle` overrides this
|
|
37
|
+
* for that tab only.
|
|
38
|
+
*/
|
|
27
39
|
emptyTitle?: React.ReactNode;
|
|
28
40
|
emptySubtitle?: React.ReactNode;
|
|
29
41
|
/** Optional action under the empty state (e.g. a Settings button). */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { type Column, type ColumnType, type EntityValue, type ReferenceOption, type Row, type StatusOption, tagTone, } from "./column";
|
|
2
2
|
export { type EditableOption, editableInputType, useEditableField, } from "./editable-field";
|
|
3
|
-
export { RecordDetails, type RecordDetailsProps, RecordPage, type RecordPageHighlight, type RecordPageLabels, type RecordPageLabelsInput, type RecordPageNote, type RecordPageProps, type RecordPageSection, type RecordPageTab, type RecordPageTask, recordPageLabels, } from "./recordpage";
|
|
3
|
+
export { RecordDetails, type RecordDetailsProps, RecordPage, type RecordPageHighlight, type RecordPageLabels, type RecordPageLabelsInput, RecordPageMain, type RecordPageMainProps, type RecordPageNote, type RecordPageProps, type RecordPageSection, type RecordPageTab, type RecordPageTask, recordPageLabels, } from "./recordpage";
|
|
4
4
|
export { recordpageRecipe } from "./recordpage.recipe";
|
|
@@ -239,6 +239,29 @@ export type RecordPageLabels = {
|
|
|
239
239
|
comments: string;
|
|
240
240
|
/** Empty state under the Lists panel. */
|
|
241
241
|
noLists: string;
|
|
242
|
+
/** Activity tab toolbar (#622). */
|
|
243
|
+
filters: string;
|
|
244
|
+
addMeeting: string;
|
|
245
|
+
/** Files tab empty state (#622): title, hint body, and its two actions. */
|
|
246
|
+
noFiles: string;
|
|
247
|
+
filesHint: string;
|
|
248
|
+
newFolder: string;
|
|
249
|
+
uploadFile: string;
|
|
250
|
+
/** aria-label on the Files tab empty state's "⋮" overflow button (#622). */
|
|
251
|
+
fileMoreActions: string;
|
|
252
|
+
/** Associated deals tab empty state (#622). */
|
|
253
|
+
noDealsFound: string;
|
|
254
|
+
noDealsHint: string;
|
|
255
|
+
newDeal: string;
|
|
256
|
+
/** Emails tab empty state (#987): the dedicated tab's own illustrated
|
|
257
|
+
* state, distinct from `noEmailsWith` (Overview's condensed embed). */
|
|
258
|
+
noEmails: string;
|
|
259
|
+
noEmailsHint: string;
|
|
260
|
+
configureMailbox: string;
|
|
261
|
+
/** Calls tab empty state (#988): chrome only, no real gating. */
|
|
262
|
+
upgradeToViewCalls: string;
|
|
263
|
+
callsUpgradeHint: string;
|
|
264
|
+
upgrade: string;
|
|
242
265
|
highlights: string;
|
|
243
266
|
recordDetails: string;
|
|
244
267
|
searchFields: string;
|
|
@@ -347,6 +370,29 @@ export declare function RecordDetails({ record, columns, sections, onEdit, label
|
|
|
347
370
|
export declare namespace RecordDetails {
|
|
348
371
|
var displayName: string;
|
|
349
372
|
}
|
|
373
|
+
export type RecordPageMainProps = React.ComponentPropsWithoutRef<"main">;
|
|
374
|
+
/**
|
|
375
|
+
* The main/tab-content column's own box, on its own (#750) — the same
|
|
376
|
+
* "standalone piece" `RecordDetails` already is for the Details column,
|
|
377
|
+
* mirrored to the other side of the layout. `RecordPage` composes this
|
|
378
|
+
* internally for its own tabbed body (below) — this exact box, not a second
|
|
379
|
+
* copy — so a consumer building a custom record page (its own tab set, its
|
|
380
|
+
* own menu, `RecordDetails` for the left column, but not the full
|
|
381
|
+
* `RecordPage`, which hardcodes the CRM tab set) gets the same
|
|
382
|
+
* Attio-measured inset: `flex: 1; min-width: 0; display: flex;
|
|
383
|
+
* flex-direction: column; min-height: 0; overflow-y: auto; padding: 12px
|
|
384
|
+
* 20px` (`recordpage.recipe.ts`'s own `.crisp-recordpage-main`) — without
|
|
385
|
+
* reaching for that internal class name directly, the only option before
|
|
386
|
+
* this existed.
|
|
387
|
+
*
|
|
388
|
+
* Needs the same single `.crisp-recordpage`-scoped ancestor `RecordDetails`
|
|
389
|
+
* already documents — wrap both in `recordpageRecipe()`, the way
|
|
390
|
+
* `RecordPage`'s own root does.
|
|
391
|
+
*/
|
|
392
|
+
export declare function RecordPageMain({ className, children, ...rest }: RecordPageMainProps): React.JSX.Element;
|
|
393
|
+
export declare namespace RecordPageMain {
|
|
394
|
+
var displayName: string;
|
|
395
|
+
}
|
|
350
396
|
/**
|
|
351
397
|
* The full-page company record view — the page that opens when you click into a
|
|
352
398
|
* record (as opposed to the peek [RecordPanel]). A top breadcrumb bar with
|