@crisp-ui-kit/crisp 0.54.8 → 0.54.9
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/board.css +32 -8
- package/dist/board.layered.css +32 -8
- package/dist/cjs/components/contextmenu/contextmenu.js +2 -2
- package/dist/cjs/components/contextmenu/contextmenu.recipe.js +24 -0
- package/dist/cjs/components/datatable/datatable.js +541 -51
- package/dist/cjs/components/datatable/datatable.recipe.js +61 -3
- package/dist/cjs/components/dialog/dialog.js +65 -1
- package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +37 -2
- package/dist/cjs/components/tabletoolbar/tabletoolbar.js +148 -15
- package/dist/cjs/components/tabletoolbar/tabletoolbar.recipe.js +35 -1
- package/dist/cjs/product/board/board.js +62 -28
- package/dist/cjs/product/board/board.recipe.js +42 -2
- package/dist/cjs/product/comments/comments.js +11 -2
- package/dist/cjs/product/comments/comments.recipe.js +14 -4
- package/dist/cjs/product/recordstable/recordstable.js +1 -17
- package/dist/cjs/product/savedviews/savedviews.js +55 -24
- package/dist/cjs/product/savedviews/savedviews.recipe.js +27 -0
- package/dist/comments.css +14 -4
- package/dist/comments.layered.css +14 -4
- package/dist/contextmenu.css +24 -0
- package/dist/contextmenu.layered.css +24 -0
- package/dist/datatable.css +103 -77
- package/dist/datatable.layered.css +103 -77
- package/dist/esm/components/contextmenu/contextmenu.js +2 -2
- package/dist/esm/components/contextmenu/contextmenu.recipe.js +24 -0
- package/dist/esm/components/datatable/datatable.js +541 -52
- package/dist/esm/components/datatable/datatable.recipe.js +62 -4
- package/dist/esm/components/dialog/dialog.js +65 -1
- package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +37 -2
- package/dist/esm/components/tabletoolbar/tabletoolbar.js +149 -16
- package/dist/esm/components/tabletoolbar/tabletoolbar.recipe.js +37 -3
- package/dist/esm/product/board/board.js +63 -29
- package/dist/esm/product/board/board.recipe.js +42 -2
- package/dist/esm/product/comments/comments.js +12 -3
- package/dist/esm/product/comments/comments.recipe.js +14 -4
- package/dist/esm/product/recordstable/recordstable.js +2 -18
- package/dist/esm/product/savedviews/savedviews.js +57 -26
- package/dist/esm/product/savedviews/savedviews.recipe.js +27 -0
- package/dist/recordstable.css +33 -31
- package/dist/recordstable.layered.css +33 -31
- package/dist/savedviews.css +27 -0
- package/dist/savedviews.layered.css +27 -0
- package/dist/styles.css +266 -124
- package/dist/styles.layered.css +266 -124
- package/dist/tabletoolbar.css +33 -4
- package/dist/tabletoolbar.layered.css +33 -4
- package/dist/types/components/contextmenu/contextmenu.d.ts +8 -1
- package/dist/types/components/datatable/datatable.d.ts +90 -2
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +72 -2
- package/dist/types/product/board/board.d.ts +48 -2
- package/dist/types/product/comments/comments.d.ts +6 -1
- package/dist/types/product/recordstable/recordstable.d.ts +0 -1
- package/dist/types/product/savedviews/savedviews.d.ts +45 -8
- package/package.json +1 -1
package/dist/tabletoolbar.css
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
& .crisp-tabletoolbar-sort-learn { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); font-size: var(--crisp-text-lg); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); text-decoration: none; }
|
|
40
40
|
& .crisp-tabletoolbar-sort-learn svg { flex-shrink: 0; }
|
|
41
41
|
& .crisp-tabletoolbar-sort-learn:hover { color: var(--crisp-fg-primary); }
|
|
42
|
-
& .crisp-tabletoolbar-menu-item { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); text-align: left; cursor: pointer; }
|
|
42
|
+
& .crisp-tabletoolbar-menu-item { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); text-align: left; text-decoration: none; cursor: pointer; }
|
|
43
43
|
& .crisp-tabletoolbar-menu-item:hover { background: var(--crisp-bg-raised); }
|
|
44
44
|
& .crisp-tabletoolbar-menu-item:disabled { opacity: 0.4; cursor: default; }
|
|
45
45
|
& .crisp-tabletoolbar-menu-item:disabled:hover { background: none; }
|
|
@@ -47,7 +47,25 @@
|
|
|
47
47
|
& .crisp-tabletoolbar-menu-item[data-on] svg { color: var(--crisp-bg-brand-solid); }
|
|
48
48
|
& .crisp-tabletoolbar-menu-item .crisp-tabletoolbar-menu-check { margin-left: auto; }
|
|
49
49
|
& .crisp-tabletoolbar-menu-input { height: var(--crisp-size-row); margin: var(--crisp-space-0-5); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); background: var(--crisp-bg-surface); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; }
|
|
50
|
-
& .crisp-tabletoolbar-menu-sep { height: 1px; background: var(--crisp-border-subtle); margin: var(--crisp-space-0-5) 0; }
|
|
50
|
+
& .crisp-tabletoolbar-menu-sep { height: 1px; border: none; background: var(--crisp-border-subtle); margin: var(--crisp-space-0-5) 0; }
|
|
51
|
+
/* #592: the Filter field picker's nested-scope header (back control +
|
|
52
|
+
search, once drilled into a nestedColumns column) and a search
|
|
53
|
+
result's own breadcrumb row ("Team › Twitter follower count", surfaced by the SAME query matching a nested column). menu-back reuses the established 28px icon-only control pattern this file already uses twice (sort-remove, the kebab segment) rather than an independent measurement of Attio's own back arrow. The breadcrumb
|
|
54
|
+
colours ARE measured live: the parent segment muted at the same
|
|
55
|
+
exact color-mix 63% sort-learn above already uses, the
|
|
56
|
+
separator chevron and leaf segment both full fgPrimary (the
|
|
57
|
+
generic menu-item svg rule below defaults every icon to
|
|
58
|
+
fgMuted, so the separator needs its own override to read
|
|
59
|
+
correctly here). */
|
|
60
|
+
& .crisp-tabletoolbar-menu-nesthead { display: flex; align-items: center; gap: var(--crisp-space-1); margin: var(--crisp-space-0-5); }
|
|
61
|
+
& .crisp-tabletoolbar-menu-nesthead .crisp-tabletoolbar-menu-input { flex: 1; margin: 0; }
|
|
62
|
+
& .crisp-tabletoolbar-menu-back { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); cursor: pointer; }
|
|
63
|
+
& .crisp-tabletoolbar-menu-back:hover { background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); }
|
|
64
|
+
& .crisp-tabletoolbar-menu-item--expand { justify-content: space-between; }
|
|
65
|
+
& .crisp-tabletoolbar-menu-item-path { display: inline-flex; align-items: center; gap: 2px; min-width: 0; overflow: hidden; }
|
|
66
|
+
& .crisp-tabletoolbar-menu-item-path-parent { flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; max-width: 100px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
67
|
+
& .crisp-tabletoolbar-menu-item-path-sep { flex-shrink: 0; color: var(--crisp-fg-primary); }
|
|
68
|
+
& .crisp-tabletoolbar-menu-item-path > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
51
69
|
& .crisp-tabletoolbar-menu--up { top: auto; bottom: calc(100% + var(--crisp-space-1)); transform-origin: bottom; }
|
|
52
70
|
& .crisp-tabletoolbar-menu--right { left: auto; right: 0; }
|
|
53
71
|
& .crisp-tabletoolbar-menu--fixed { position: fixed; top: auto; left: auto; z-index: 40; }
|
|
@@ -68,12 +86,21 @@
|
|
|
68
86
|
& .crisp-tabletoolbar-count { font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
69
87
|
& .crisp-tabletoolbar-new { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); padding: 0 var(--crisp-space-2-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
|
|
70
88
|
& .crisp-tabletoolbar-new:hover { background: var(--crisp-bg-brand-solid-pressed); }
|
|
89
|
+
|
|
71
90
|
& .crisp-tabletoolbar-fcond { display: inline-flex; align-items: center; height: var(--crisp-size-row); font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); white-space: nowrap; }
|
|
72
91
|
& .crisp-tabletoolbar-fcond-seg { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: 100%; margin: 0; padding: 0 var(--crisp-space-2); border: none; background: var(--crisp-bg-surface-muted); box-shadow: inset 0 0 0 1px var(--crisp-border-divider); font-family: inherit; font-size: inherit; color: inherit; cursor: pointer; }
|
|
73
92
|
& .crisp-tabletoolbar-fcond-seg svg { flex-shrink: 0; }
|
|
74
|
-
& .crisp-tabletoolbar-fcond[data-complete] .crisp-tabletoolbar-fcond-seg--field,
|
|
75
|
-
& .crisp-tabletoolbar-fcond-
|
|
93
|
+
& .crisp-tabletoolbar-fcond[data-complete] .crisp-tabletoolbar-fcond-seg--field,
|
|
94
|
+
& .crisp-tabletoolbar-fcond[data-complete] .crisp-tabletoolbar-fcond-seg--val { background: var(--crisp-bg-surface); }
|
|
95
|
+
& .crisp-tabletoolbar-fcond-seg--field { border-radius: var(--crisp-radius-md) 0 0 var(--crisp-radius-md); font-weight: var(--crisp-weight-medium); max-width: 200px; }
|
|
76
96
|
& .crisp-tabletoolbar-fcond-seg--field svg { color: var(--crisp-fg-muted); }
|
|
97
|
+
/* #592: a nested pick's field segment ("Team › Twitter follower
|
|
98
|
+
count") — measured live: BOTH path segments the same colour (chip context only; the picker's own menu rows keep the parent muted, see
|
|
99
|
+
tabletoolbar.chrome.ts), each independently truncated. Attio's own layout gives the leaf segment priority (it stays fully readable longer, the parent truncates first) via a two-part min-content measurement this reproduces qualitatively with a flex-shrink differential rather than byte-for-byte (the exact px split Attio computes is content-length-dependent, not a fixed value) — not independently re-verified at other path-segment lengths. */
|
|
100
|
+
& .crisp-tabletoolbar-fcond-path { display: inline-flex; align-items: center; gap: 2px; min-width: 0; max-width: 178px; }
|
|
101
|
+
& .crisp-tabletoolbar-fcond-path-seg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 auto; }
|
|
102
|
+
& .crisp-tabletoolbar-fcond-path-seg:first-child { flex: 0 1 auto; }
|
|
103
|
+
& .crisp-tabletoolbar-fcond-path-sep { flex-shrink: 0; color: inherit; }
|
|
77
104
|
& .crisp-tabletoolbar-fcond-seg--op { background: var(--crisp-bg-surface); color: var(--crisp-fg-muted); }
|
|
78
105
|
& .crisp-tabletoolbar-fcond-seg--val { font-weight: var(--crisp-weight-medium); max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
|
|
79
106
|
& .crisp-tabletoolbar-fcond-seg--kebab { background: var(--crisp-bg-surface); justify-content: center; width: 28px; padding: 0; border-radius: 0 var(--crisp-radius-md) var(--crisp-radius-md) 0; color: var(--crisp-fg-muted); }
|
|
@@ -83,6 +110,8 @@
|
|
|
83
110
|
& .crisp-tabletoolbar-datepop-presets { display: flex; flex-wrap: wrap; gap: var(--crisp-space-1); margin-top: var(--crisp-space-2); padding: 0 var(--crisp-space-1); }
|
|
84
111
|
& .crisp-tabletoolbar-datepop-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; }
|
|
85
112
|
& .crisp-tabletoolbar-datepop-preset:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); }
|
|
113
|
+
& .crisp-tabletoolbar-tool--raised { border: none; background: var(--crisp-bg-surface-muted); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); font-family: inherit; cursor: pointer; }
|
|
114
|
+
[dir="rtl"] & [data-rtl-flip] { transform: scaleX(-1); }
|
|
86
115
|
}
|
|
87
116
|
|
|
88
117
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
& .crisp-tabletoolbar-sort-learn { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); font-size: var(--crisp-text-lg); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); text-decoration: none; }
|
|
41
41
|
& .crisp-tabletoolbar-sort-learn svg { flex-shrink: 0; }
|
|
42
42
|
& .crisp-tabletoolbar-sort-learn:hover { color: var(--crisp-fg-primary); }
|
|
43
|
-
& .crisp-tabletoolbar-menu-item { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); text-align: left; cursor: pointer; }
|
|
43
|
+
& .crisp-tabletoolbar-menu-item { display: flex; align-items: center; gap: var(--crisp-space-1-5); width: 100%; height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); text-align: left; text-decoration: none; cursor: pointer; }
|
|
44
44
|
& .crisp-tabletoolbar-menu-item:hover { background: var(--crisp-bg-raised); }
|
|
45
45
|
& .crisp-tabletoolbar-menu-item:disabled { opacity: 0.4; cursor: default; }
|
|
46
46
|
& .crisp-tabletoolbar-menu-item:disabled:hover { background: none; }
|
|
@@ -48,7 +48,25 @@
|
|
|
48
48
|
& .crisp-tabletoolbar-menu-item[data-on] svg { color: var(--crisp-bg-brand-solid); }
|
|
49
49
|
& .crisp-tabletoolbar-menu-item .crisp-tabletoolbar-menu-check { margin-left: auto; }
|
|
50
50
|
& .crisp-tabletoolbar-menu-input { height: var(--crisp-size-row); margin: var(--crisp-space-0-5); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle); background: var(--crisp-bg-surface); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; }
|
|
51
|
-
& .crisp-tabletoolbar-menu-sep { height: 1px; background: var(--crisp-border-subtle); margin: var(--crisp-space-0-5) 0; }
|
|
51
|
+
& .crisp-tabletoolbar-menu-sep { height: 1px; border: none; background: var(--crisp-border-subtle); margin: var(--crisp-space-0-5) 0; }
|
|
52
|
+
/* #592: the Filter field picker's nested-scope header (back control +
|
|
53
|
+
search, once drilled into a nestedColumns column) and a search
|
|
54
|
+
result's own breadcrumb row ("Team › Twitter follower count", surfaced by the SAME query matching a nested column). menu-back reuses the established 28px icon-only control pattern this file already uses twice (sort-remove, the kebab segment) rather than an independent measurement of Attio's own back arrow. The breadcrumb
|
|
55
|
+
colours ARE measured live: the parent segment muted at the same
|
|
56
|
+
exact color-mix 63% sort-learn above already uses, the
|
|
57
|
+
separator chevron and leaf segment both full fgPrimary (the
|
|
58
|
+
generic menu-item svg rule below defaults every icon to
|
|
59
|
+
fgMuted, so the separator needs its own override to read
|
|
60
|
+
correctly here). */
|
|
61
|
+
& .crisp-tabletoolbar-menu-nesthead { display: flex; align-items: center; gap: var(--crisp-space-1); margin: var(--crisp-space-0-5); }
|
|
62
|
+
& .crisp-tabletoolbar-menu-nesthead .crisp-tabletoolbar-menu-input { flex: 1; margin: 0; }
|
|
63
|
+
& .crisp-tabletoolbar-menu-back { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); cursor: pointer; }
|
|
64
|
+
& .crisp-tabletoolbar-menu-back:hover { background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); }
|
|
65
|
+
& .crisp-tabletoolbar-menu-item--expand { justify-content: space-between; }
|
|
66
|
+
& .crisp-tabletoolbar-menu-item-path { display: inline-flex; align-items: center; gap: 2px; min-width: 0; overflow: hidden; }
|
|
67
|
+
& .crisp-tabletoolbar-menu-item-path-parent { flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; max-width: 100px; color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); }
|
|
68
|
+
& .crisp-tabletoolbar-menu-item-path-sep { flex-shrink: 0; color: var(--crisp-fg-primary); }
|
|
69
|
+
& .crisp-tabletoolbar-menu-item-path > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
52
70
|
& .crisp-tabletoolbar-menu--up { top: auto; bottom: calc(100% + var(--crisp-space-1)); transform-origin: bottom; }
|
|
53
71
|
& .crisp-tabletoolbar-menu--right { left: auto; right: 0; }
|
|
54
72
|
& .crisp-tabletoolbar-menu--fixed { position: fixed; top: auto; left: auto; z-index: 40; }
|
|
@@ -69,12 +87,21 @@
|
|
|
69
87
|
& .crisp-tabletoolbar-count { font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
70
88
|
& .crisp-tabletoolbar-new { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-row); padding: 0 var(--crisp-space-2-5); border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; transition: background-color .12s; }
|
|
71
89
|
& .crisp-tabletoolbar-new:hover { background: var(--crisp-bg-brand-solid-pressed); }
|
|
90
|
+
|
|
72
91
|
& .crisp-tabletoolbar-fcond { display: inline-flex; align-items: center; height: var(--crisp-size-row); font-size: var(--crisp-text-md); color: var(--crisp-fg-primary); white-space: nowrap; }
|
|
73
92
|
& .crisp-tabletoolbar-fcond-seg { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: 100%; margin: 0; padding: 0 var(--crisp-space-2); border: none; background: var(--crisp-bg-surface-muted); box-shadow: inset 0 0 0 1px var(--crisp-border-divider); font-family: inherit; font-size: inherit; color: inherit; cursor: pointer; }
|
|
74
93
|
& .crisp-tabletoolbar-fcond-seg svg { flex-shrink: 0; }
|
|
75
|
-
& .crisp-tabletoolbar-fcond[data-complete] .crisp-tabletoolbar-fcond-seg--field,
|
|
76
|
-
& .crisp-tabletoolbar-fcond-
|
|
94
|
+
& .crisp-tabletoolbar-fcond[data-complete] .crisp-tabletoolbar-fcond-seg--field,
|
|
95
|
+
& .crisp-tabletoolbar-fcond[data-complete] .crisp-tabletoolbar-fcond-seg--val { background: var(--crisp-bg-surface); }
|
|
96
|
+
& .crisp-tabletoolbar-fcond-seg--field { border-radius: var(--crisp-radius-md) 0 0 var(--crisp-radius-md); font-weight: var(--crisp-weight-medium); max-width: 200px; }
|
|
77
97
|
& .crisp-tabletoolbar-fcond-seg--field svg { color: var(--crisp-fg-muted); }
|
|
98
|
+
/* #592: a nested pick's field segment ("Team › Twitter follower
|
|
99
|
+
count") — measured live: BOTH path segments the same colour (chip context only; the picker's own menu rows keep the parent muted, see
|
|
100
|
+
tabletoolbar.chrome.ts), each independently truncated. Attio's own layout gives the leaf segment priority (it stays fully readable longer, the parent truncates first) via a two-part min-content measurement this reproduces qualitatively with a flex-shrink differential rather than byte-for-byte (the exact px split Attio computes is content-length-dependent, not a fixed value) — not independently re-verified at other path-segment lengths. */
|
|
101
|
+
& .crisp-tabletoolbar-fcond-path { display: inline-flex; align-items: center; gap: 2px; min-width: 0; max-width: 178px; }
|
|
102
|
+
& .crisp-tabletoolbar-fcond-path-seg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 auto; }
|
|
103
|
+
& .crisp-tabletoolbar-fcond-path-seg:first-child { flex: 0 1 auto; }
|
|
104
|
+
& .crisp-tabletoolbar-fcond-path-sep { flex-shrink: 0; color: inherit; }
|
|
78
105
|
& .crisp-tabletoolbar-fcond-seg--op { background: var(--crisp-bg-surface); color: var(--crisp-fg-muted); }
|
|
79
106
|
& .crisp-tabletoolbar-fcond-seg--val { font-weight: var(--crisp-weight-medium); max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
|
|
80
107
|
& .crisp-tabletoolbar-fcond-seg--kebab { background: var(--crisp-bg-surface); justify-content: center; width: 28px; padding: 0; border-radius: 0 var(--crisp-radius-md) var(--crisp-radius-md) 0; color: var(--crisp-fg-muted); }
|
|
@@ -84,6 +111,8 @@
|
|
|
84
111
|
& .crisp-tabletoolbar-datepop-presets { display: flex; flex-wrap: wrap; gap: var(--crisp-space-1); margin-top: var(--crisp-space-2); padding: 0 var(--crisp-space-1); }
|
|
85
112
|
& .crisp-tabletoolbar-datepop-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; }
|
|
86
113
|
& .crisp-tabletoolbar-datepop-preset:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); }
|
|
114
|
+
& .crisp-tabletoolbar-tool--raised { border: none; background: var(--crisp-bg-surface-muted); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04); font-family: inherit; cursor: pointer; }
|
|
115
|
+
[dir="rtl"] & [data-rtl-flip] { transform: scaleX(-1); }
|
|
87
116
|
}
|
|
88
117
|
|
|
89
118
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -27,13 +27,20 @@ export type ContextMenuProps = {
|
|
|
27
27
|
* element, same as any other `asChild` in crisp (`core/primitive.tsx`).
|
|
28
28
|
*/
|
|
29
29
|
asChild?: boolean;
|
|
30
|
+
/** `"light"` (default) is this component's own original popover surface.
|
|
31
|
+
* `"dark"` is Attio's OWN cell-level context menu (`DataTable`'s #598) —
|
|
32
|
+
* measured live as a fixed, theme-INDEPENDENT dark chrome (background
|
|
33
|
+
* `#101112`, text `#eeeff1`), the same "dark pill" ink pair `Tooltip`
|
|
34
|
+
* already hardcodes for the same reason: this surface doesn't follow the
|
|
35
|
+
* app's light/dark theme, Attio always renders it dark. */
|
|
36
|
+
variant?: "light" | "dark";
|
|
30
37
|
};
|
|
31
38
|
/**
|
|
32
39
|
* A right-click context menu — the popover surface positioned at the cursor.
|
|
33
40
|
* Wrap the target; right-clicking it opens the menu (flipping at the viewport
|
|
34
41
|
* edges), closing on select, outside pointer-down, and Escape.
|
|
35
42
|
*/
|
|
36
|
-
export declare function ContextMenu({ children, items, menuLabel: menuLabelProp, className, asChild, }: ContextMenuProps): React.JSX.Element;
|
|
43
|
+
export declare function ContextMenu({ children, items, menuLabel: menuLabelProp, className, asChild, variant, }: ContextMenuProps): React.JSX.Element;
|
|
37
44
|
export declare namespace ContextMenu {
|
|
38
45
|
var displayName: string;
|
|
39
46
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type CalcOp } from "../columncalc";
|
|
2
3
|
type IconType = React.ComponentType<{
|
|
3
4
|
size?: number;
|
|
4
5
|
strokeWidth?: number;
|
|
@@ -7,6 +8,7 @@ export declare function isLabelTruncated(el: {
|
|
|
7
8
|
scrollWidth: number;
|
|
8
9
|
clientWidth: number;
|
|
9
10
|
}): boolean;
|
|
11
|
+
export declare function reorderColumns<T>(cols: DataTableColumn<T>[], order: string[] | undefined): DataTableColumn<T>[];
|
|
10
12
|
export type EntityValue = {
|
|
11
13
|
name: string;
|
|
12
14
|
avatar?: string;
|
|
@@ -140,6 +142,24 @@ export type DataTableColumn<T> = {
|
|
|
140
142
|
format?: (value: unknown, row: T) => string;
|
|
141
143
|
/** Footer summary for this column (shown when any column supplies one). */
|
|
142
144
|
summary?: (rows: T[]) => React.ReactNode;
|
|
145
|
+
/**
|
|
146
|
+
* Give this column an aggregation footer via `ColumnCalc`, matching
|
|
147
|
+
* Attio's own per-type set exactly (crisp/#602, checklist G-073;
|
|
148
|
+
* confirmed live against `app.attio.com`'s "Add calculation" menu on
|
|
149
|
+
* both a text and a numeric column): Count empty / Count filled /
|
|
150
|
+
* Percent empty / Percent filled on every column, plus Sum / Average /
|
|
151
|
+
* Min / Max on `"number"`/`"currency"` columns, plus an explicit "None"
|
|
152
|
+
* once one is active. RecordsTable's own OLDER, separate calc footer
|
|
153
|
+
* predates `ColumnCalc` and gives a flat, per-type-WRONG set (no
|
|
154
|
+
* Percent empty/filled at all, "Count all" instead of "Count empty" +
|
|
155
|
+
* "Count filled" as two ops) — that duplicate implementation is not
|
|
156
|
+
* touched here; this is DataTable's own footer only. Wins over
|
|
157
|
+
* `summary` when both are set on the same column. */
|
|
158
|
+
calc?: {
|
|
159
|
+
defaultOp?: CalcOp;
|
|
160
|
+
op?: CalcOp;
|
|
161
|
+
onOpChange?: (op: CalcOp) => void;
|
|
162
|
+
};
|
|
143
163
|
/** Opt this column out of the header menu's Hide/Move/Rename items. */
|
|
144
164
|
managed?: boolean;
|
|
145
165
|
/** Hidden from the grid but still listed in the column manager. */
|
|
@@ -151,7 +171,12 @@ export type DataTableColumn<T> = {
|
|
|
151
171
|
* icon set); this uses a Lucide `Lock`, the same substitution every
|
|
152
172
|
* other crisp icon makes. Purely a visual marker — it does NOT disable
|
|
153
173
|
* editing on its own; a column that shouldn't be editable simply
|
|
154
|
-
* doesn't set `editable: true`, the same as any other column.
|
|
174
|
+
* doesn't set `editable: true`, the same as any other column.
|
|
175
|
+
* Also used by the cell context menu (crisp/#598, #645): matching
|
|
176
|
+
* Attio's own "no copy handler at all" for a computed field (checklist
|
|
177
|
+
* G-100), a `readOnly` cell's Copy item is disabled and its keyboard/
|
|
178
|
+
* native-copy path writes nothing to the clipboard, and its Clear-value
|
|
179
|
+
* item is disabled (there is nothing editable to clear). */
|
|
155
180
|
readOnly?: boolean;
|
|
156
181
|
/** `type: "entity"` only (#501) — makes the cell's name its own click
|
|
157
182
|
* target, separate from the row's own `onRowClick`: the name renders as a
|
|
@@ -163,6 +188,30 @@ export type DataTableColumn<T> = {
|
|
|
163
188
|
* row's own record — that's what `onRowClick` is for. Ignored on any
|
|
164
189
|
* other `type`. */
|
|
165
190
|
onEntityClick?: (row: T) => void;
|
|
191
|
+
/** `type: "entity"` only (crisp/#601, checklist G-048) — a right-aligned
|
|
192
|
+
* "Open preview" icon that appears on row hover (or keyboard focus),
|
|
193
|
+
* alongside `onOpenComments` below. Matches Attio's own measured pair
|
|
194
|
+
* exactly: a 20px ghost button, `radius.sm`, muted at rest, darkening on
|
|
195
|
+
* its own hover. Omit to render neither icon (default). Ignored on any
|
|
196
|
+
* other `type`, same as `onEntityClick`. */
|
|
197
|
+
onOpenPreview?: (row: T) => void;
|
|
198
|
+
/** `type: "entity"` only (crisp/#601, checklist G-048) — the OTHER
|
|
199
|
+
* hover icon next to `onOpenPreview`. Measured live: its button carries
|
|
200
|
+
* `aria-controls="comment-drawer"`, not the "possibly drag-to-reorder"
|
|
201
|
+
* the issue's own first-pass guess landed on — it opens a comment
|
|
202
|
+
* drawer for the row. Once set, renders via `CommentCountBadge`
|
|
203
|
+
* (product/comments, crisp/#625) rather than a plain icon — a persistent
|
|
204
|
+
* dot once the row has ≥1 comment, replaced on hover by the count (see
|
|
205
|
+
* `commentCount`); `onOpenPreview` above rides along as that badge's own
|
|
206
|
+
* second icon instead of rendering separately. Setting `onOpenPreview`
|
|
207
|
+
* with NO `onOpenComments` keeps the old plain-icon-only rendering (a
|
|
208
|
+
* column with a preview affordance but no comments concept at all). */
|
|
209
|
+
onOpenComments?: (row: T) => void;
|
|
210
|
+
/** The row's own comment count, read by `CommentCountBadge` when
|
|
211
|
+
* `onOpenComments` is set. Omit to always pass `0` — the badge still
|
|
212
|
+
* renders (a plain icon, no dot, no digit) once `onOpenComments` is set;
|
|
213
|
+
* it just can't show a real count without this. */
|
|
214
|
+
commentCount?: (row: T) => number;
|
|
166
215
|
};
|
|
167
216
|
export type SortState = {
|
|
168
217
|
key: string;
|
|
@@ -227,8 +276,35 @@ export type DataTableProps<T extends {
|
|
|
227
276
|
viewSettingsLabel?: string;
|
|
228
277
|
/** That menu's own "Columns" section heading. */
|
|
229
278
|
columnsGroupLabel?: string;
|
|
279
|
+
/** Accessible name for the cell context menu (crisp/#598) and the hidden
|
|
280
|
+
* clipboard-proxy textarea its Copy/Cmd+C share (crisp/#645). */
|
|
281
|
+
cellMenuLabel?: string;
|
|
282
|
+
/** The cell context menu's four items, matching Attio's own exactly
|
|
283
|
+
* (checklist G-043 — "identical menu regardless of field type"). */
|
|
284
|
+
copyLabel?: string;
|
|
285
|
+
pasteLabel?: string;
|
|
286
|
+
viewEditHistoryLabel?: string;
|
|
287
|
+
/** "Clear value" commits an empty string via the existing `onEdit`, same
|
|
288
|
+
* as clearing a plain text editor by hand -- no separate callback. */
|
|
289
|
+
clearValueLabel?: string;
|
|
230
290
|
/** Called with the next column list after a move, rename or hide. */
|
|
231
291
|
onColumnsChange?: (columns: DataTableColumn<T>[]) => void;
|
|
292
|
+
/**
|
|
293
|
+
* Controlled column order — a plain array of `key`s (crisp/#731), lighter
|
|
294
|
+
* than `onColumnsChange`'s full column definitions (which can't round-trip
|
|
295
|
+
* through JSON: `render`/`accessor`/etc. are functions) and so the shape a
|
|
296
|
+
* saved view actually persists. Omit for an uncontrolled default seeded
|
|
297
|
+
* from `columns`' own order and updated internally by a header drag or the
|
|
298
|
+
* column menu's Move left/right. A key this doesn't mention (a column
|
|
299
|
+
* added since the order was last saved) renders after every key it DOES
|
|
300
|
+
* mention, in `columns`' own relative order — see `reorderColumns`. Column
|
|
301
|
+
* drag-to-reorder itself is always available (like resize); this prop only
|
|
302
|
+
* changes who owns the resulting order.
|
|
303
|
+
*/
|
|
304
|
+
columnOrder?: string[];
|
|
305
|
+
/** Called with the next `columnOrder` after a header drag or the column
|
|
306
|
+
* menu's Move left/right — whichever changed the order. */
|
|
307
|
+
onColumnOrderChange?: (order: string[]) => void;
|
|
232
308
|
/** Group rows under a heading row, the way a grouped view does. */
|
|
233
309
|
groupBy?: (row: T) => string;
|
|
234
310
|
/**
|
|
@@ -241,6 +317,11 @@ export type DataTableProps<T extends {
|
|
|
241
317
|
onRowsReorder?: (rows: T[]) => void;
|
|
242
318
|
/** aria-label on each row's drag grip (default "Reorder row"). */
|
|
243
319
|
reorderRowLabel?: string;
|
|
320
|
+
/** aria-label on the entity column's "Open preview" hover icon (crisp/#601;
|
|
321
|
+
* only rendered when a column sets `onOpenPreview`). Also passed through
|
|
322
|
+
* to `CommentCountBadge`'s own `previewLabel` when a column sets
|
|
323
|
+
* `onOpenComments` too (crisp/#601 supersession). */
|
|
324
|
+
openPreviewLabel?: string;
|
|
244
325
|
/**
|
|
245
326
|
* Render an error state in place of the rows. Uses the same measured
|
|
246
327
|
* `EmptyState variant="page"` surface as the zero-row state.
|
|
@@ -265,6 +346,13 @@ export type DataTableProps<T extends {
|
|
|
265
346
|
* outside `render`'s own output so a hover-only wrapper (a `Tooltip`, say)
|
|
266
347
|
* can't swallow it. */
|
|
267
348
|
onEdit?: (id: string, key: string, value: string) => Promise<void> | void;
|
|
349
|
+
/** The cell context menu's "View edit history" item (crisp/#598, checklist
|
|
350
|
+
* G-043 -- Attio's own item carries a "Pro" pill crisp has no billing
|
|
351
|
+
* concept to gate on, so the item itself always renders; see the
|
|
352
|
+
* component's own comment). Omitted: the item still renders (matching
|
|
353
|
+
* Attio, which shows it regardless of field type) but disabled, since
|
|
354
|
+
* there is nothing for it to open. */
|
|
355
|
+
onViewEditHistory?: (id: string, key: string) => void;
|
|
268
356
|
/** Sticky the first column(s) with a horizontal scroll shadow (default true). */
|
|
269
357
|
stickyFirst?: boolean;
|
|
270
358
|
/** Sticky the LAST column with a horizontal scroll shadow, mirroring
|
|
@@ -337,7 +425,7 @@ export type DataTableProps<T extends {
|
|
|
337
425
|
};
|
|
338
426
|
export declare function DataTable<T extends {
|
|
339
427
|
id: string;
|
|
340
|
-
}>({ columns: columnsProp, data, selectable, selectedIds, onSelectionChange, selectAllLabel: selectAllLabelProp, selectRowLabel, selectionAnnouncement, columnMenu, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, onEdit, stickyFirst, stickyLast, scrollProps, locale: localeProp, avatarTone, surface, interactive, onRowClick, onAddRow, addRowLabel: addRowLabelProp, empty: emptyProp, showCount, countLabel, toolbar, height, className, reorderRowLabel: reorderRowLabelProp, sortAscendingLabel: sortAscendingLabelProp, sortDescendingLabel: sortDescendingLabelProp, moveColumnLeftLabel: moveColumnLeftLabelProp, moveColumnRightLabel: moveColumnRightLabelProp, editColumnLabel: editColumnLabelProp, hideColumnLabel: hideColumnLabelProp, renameColumnLabel: renameColumnLabelProp, viewSettingsLabel: viewSettingsLabelProp, columnsGroupLabel: columnsGroupLabelProp, ...rest }: DataTableProps<T>): React.JSX.Element;
|
|
428
|
+
}>({ columns: columnsProp, data, selectable, selectedIds, onSelectionChange, selectAllLabel: selectAllLabelProp, selectRowLabel, selectionAnnouncement, columnMenu, onColumnsChange, columnOrder, onColumnOrderChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, onEdit, onViewEditHistory, stickyFirst, stickyLast, scrollProps, locale: localeProp, avatarTone, surface, interactive, onRowClick, onAddRow, addRowLabel: addRowLabelProp, empty: emptyProp, showCount, countLabel, toolbar, height, className, reorderRowLabel: reorderRowLabelProp, openPreviewLabel: openPreviewLabelProp, sortAscendingLabel: sortAscendingLabelProp, sortDescendingLabel: sortDescendingLabelProp, moveColumnLeftLabel: moveColumnLeftLabelProp, moveColumnRightLabel: moveColumnRightLabelProp, editColumnLabel: editColumnLabelProp, hideColumnLabel: hideColumnLabelProp, renameColumnLabel: renameColumnLabelProp, viewSettingsLabel: viewSettingsLabelProp, columnsGroupLabel: columnsGroupLabelProp, cellMenuLabel: cellMenuLabelProp, copyLabel: copyLabelProp, pasteLabel: pasteLabelProp, viewEditHistoryLabel: viewEditHistoryLabelProp, clearValueLabel: clearValueLabelProp, ...rest }: DataTableProps<T>): React.JSX.Element;
|
|
341
429
|
export declare namespace DataTable {
|
|
342
430
|
var displayName: string;
|
|
343
431
|
}
|
|
@@ -48,8 +48,39 @@ export type TableToolbarColumn = {
|
|
|
48
48
|
* `is`/`is not`/`before`/`after`/`empty`/`not empty` with a calendar +
|
|
49
49
|
* Today/Tomorrow/Next week quick-picks — both sets, and the number
|
|
50
50
|
* spinner, measured live against Attio's own column-typed filter menus.
|
|
51
|
+
* `"select"` (#715) swaps in `is`/`is not`/`empty`/`not empty` — a
|
|
52
|
+
* closed-vocabulary column's text-search operators (`contains`/`starts
|
|
53
|
+
* with`/…) mean nothing against a fixed value set. Pair it with `values`
|
|
54
|
+
* to also offer `"is any of"`, the same as every other type.
|
|
51
55
|
*/
|
|
52
|
-
type?: "text" | "number" | "date";
|
|
56
|
+
type?: "text" | "number" | "date" | "select";
|
|
57
|
+
/**
|
|
58
|
+
* This column's own related object's attributes, reachable as a
|
|
59
|
+
* "Parent › Child" path in the Filter field picker (#592) — a
|
|
60
|
+
* relationship field (Attio's own "Team 26", a company's linked people,
|
|
61
|
+
* e.g.) expands into a nested picker over these instead of only
|
|
62
|
+
* offering the relationship field itself. Recurses: a nested column can
|
|
63
|
+
* carry its own `nestedColumns` too (Team → Company → …, confirmed
|
|
64
|
+
* reachable live) with no depth limit built in here. The relationship
|
|
65
|
+
* field itself stays independently selectable (its own operators, e.g.
|
|
66
|
+
* `contains`/`does not contain`/`empty`/`not empty` for a person
|
|
67
|
+
* relationship, measured live) — drilling in doesn't remove that option,
|
|
68
|
+
* it adds the nested one alongside it, matching Attio's own picker
|
|
69
|
+
* exactly (its nested screen lists the relationship field itself first,
|
|
70
|
+
* checked when it's the chip's current field, then its children).
|
|
71
|
+
*/
|
|
72
|
+
nestedColumns?: TableToolbarColumn[];
|
|
73
|
+
/**
|
|
74
|
+
* The related object's own singular noun, used once a consumer drills
|
|
75
|
+
* into this column: the nested picker's placeholder reads `Search
|
|
76
|
+
* ${nestedObjectLabel} attributes…` — measured live, e.g. "person" for a
|
|
77
|
+
* Team/People relationship, "company" for a Company relationship. Only
|
|
78
|
+
* meaningful alongside `nestedColumns`. Falls back to this column's own
|
|
79
|
+
* `label`, lowercased, when omitted — a plain fallback, since Attio's
|
|
80
|
+
* own noun is the *related object's* name, not usually the field's own
|
|
81
|
+
* label lowercased ("Team" the field vs. "person" the related object).
|
|
82
|
+
*/
|
|
83
|
+
nestedObjectLabel?: string;
|
|
53
84
|
};
|
|
54
85
|
export type TableToolbarProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"> & {
|
|
55
86
|
/**
|
|
@@ -192,6 +223,45 @@ export type TableToolbarProps = Omit<React.ComponentPropsWithoutRef<"div">, "chi
|
|
|
192
223
|
addAttributeToViewLabel?: string;
|
|
193
224
|
/** Placeholder in the add-attribute search box (default "Search attributes…"). */
|
|
194
225
|
searchAttributesPlaceholder?: string;
|
|
226
|
+
/**
|
|
227
|
+
* Text on the Import/Export trigger (default "Import / Export"). The
|
|
228
|
+
* trigger only renders when at least one of `onImportCsv`/`onExportCsv`/
|
|
229
|
+
* `onExportExcel`/`importExportHelpHref` is given — an unwired menu has
|
|
230
|
+
* nothing to do, the same "still renders empty" contract other triggers
|
|
231
|
+
* here make doesn't fit a menu that would just be blank.
|
|
232
|
+
*/
|
|
233
|
+
importExportLabel?: string;
|
|
234
|
+
/** The menu's "Import CSV" item — omit to leave it out. */
|
|
235
|
+
onImportCsv?: () => void;
|
|
236
|
+
/** The menu's "Export view as CSV" item — omit to leave it out. */
|
|
237
|
+
onExportCsv?: () => void;
|
|
238
|
+
/** The menu's "Export view as Excel" item — omit to leave it out. */
|
|
239
|
+
onExportExcel?: () => void;
|
|
240
|
+
/** Shows a "Learn about imports and exports" link in the menu when set —
|
|
241
|
+
* same pattern as Sort's own `helpHref`. */
|
|
242
|
+
importExportHelpHref?: string;
|
|
243
|
+
/** Label on the "Import CSV" item (default "Import CSV"). */
|
|
244
|
+
importCsvLabel?: string;
|
|
245
|
+
/** Label on the "Export view as CSV" item (default "Export view as CSV"). */
|
|
246
|
+
exportCsvLabel?: string;
|
|
247
|
+
/** Label on the "Export view as Excel" item (default "Export view as Excel"). */
|
|
248
|
+
exportExcelLabel?: string;
|
|
249
|
+
/** Text of the Import/Export menu's help link (default "Learn about
|
|
250
|
+
* imports and exports"). */
|
|
251
|
+
learnImportExportLabel?: string;
|
|
252
|
+
/** aria-label on the Filter field picker's back control, shown once
|
|
253
|
+
* drilled into a `nestedColumns` column (default "Back"). */
|
|
254
|
+
backLabel?: string;
|
|
255
|
+
/**
|
|
256
|
+
* Placeholder in the field picker's own search box once drilled into a
|
|
257
|
+
* `nestedColumns` column — receives that column's `nestedObjectLabel`
|
|
258
|
+
* (or its `label`, lowercased). Defaults to `Search ${noun} attributes…`,
|
|
259
|
+
* matching Attio's own measured wording ("Search person attributes…",
|
|
260
|
+
* drilled into a Team/People relationship) — a formatter, like
|
|
261
|
+
* `sortTriggerLabel` above, since the noun sits mid-sentence and a fixed
|
|
262
|
+
* template doesn't survive every language's word order.
|
|
263
|
+
*/
|
|
264
|
+
nestedFieldPlaceholder?: (noun: string) => string;
|
|
195
265
|
};
|
|
196
266
|
/**
|
|
197
267
|
* Applies a toolbar's filter conditions to any row array. Reads the raw value
|
|
@@ -218,7 +288,7 @@ export declare function applySorts<T>(rows: T[], sorts: ToolbarSort[], get?: (ro
|
|
|
218
288
|
* this (Sort: Due date/Assignee/Creation date; Filter: Assignee/Record/
|
|
219
289
|
* Created by), which one shared list can't reproduce.
|
|
220
290
|
*/
|
|
221
|
-
export declare function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: filterColumnsProp, sorts: sortsProp, defaultSorts, onSortsChange, filters: filtersProp, defaultFilters, onFiltersChange, count, children, helpHref, className, sortLabel: sortLabelProp, filterLabel: filterLabelProp, reorderSortLabel: reorderSortLabelProp, noSortsLabel: noSortsLabelProp, addSortLabel: addSortLabelProp, learnSortingLabel: learnSortingLabelProp, selectConditionLabel: selectConditionLabelProp, sortFieldLabel: sortFieldLabelProp, sortDirectionLabel: sortDirectionLabelProp, removeSortLabel: removeSortLabelProp, filterFieldLabel: filterFieldLabelProp, filterFieldPlaceholder: filterFieldPlaceholderProp, filterValuePlaceholder: filterValuePlaceholderProp, filterOptionsLabel: filterOptionsLabelProp, deleteFilterLabel: deleteFilterLabelProp, ascendingLabel: ascendingLabelProp, descendingLabel: descendingLabelProp, sortTriggerLabel, filterTriggerLabel, inline, showSort, showViewSettings, viewColumns: viewColumnsProp, shownKeys: shownKeysProp, defaultShownKeys, onShownKeysChange, viewSettingsLabel: viewSettingsLabelProp, reorderAttributeLabel: reorderAttributeLabelProp, hideAttributeLabel, addAttributeToViewLabel: addAttributeToViewLabelProp, searchAttributesPlaceholder: searchAttributesPlaceholderProp, ...rest }: TableToolbarProps): React.JSX.Element;
|
|
291
|
+
export declare function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: filterColumnsProp, sorts: sortsProp, defaultSorts, onSortsChange, filters: filtersProp, defaultFilters, onFiltersChange, count, children, helpHref, className, sortLabel: sortLabelProp, filterLabel: filterLabelProp, reorderSortLabel: reorderSortLabelProp, noSortsLabel: noSortsLabelProp, addSortLabel: addSortLabelProp, learnSortingLabel: learnSortingLabelProp, selectConditionLabel: selectConditionLabelProp, sortFieldLabel: sortFieldLabelProp, sortDirectionLabel: sortDirectionLabelProp, removeSortLabel: removeSortLabelProp, filterFieldLabel: filterFieldLabelProp, filterFieldPlaceholder: filterFieldPlaceholderProp, filterValuePlaceholder: filterValuePlaceholderProp, filterOptionsLabel: filterOptionsLabelProp, deleteFilterLabel: deleteFilterLabelProp, ascendingLabel: ascendingLabelProp, descendingLabel: descendingLabelProp, sortTriggerLabel, filterTriggerLabel, inline, showSort, showViewSettings, viewColumns: viewColumnsProp, shownKeys: shownKeysProp, defaultShownKeys, onShownKeysChange, viewSettingsLabel: viewSettingsLabelProp, reorderAttributeLabel: reorderAttributeLabelProp, hideAttributeLabel, addAttributeToViewLabel: addAttributeToViewLabelProp, searchAttributesPlaceholder: searchAttributesPlaceholderProp, importExportLabel: importExportLabelProp, onImportCsv, onExportCsv, onExportExcel, importExportHelpHref, importCsvLabel: importCsvLabelProp, exportCsvLabel: exportCsvLabelProp, exportExcelLabel: exportExcelLabelProp, learnImportExportLabel: learnImportExportLabelProp, backLabel: backLabelProp, nestedFieldPlaceholder, ...rest }: TableToolbarProps): React.JSX.Element;
|
|
222
292
|
export type ToolbarToolProps = React.ComponentPropsWithoutRef<"button"> & {
|
|
223
293
|
/** Drawn the way Sort/Filter are once a condition is set (#399). */
|
|
224
294
|
active?: boolean;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
/** crisp/#718 — Attio's own two independent density toggles: "collapse"
|
|
3
|
+
* (columns narrow to a 52px vertical rail; cards shrink to a 40px row) or
|
|
4
|
+
* "expand" (the normal width/height), measured live on the Deals
|
|
5
|
+
* pipeline. */
|
|
6
|
+
export type BoardDensity = "expand" | "collapse";
|
|
2
7
|
export type BoardColumn = {
|
|
3
8
|
id: string;
|
|
4
9
|
title: string;
|
|
@@ -24,10 +29,51 @@ export type BoardProps<T extends BoardCard> = Omit<React.ComponentPropsWithoutRe
|
|
|
24
29
|
cards: T[];
|
|
25
30
|
/** Called with the next cards after a drag moves one between columns. */
|
|
26
31
|
onCardsChange?: (cards: T[]) => void;
|
|
27
|
-
|
|
32
|
+
/**
|
|
33
|
+
* The second argument is the board's CURRENT card density (crisp/#718) —
|
|
34
|
+
* `renderCard` decides what a collapsed (40px row) card actually shows,
|
|
35
|
+
* since Board only knows the card is a `T`, never its display shape.
|
|
36
|
+
* Ignoring the argument (a plain `(card) => ...`) keeps every existing
|
|
37
|
+
* call site valid; `cardDensity` then just resolves to `"expand"` always,
|
|
38
|
+
* exactly as before this prop existed.
|
|
39
|
+
*/
|
|
40
|
+
renderCard: (card: T, cardDensity: BoardDensity) => React.ReactNode;
|
|
28
41
|
/** When set, each column shows a "+ {newCardLabel}" button and its header +. */
|
|
29
42
|
onNewCard?: (columnId: string) => void;
|
|
30
43
|
newCardLabel?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Shows the density toolbar above the board — Attio's own two
|
|
46
|
+
* independent "Collapse/Expand columns" and "Collapse/Expand cards"
|
|
47
|
+
* segmented toggles (crisp/#718, measured live). Default `false`: an
|
|
48
|
+
* existing `Board` renders no toolbar and no extra chrome, exactly as
|
|
49
|
+
* before this prop existed.
|
|
50
|
+
*/
|
|
51
|
+
density?: boolean;
|
|
52
|
+
/** Controlled column density (omit for uncontrolled, seeded "expand"). */
|
|
53
|
+
columnDensity?: BoardDensity;
|
|
54
|
+
onColumnDensityChange?: (density: BoardDensity) => void;
|
|
55
|
+
/** Controlled card density (omit for uncontrolled, seeded "expand") —
|
|
56
|
+
* also the value `renderCard`'s second argument resolves to. */
|
|
57
|
+
cardDensity?: BoardDensity;
|
|
58
|
+
onCardDensityChange?: (density: BoardDensity) => void;
|
|
59
|
+
collapseColumnsLabel?: string;
|
|
60
|
+
expandColumnsLabel?: string;
|
|
61
|
+
collapseCardsLabel?: string;
|
|
62
|
+
expandCardsLabel?: string;
|
|
63
|
+
/** aria-label for the column-density toggle's own `role="radiogroup"`
|
|
64
|
+
* wrapper (Attio's own markup uses a plain `role="group"` with no name —
|
|
65
|
+
* crisp names both groups, the more correct ARIA shape for a set of
|
|
66
|
+
* mutually-exclusive `role="radio"` buttons). */
|
|
67
|
+
columnDensityGroupLabel?: string;
|
|
68
|
+
cardDensityGroupLabel?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Renders a trailing 52×52px dashed "+" slot after the last column —
|
|
71
|
+
* Attio's own "Add stage" (crisp/#718, measured live). Omit to skip it
|
|
72
|
+
* entirely, matching every other opt-in affordance here (`onNewCard`,
|
|
73
|
+
* `calc`).
|
|
74
|
+
*/
|
|
75
|
+
onAddStage?: () => void;
|
|
76
|
+
addStageLabel?: string;
|
|
31
77
|
/**
|
|
32
78
|
* Accessible name for a card. Also used in the move announcement. Without it
|
|
33
79
|
* a card is announced by whatever `renderCard` puts in it, which is usually
|
|
@@ -54,7 +100,7 @@ export type BoardProps<T extends BoardCard> = Omit<React.ComponentPropsWithoutRe
|
|
|
54
100
|
* it via `onCardsChange` (the parent owns the cards, so the move is a
|
|
55
101
|
* controlled state update). Measured from a deals pipeline.
|
|
56
102
|
*/
|
|
57
|
-
export declare function Board<T extends BoardCard>({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLabel: newCardLabelProp, getCardLabel, announceMove: announceMoveProp, calc, className, ...rest }: BoardProps<T>): React.JSX.Element;
|
|
103
|
+
export declare function Board<T extends BoardCard>({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLabel: newCardLabelProp, getCardLabel, announceMove: announceMoveProp, calc, density, columnDensity: columnDensityProp, onColumnDensityChange, cardDensity: cardDensityProp, onCardDensityChange, collapseColumnsLabel: collapseColumnsLabelProp, expandColumnsLabel: expandColumnsLabelProp, collapseCardsLabel: collapseCardsLabelProp, expandCardsLabel: expandCardsLabelProp, columnDensityGroupLabel: columnDensityGroupLabelProp, cardDensityGroupLabel: cardDensityGroupLabelProp, onAddStage, addStageLabel: addStageLabelProp, className, ...rest }: BoardProps<T>): React.JSX.Element;
|
|
58
104
|
export declare namespace Board {
|
|
59
105
|
var displayName: string;
|
|
60
106
|
}
|
|
@@ -120,7 +120,12 @@ export type CommentsPanelProps = Omit<React.ComponentPropsWithoutRef<"div">, "ch
|
|
|
120
120
|
emojiOptions?: string[];
|
|
121
121
|
mentionTrigger?: string;
|
|
122
122
|
renderMentionPicker?: (state: CommentMentionTriggerState) => React.ReactNode;
|
|
123
|
-
|
|
123
|
+
/** Omit for a consumer with no separate open/close state of its own —
|
|
124
|
+
* embedded in a tab pane rather than a true slide-over/drawer, e.g.
|
|
125
|
+
* (crisp#738, the same reasoning #721 already applied to
|
|
126
|
+
* `onReact`/`onDelete`) — the header's close "✕" drops out rather than
|
|
127
|
+
* sitting there as a button that visibly does nothing. */
|
|
128
|
+
onClose?: () => void;
|
|
124
129
|
closeLabel?: string;
|
|
125
130
|
backLabel?: string;
|
|
126
131
|
title?: string;
|
|
@@ -6,6 +6,27 @@ export type SavedView = {
|
|
|
6
6
|
icon?: React.ReactNode;
|
|
7
7
|
/** Renders a small shared-view indicator next to the name. */
|
|
8
8
|
shared?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Text matched against the switcher's own search box (#618) when `name`
|
|
11
|
+
* isn't a plain string — same fallback `Select`'s own `keywords` already
|
|
12
|
+
* gives a non-string `label`. Falls back to `id` when `name` is also
|
|
13
|
+
* non-string and this is omitted, the same way `Select`'s own
|
|
14
|
+
* `optionText` falls back to `value` — a view with a rich, non-string
|
|
15
|
+
* name and no `keywords` still matches SOME query (its own id) rather
|
|
16
|
+
* than becoming permanently unfindable by search.
|
|
17
|
+
*/
|
|
18
|
+
keywords?: string;
|
|
19
|
+
/**
|
|
20
|
+
* "Created by …" — the first line of the kebab menu's own footer row
|
|
21
|
+
* (#618, measured live: "Created by Attio system" / "26th Aug 2026
|
|
22
|
+
* 12:20 PM", two stacked lines). Renders only the line(s) actually
|
|
23
|
+
* given — omit both for a view with no author/date metadata and the
|
|
24
|
+
* footer (and its divider) don't render at all.
|
|
25
|
+
*/
|
|
26
|
+
createdBy?: React.ReactNode;
|
|
27
|
+
/** The footer's second line — a pre-formatted date/time, since crisp
|
|
28
|
+
* doesn't own locale formatting. See `createdBy`. */
|
|
29
|
+
createdAt?: React.ReactNode;
|
|
9
30
|
};
|
|
10
31
|
export type SavedViewsProps = Omit<React.ComponentPropsWithoutRef<"div">, "children" | "onSelect"> & {
|
|
11
32
|
/** The trigger's label when no view is active (Attio's "All Companies"). */
|
|
@@ -32,6 +53,18 @@ export type SavedViewsProps = Omit<React.ComponentPropsWithoutRef<"div">, "child
|
|
|
32
53
|
viewOptionsLabel?: string;
|
|
33
54
|
/** aria-label for the panel itself (defaults to the resolved trigger label). */
|
|
34
55
|
"aria-label"?: string;
|
|
56
|
+
/** Placeholder on the panel's own search box (default "Search views..." —
|
|
57
|
+
* Attio's own text, measured live: 3 literal dots, not an ellipsis
|
|
58
|
+
* glyph). */
|
|
59
|
+
searchPlaceholder?: string;
|
|
60
|
+
/** aria-label on the search box (default "Filter views" — Attio's own
|
|
61
|
+
* measured aria-label, distinct from its placeholder text). */
|
|
62
|
+
searchLabel?: string;
|
|
63
|
+
/** Shown in place of the view list when a search matches nothing (default
|
|
64
|
+
* "No results" — the same text and contract `Select`'s own `searchable`
|
|
65
|
+
* empty state already uses). The "Create new view" row still renders
|
|
66
|
+
* below it either way. */
|
|
67
|
+
emptyLabel?: string;
|
|
35
68
|
className?: string;
|
|
36
69
|
};
|
|
37
70
|
/**
|
|
@@ -40,16 +73,20 @@ export type SavedViewsProps = Omit<React.ComponentPropsWithoutRef<"div">, "child
|
|
|
40
73
|
* row (leading coloured icon, name, a hover-revealed kebab of
|
|
41
74
|
* rename/duplicate/delete), plus a trailing "Create new view" row. The
|
|
42
75
|
* active view is marked `aria-selected`/`aria-current="page"` and mirrored
|
|
43
|
-
* onto the trigger's own icon/label.
|
|
76
|
+
* onto the trigger's own icon/label. The panel opens on a "Search views..."
|
|
77
|
+
* box (#618, P-007) — real DOM focus moves there (`requestAnimationFrame`,
|
|
78
|
+
* same race `Select`'s own `searchable` variant already guards against),
|
|
79
|
+
* not virtual focus on the trigger.
|
|
44
80
|
*
|
|
45
|
-
* Keyboard: while the
|
|
46
|
-
* virtual highlight (`aria-activedescendant
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
81
|
+
* Keyboard: while the panel is open, focus lives on the search input — ↑/↓
|
|
82
|
+
* move a virtual highlight (`aria-activedescendant`) over the (possibly
|
|
83
|
+
* filtered) view list, Enter chooses the highlighted row, Escape closes,
|
|
84
|
+
* deferring to a still-open kebab submenu first (`hasOpenFloatingLayer`),
|
|
85
|
+
* so Escape closes one layer at a time — the same split `Select`'s own
|
|
86
|
+
* `searchable` variant already uses between its trigger and its own search
|
|
87
|
+
* input.
|
|
51
88
|
*/
|
|
52
|
-
export declare function SavedViews({ label, icon, views, activeId, onSelect, onCreate, onRename, onDuplicate, onDelete, onToggleFavorite, createLabel: createLabelProp, renameLabel: renameLabelProp, duplicateLabel: duplicateLabelProp, deleteLabel: deleteLabelProp, favoriteLabel: favoriteLabelProp, viewOptionsLabel: viewOptionsLabelProp, className, "aria-label": ariaLabel, ...rest }: SavedViewsProps): React.JSX.Element;
|
|
89
|
+
export declare function SavedViews({ label, icon, views, activeId, onSelect, onCreate, onRename, onDuplicate, onDelete, onToggleFavorite, createLabel: createLabelProp, renameLabel: renameLabelProp, duplicateLabel: duplicateLabelProp, deleteLabel: deleteLabelProp, favoriteLabel: favoriteLabelProp, viewOptionsLabel: viewOptionsLabelProp, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, emptyLabel: emptyLabelProp, className, "aria-label": ariaLabel, ...rest }: SavedViewsProps): React.JSX.Element;
|
|
53
90
|
export declare namespace SavedViews {
|
|
54
91
|
var displayName: string;
|
|
55
92
|
}
|