@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.
Files changed (53) hide show
  1. package/dist/button.css +3 -0
  2. package/dist/button.d.ts +2 -2
  3. package/dist/button.layered.css +3 -0
  4. package/dist/chip.css +1 -1
  5. package/dist/chip.layered.css +1 -1
  6. package/dist/cjs/components/breadcrumb/breadcrumb.js +1 -1
  7. package/dist/cjs/components/button/button.recipe.js +28 -0
  8. package/dist/cjs/components/chip/chip.recipe.js +3 -1
  9. package/dist/cjs/components/datatable/datatable.recipe.js +10 -4
  10. package/dist/cjs/components/datepickerfield/datepickerfield.js +2 -2
  11. package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +16 -3
  12. package/dist/cjs/components/menu/menu.js +18 -2
  13. package/dist/cjs/components/table/table.recipe.js +7 -1
  14. package/dist/cjs/core/floating-portal.js +7 -4
  15. package/dist/cjs/product/inbox/inbox.js +11 -3
  16. package/dist/cjs/product/recordpage/index.js +2 -1
  17. package/dist/cjs/product/recordpage/recordpage.js +49 -3
  18. package/dist/cjs/product/recordpage/recordpage.recipe.js +25 -0
  19. package/dist/datatable.css +10 -4
  20. package/dist/datatable.layered.css +10 -4
  21. package/dist/datepickerfield.css +8 -2
  22. package/dist/datepickerfield.d.ts +2 -2
  23. package/dist/datepickerfield.layered.css +8 -2
  24. package/dist/esm/components/breadcrumb/breadcrumb.js +1 -1
  25. package/dist/esm/components/button/button.recipe.js +28 -0
  26. package/dist/esm/components/chip/chip.recipe.js +3 -1
  27. package/dist/esm/components/datatable/datatable.recipe.js +10 -4
  28. package/dist/esm/components/datepickerfield/datepickerfield.js +2 -2
  29. package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +16 -3
  30. package/dist/esm/components/menu/menu.js +18 -2
  31. package/dist/esm/components/table/table.recipe.js +7 -1
  32. package/dist/esm/core/floating-portal.js +7 -4
  33. package/dist/esm/product/inbox/inbox.js +11 -3
  34. package/dist/esm/product/recordpage/index.js +1 -1
  35. package/dist/esm/product/recordpage/recordpage.js +49 -4
  36. package/dist/esm/product/recordpage/recordpage.recipe.js +25 -0
  37. package/dist/recordpage.css +23 -0
  38. package/dist/recordpage.layered.css +23 -0
  39. package/dist/styles.css +52 -9
  40. package/dist/styles.layered.css +52 -9
  41. package/dist/table.css +7 -2
  42. package/dist/table.layered.css +7 -2
  43. package/dist/types/components/breadcrumb/breadcrumb.d.ts +9 -1
  44. package/dist/types/components/button/button.d.ts +2 -0
  45. package/dist/types/components/button/button.recipe.d.ts +13 -0
  46. package/dist/types/components/chip/chip.recipe.d.ts +1 -1
  47. package/dist/types/components/datepickerfield/datepickerfield.d.ts +4 -1
  48. package/dist/types/components/datepickerfield/datepickerfield.recipe.d.ts +18 -3
  49. package/dist/types/core/floating-portal.d.ts +6 -5
  50. package/dist/types/product/inbox/inbox.d.ts +13 -1
  51. package/dist/types/product/recordpage/index.d.ts +1 -1
  52. package/dist/types/product/recordpage/recordpage.d.ts +46 -0
  53. 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: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
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
- & .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
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: hidden; text-overflow: ellipsis; }
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: hidden; 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); }
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: hidden; text-overflow: ellipsis; }
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
- & 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: hidden; text-overflow: ellipsis; }
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)); }
@@ -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: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
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
- & .crisp-datatable-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
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: hidden; text-overflow: ellipsis; }
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: hidden; 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); }
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: hidden; text-overflow: ellipsis; }
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
- & 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: hidden; text-overflow: ellipsis; }
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
- & 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: hidden; text-overflow: ellipsis; }
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]`,
@@ -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
- & 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: hidden; text-overflow: ellipsis; }
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
- onClick?: () => void;
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: "hidden";
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
- export declare const datepickerfieldRecipe: import("../..").RecipeFn<{}> & {
3
- config: import("../..").RecipeConfig<{}>;
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, which
19
- * starts `false` and is driven only by client interaction — never a prop a
20
- * fixture sets true at mount (unlike Dialog/Drawer/Command) — so this never
21
- * touches `document` during SSR, the same safety Tooltip already had.
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.ReactPortal;
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
- /** Empty-state text (shown when there are no notifications). */
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crisp-ui-kit/crisp",
3
- "version": "0.57.2",
3
+ "version": "0.57.3",
4
4
  "description": "A lean React design system, measured pixel-for-pixel from Attio.",
5
5
  "license": "MIT",
6
6
  "type": "module",