@crisp-ui-kit/crisp 0.54.8 → 0.54.10
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 +593 -51
- package/dist/cjs/components/datatable/datatable.recipe.js +67 -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 +218 -39
- package/dist/cjs/components/tabletoolbar/tabletoolbar.recipe.js +48 -1
- package/dist/cjs/components/text/text.recipe.js +17 -7
- 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 +106 -77
- package/dist/datatable.layered.css +106 -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 +593 -52
- package/dist/esm/components/datatable/datatable.recipe.js +68 -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 +219 -40
- package/dist/esm/components/tabletoolbar/tabletoolbar.recipe.js +50 -3
- package/dist/esm/components/text/text.recipe.js +17 -7
- 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 +282 -125
- package/dist/styles.layered.css +282 -125
- package/dist/tabletoolbar.css +45 -4
- package/dist/tabletoolbar.layered.css +45 -4
- package/dist/text.css +1 -1
- package/dist/text.layered.css +1 -1
- package/dist/types/components/contextmenu/contextmenu.d.ts +8 -1
- package/dist/types/components/datatable/datatable.d.ts +98 -2
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +72 -2
- package/dist/types/components/text/text.recipe.d.ts +1 -1
- 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,21 +86,44 @@
|
|
|
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); }
|
|
80
107
|
& .crisp-tabletoolbar-fcond-seg--kebab:hover { color: var(--crisp-fg-primary); }
|
|
108
|
+
/* #754: the sort row's own field trigger, replacing a plain Select
|
|
109
|
+
with the same nested-drill-down popover Filter's field picker already has — reuses Select's own already-measured trigger chrome
|
|
110
|
+
verbatim (its class is scoped under Select's own root class, so it can't be reused as a bare class name outside an actual Select tree;
|
|
111
|
+
these values are copied, not re-measured). */
|
|
112
|
+
& .crisp-tabletoolbar-sort-field-picker { position: relative; display: inline-flex; flex: 1; min-width: 0; }
|
|
113
|
+
& .crisp-tabletoolbar-sort-field-trigger { box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-menuRow); width: 100%; min-width: 0; margin: 0; padding: 0 var(--crisp-space-1-5) 0 var(--crisp-space-2); border: none; 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); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); cursor: pointer; transition: background-color .12s ease, box-shadow .12s ease; }
|
|
114
|
+
& .crisp-tabletoolbar-sort-field-trigger:hover { background: var(--crisp-bg-raised); }
|
|
115
|
+
& .crisp-tabletoolbar-sort-field-trigger[aria-expanded="true"],
|
|
116
|
+
& .crisp-tabletoolbar-sort-field-trigger:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); background: var(--crisp-bg-surface); }
|
|
117
|
+
& .crisp-tabletoolbar-sort-field-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: start; }
|
|
118
|
+
& .crisp-tabletoolbar-sort-field-picker .crisp-tabletoolbar-menu { min-width: 200px; }
|
|
81
119
|
& .crisp-tabletoolbar-menu--val { min-width: 134px; }
|
|
82
120
|
& .crisp-tabletoolbar-datepop { width: 300px; }
|
|
83
121
|
& .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
122
|
& .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
123
|
& .crisp-tabletoolbar-datepop-preset:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); }
|
|
124
|
+
|
|
125
|
+
& .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; }
|
|
126
|
+
[dir="rtl"] & [data-rtl-flip] { transform: scaleX(-1); }
|
|
86
127
|
}
|
|
87
128
|
|
|
88
129
|
@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,21 +87,44 @@
|
|
|
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); }
|
|
81
108
|
& .crisp-tabletoolbar-fcond-seg--kebab:hover { color: var(--crisp-fg-primary); }
|
|
109
|
+
/* #754: the sort row's own field trigger, replacing a plain Select
|
|
110
|
+
with the same nested-drill-down popover Filter's field picker already has — reuses Select's own already-measured trigger chrome
|
|
111
|
+
verbatim (its class is scoped under Select's own root class, so it can't be reused as a bare class name outside an actual Select tree;
|
|
112
|
+
these values are copied, not re-measured). */
|
|
113
|
+
& .crisp-tabletoolbar-sort-field-picker { position: relative; display: inline-flex; flex: 1; min-width: 0; }
|
|
114
|
+
& .crisp-tabletoolbar-sort-field-trigger { box-sizing: border-box; display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); height: var(--crisp-size-menuRow); width: 100%; min-width: 0; margin: 0; padding: 0 var(--crisp-space-1-5) 0 var(--crisp-space-2); border: none; 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); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); cursor: pointer; transition: background-color .12s ease, box-shadow .12s ease; }
|
|
115
|
+
& .crisp-tabletoolbar-sort-field-trigger:hover { background: var(--crisp-bg-raised); }
|
|
116
|
+
& .crisp-tabletoolbar-sort-field-trigger[aria-expanded="true"],
|
|
117
|
+
& .crisp-tabletoolbar-sort-field-trigger:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); background: var(--crisp-bg-surface); }
|
|
118
|
+
& .crisp-tabletoolbar-sort-field-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: start; }
|
|
119
|
+
& .crisp-tabletoolbar-sort-field-picker .crisp-tabletoolbar-menu { min-width: 200px; }
|
|
82
120
|
& .crisp-tabletoolbar-menu--val { min-width: 134px; }
|
|
83
121
|
& .crisp-tabletoolbar-datepop { width: 300px; }
|
|
84
122
|
& .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
123
|
& .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
124
|
& .crisp-tabletoolbar-datepop-preset:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); }
|
|
125
|
+
|
|
126
|
+
& .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; }
|
|
127
|
+
[dir="rtl"] & [data-rtl-flip] { transform: scaleX(-1); }
|
|
87
128
|
}
|
|
88
129
|
|
|
89
130
|
@media (prefers-reduced-motion: reduce) {
|
package/dist/text.css
CHANGED
package/dist/text.layered.css
CHANGED
|
@@ -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,8 +171,21 @@ 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;
|
|
181
|
+
/** Marks the column's values as AI-enriched (crisp/#758) — every cell
|
|
182
|
+
* gets a full-bleed purple wash, composited OVER whatever row-state
|
|
183
|
+
* background the cell already has (hover, selected), which is why it's
|
|
184
|
+
* an overlay rather than a plain `background`. Ported from
|
|
185
|
+
* `RecordsTable`'s own already-measured value (`#9b69ff` at 4%, same as
|
|
186
|
+
* `bgPurple`) — no new measurement needed, `RecordsTable`'s own
|
|
187
|
+
* `Column.enriched` predates this. */
|
|
188
|
+
enriched?: boolean;
|
|
156
189
|
/** `type: "entity"` only (#501) — makes the cell's name its own click
|
|
157
190
|
* target, separate from the row's own `onRowClick`: the name renders as a
|
|
158
191
|
* `stopPropagation`-guarded button instead of a plain span, the same
|
|
@@ -163,6 +196,30 @@ export type DataTableColumn<T> = {
|
|
|
163
196
|
* row's own record — that's what `onRowClick` is for. Ignored on any
|
|
164
197
|
* other `type`. */
|
|
165
198
|
onEntityClick?: (row: T) => void;
|
|
199
|
+
/** `type: "entity"` only (crisp/#601, checklist G-048) — a right-aligned
|
|
200
|
+
* "Open preview" icon that appears on row hover (or keyboard focus),
|
|
201
|
+
* alongside `onOpenComments` below. Matches Attio's own measured pair
|
|
202
|
+
* exactly: a 20px ghost button, `radius.sm`, muted at rest, darkening on
|
|
203
|
+
* its own hover. Omit to render neither icon (default). Ignored on any
|
|
204
|
+
* other `type`, same as `onEntityClick`. */
|
|
205
|
+
onOpenPreview?: (row: T) => void;
|
|
206
|
+
/** `type: "entity"` only (crisp/#601, checklist G-048) — the OTHER
|
|
207
|
+
* hover icon next to `onOpenPreview`. Measured live: its button carries
|
|
208
|
+
* `aria-controls="comment-drawer"`, not the "possibly drag-to-reorder"
|
|
209
|
+
* the issue's own first-pass guess landed on — it opens a comment
|
|
210
|
+
* drawer for the row. Once set, renders via `CommentCountBadge`
|
|
211
|
+
* (product/comments, crisp/#625) rather than a plain icon — a persistent
|
|
212
|
+
* dot once the row has ≥1 comment, replaced on hover by the count (see
|
|
213
|
+
* `commentCount`); `onOpenPreview` above rides along as that badge's own
|
|
214
|
+
* second icon instead of rendering separately. Setting `onOpenPreview`
|
|
215
|
+
* with NO `onOpenComments` keeps the old plain-icon-only rendering (a
|
|
216
|
+
* column with a preview affordance but no comments concept at all). */
|
|
217
|
+
onOpenComments?: (row: T) => void;
|
|
218
|
+
/** The row's own comment count, read by `CommentCountBadge` when
|
|
219
|
+
* `onOpenComments` is set. Omit to always pass `0` — the badge still
|
|
220
|
+
* renders (a plain icon, no dot, no digit) once `onOpenComments` is set;
|
|
221
|
+
* it just can't show a real count without this. */
|
|
222
|
+
commentCount?: (row: T) => number;
|
|
166
223
|
};
|
|
167
224
|
export type SortState = {
|
|
168
225
|
key: string;
|
|
@@ -227,8 +284,35 @@ export type DataTableProps<T extends {
|
|
|
227
284
|
viewSettingsLabel?: string;
|
|
228
285
|
/** That menu's own "Columns" section heading. */
|
|
229
286
|
columnsGroupLabel?: string;
|
|
287
|
+
/** Accessible name for the cell context menu (crisp/#598) and the hidden
|
|
288
|
+
* clipboard-proxy textarea its Copy/Cmd+C share (crisp/#645). */
|
|
289
|
+
cellMenuLabel?: string;
|
|
290
|
+
/** The cell context menu's four items, matching Attio's own exactly
|
|
291
|
+
* (checklist G-043 — "identical menu regardless of field type"). */
|
|
292
|
+
copyLabel?: string;
|
|
293
|
+
pasteLabel?: string;
|
|
294
|
+
viewEditHistoryLabel?: string;
|
|
295
|
+
/** "Clear value" commits an empty string via the existing `onEdit`, same
|
|
296
|
+
* as clearing a plain text editor by hand -- no separate callback. */
|
|
297
|
+
clearValueLabel?: string;
|
|
230
298
|
/** Called with the next column list after a move, rename or hide. */
|
|
231
299
|
onColumnsChange?: (columns: DataTableColumn<T>[]) => void;
|
|
300
|
+
/**
|
|
301
|
+
* Controlled column order — a plain array of `key`s (crisp/#731), lighter
|
|
302
|
+
* than `onColumnsChange`'s full column definitions (which can't round-trip
|
|
303
|
+
* through JSON: `render`/`accessor`/etc. are functions) and so the shape a
|
|
304
|
+
* saved view actually persists. Omit for an uncontrolled default seeded
|
|
305
|
+
* from `columns`' own order and updated internally by a header drag or the
|
|
306
|
+
* column menu's Move left/right. A key this doesn't mention (a column
|
|
307
|
+
* added since the order was last saved) renders after every key it DOES
|
|
308
|
+
* mention, in `columns`' own relative order — see `reorderColumns`. Column
|
|
309
|
+
* drag-to-reorder itself is always available (like resize); this prop only
|
|
310
|
+
* changes who owns the resulting order.
|
|
311
|
+
*/
|
|
312
|
+
columnOrder?: string[];
|
|
313
|
+
/** Called with the next `columnOrder` after a header drag or the column
|
|
314
|
+
* menu's Move left/right — whichever changed the order. */
|
|
315
|
+
onColumnOrderChange?: (order: string[]) => void;
|
|
232
316
|
/** Group rows under a heading row, the way a grouped view does. */
|
|
233
317
|
groupBy?: (row: T) => string;
|
|
234
318
|
/**
|
|
@@ -241,6 +325,11 @@ export type DataTableProps<T extends {
|
|
|
241
325
|
onRowsReorder?: (rows: T[]) => void;
|
|
242
326
|
/** aria-label on each row's drag grip (default "Reorder row"). */
|
|
243
327
|
reorderRowLabel?: string;
|
|
328
|
+
/** aria-label on the entity column's "Open preview" hover icon (crisp/#601;
|
|
329
|
+
* only rendered when a column sets `onOpenPreview`). Also passed through
|
|
330
|
+
* to `CommentCountBadge`'s own `previewLabel` when a column sets
|
|
331
|
+
* `onOpenComments` too (crisp/#601 supersession). */
|
|
332
|
+
openPreviewLabel?: string;
|
|
244
333
|
/**
|
|
245
334
|
* Render an error state in place of the rows. Uses the same measured
|
|
246
335
|
* `EmptyState variant="page"` surface as the zero-row state.
|
|
@@ -265,6 +354,13 @@ export type DataTableProps<T extends {
|
|
|
265
354
|
* outside `render`'s own output so a hover-only wrapper (a `Tooltip`, say)
|
|
266
355
|
* can't swallow it. */
|
|
267
356
|
onEdit?: (id: string, key: string, value: string) => Promise<void> | void;
|
|
357
|
+
/** The cell context menu's "View edit history" item (crisp/#598, checklist
|
|
358
|
+
* G-043 -- Attio's own item carries a "Pro" pill crisp has no billing
|
|
359
|
+
* concept to gate on, so the item itself always renders; see the
|
|
360
|
+
* component's own comment). Omitted: the item still renders (matching
|
|
361
|
+
* Attio, which shows it regardless of field type) but disabled, since
|
|
362
|
+
* there is nothing for it to open. */
|
|
363
|
+
onViewEditHistory?: (id: string, key: string) => void;
|
|
268
364
|
/** Sticky the first column(s) with a horizontal scroll shadow (default true). */
|
|
269
365
|
stickyFirst?: boolean;
|
|
270
366
|
/** Sticky the LAST column with a horizontal scroll shadow, mirroring
|
|
@@ -337,7 +433,7 @@ export type DataTableProps<T extends {
|
|
|
337
433
|
};
|
|
338
434
|
export declare function DataTable<T extends {
|
|
339
435
|
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;
|
|
436
|
+
}>({ 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
437
|
export declare namespace DataTable {
|
|
342
438
|
var displayName: string;
|
|
343
439
|
}
|
|
@@ -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;
|