@crisp-ui-kit/crisp 0.35.0 → 0.37.0
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/bulkbar.css +3 -0
- package/dist/bulkbar.layered.css +3 -0
- package/dist/cjs/components/bulkbar/bulkbar.js +1 -1
- package/dist/cjs/components/bulkbar/bulkbar.recipe.js +6 -0
- package/dist/cjs/components/contextmenu/contextmenu.js +25 -8
- package/dist/cjs/components/contextmenu/contextmenu.recipe.js +5 -2
- package/dist/cjs/components/dialog/dialog.js +1 -1
- package/dist/cjs/components/dialog/dialog.recipe.js +1 -1
- package/dist/cjs/components/menu/menu.js +20 -3
- package/dist/cjs/components/menu/menu.recipe.js +4 -3
- package/dist/cjs/components/multiselect/multiselect.js +26 -9
- package/dist/cjs/components/multiselect/multiselect.recipe.js +4 -3
- package/dist/cjs/components/popover/popover.js +25 -8
- package/dist/cjs/components/popover/popover.recipe.js +5 -3
- package/dist/cjs/components/select/select.js +30 -9
- package/dist/cjs/components/select/select.recipe.js +5 -3
- package/dist/cjs/components/tabletoolbar/tabletoolbar.js +50 -6
- package/dist/cjs/core/floating-portal.js +28 -0
- package/dist/cjs/core/floating-stack.js +54 -0
- package/dist/cjs/core/index.js +6 -1
- package/dist/cjs/product/recordpanel/recordpanel.js +4 -2
- package/dist/cjs/product/recordpanel/recordpanel.recipe.js +8 -0
- package/dist/cjs/product/recordstable/recordstable.js +15 -4
- package/dist/cjs/product/sidebar/sidebar.js +16 -3
- package/dist/contextmenu.css +1 -1
- package/dist/contextmenu.layered.css +1 -1
- package/dist/dialog.css +1 -1
- package/dist/dialog.layered.css +1 -1
- package/dist/esm/components/bulkbar/bulkbar.js +1 -1
- package/dist/esm/components/bulkbar/bulkbar.recipe.js +6 -0
- package/dist/esm/components/contextmenu/contextmenu.js +25 -8
- package/dist/esm/components/contextmenu/contextmenu.recipe.js +5 -2
- package/dist/esm/components/dialog/dialog.js +1 -1
- package/dist/esm/components/dialog/dialog.recipe.js +1 -1
- package/dist/esm/components/menu/menu.js +21 -4
- package/dist/esm/components/menu/menu.recipe.js +4 -3
- package/dist/esm/components/multiselect/multiselect.js +27 -10
- package/dist/esm/components/multiselect/multiselect.recipe.js +4 -3
- package/dist/esm/components/popover/popover.js +26 -9
- package/dist/esm/components/popover/popover.recipe.js +5 -3
- package/dist/esm/components/select/select.js +31 -10
- package/dist/esm/components/select/select.recipe.js +5 -3
- package/dist/esm/components/tabletoolbar/tabletoolbar.js +51 -7
- package/dist/esm/core/floating-portal.js +25 -0
- package/dist/esm/core/floating-stack.js +50 -0
- package/dist/esm/core/index.js +2 -0
- package/dist/esm/product/recordpanel/recordpanel.js +4 -2
- package/dist/esm/product/recordpanel/recordpanel.recipe.js +8 -0
- package/dist/esm/product/recordstable/recordstable.js +16 -5
- package/dist/esm/product/sidebar/sidebar.js +17 -4
- package/dist/menu.css +1 -1
- package/dist/menu.layered.css +1 -1
- package/dist/multiselect.css +1 -1
- package/dist/multiselect.layered.css +1 -1
- package/dist/popover.css +1 -1
- package/dist/popover.layered.css +1 -1
- package/dist/recordpanel.css +6 -0
- package/dist/recordpanel.layered.css +6 -0
- package/dist/select.css +1 -1
- package/dist/select.layered.css +1 -1
- package/dist/styles.css +15 -6
- package/dist/styles.layered.css +15 -6
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +10 -1
- package/dist/types/core/floating-portal.d.ts +25 -0
- package/dist/types/core/floating-stack.d.ts +13 -0
- package/dist/types/core/index.d.ts +2 -0
- package/dist/types/product/recordpanel/recordpanel.d.ts +11 -1
- package/dist/types/product/sidebar/sidebar.d.ts +56 -0
- package/package.json +1 -1
package/dist/recordpanel.css
CHANGED
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
& .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
26
26
|
& .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
27
27
|
& .crisp-recordpanel-link:hover { text-decoration: underline; }
|
|
28
|
+
/* #329: an optional slot for record actions (e.g. Edit). Reuses the header's own measured values rather than inventing new ones -- the
|
|
29
|
+
same horizontal inset (space.3), the same hairline border token
|
|
30
|
+
(borderSubtle, flipped to border-top since this sits at the opposite
|
|
31
|
+
edge), and the header/body gap (space.2) for its own vertical padding
|
|
32
|
+
and for spacing between whatever it's given. */
|
|
33
|
+
& .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
& .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
27
27
|
& .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
28
28
|
& .crisp-recordpanel-link:hover { text-decoration: underline; }
|
|
29
|
+
/* #329: an optional slot for record actions (e.g. Edit). Reuses the header's own measured values rather than inventing new ones -- the
|
|
30
|
+
same horizontal inset (space.3), the same hairline border token
|
|
31
|
+
(borderSubtle, flipped to border-top since this sits at the opposite
|
|
32
|
+
edge), and the header/body gap (space.2) for its own vertical padding
|
|
33
|
+
and for spacing between whatever it's given. */
|
|
34
|
+
& .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
@media (prefers-reduced-motion: reduce) {
|
package/dist/select.css
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
& .crisp-select-placeholder { color: var(--crisp-fg-muted); }
|
|
9
9
|
& .crisp-select-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
|
|
10
10
|
& .crisp-select-trigger[data-open] .crisp-select-chevron { transform: rotate(180deg); }
|
|
11
|
-
& .crisp-select-listbox { position: fixed; z-index:
|
|
11
|
+
& .crisp-select-listbox { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); max-height: 280px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
12
12
|
& .crisp-select-listbox[data-up] { transform-origin: bottom; }
|
|
13
13
|
& .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
14
14
|
& .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-1)) calc(-1 * var(--crisp-space-1)) var(--crisp-space-1); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
package/dist/select.layered.css
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
& .crisp-select-placeholder { color: var(--crisp-fg-muted); }
|
|
10
10
|
& .crisp-select-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
|
|
11
11
|
& .crisp-select-trigger[data-open] .crisp-select-chevron { transform: rotate(180deg); }
|
|
12
|
-
& .crisp-select-listbox { position: fixed; z-index:
|
|
12
|
+
& .crisp-select-listbox { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); max-height: 280px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
13
13
|
& .crisp-select-listbox[data-up] { transform-origin: bottom; }
|
|
14
14
|
& .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
15
15
|
& .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-1)) calc(-1 * var(--crisp-space-1)) var(--crisp-space-1); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
package/dist/styles.css
CHANGED
|
@@ -283,6 +283,9 @@
|
|
|
283
283
|
& .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
|
|
284
284
|
& .crisp-bulkbar-count:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); color: var(--crisp-fg-primary); }
|
|
285
285
|
& .crisp-bulkbar-count svg { flex-shrink: 0; }
|
|
286
|
+
/* the ", Clear selection" ARIA concatenates onto the pill's name (#324)
|
|
287
|
+
-- read, never drawn. Same technique as Slider's thumblabel. */
|
|
288
|
+
& .crisp-bulkbar-clearlabel { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
286
289
|
& .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
|
|
287
290
|
& .crisp-bulkbar-btn:hover { background: var(--crisp-bg-raised); }
|
|
288
291
|
& .crisp-bulkbar-btn--danger { color: var(--crisp-bg-danger); }
|
|
@@ -447,7 +450,7 @@
|
|
|
447
450
|
|
|
448
451
|
.crisp-contextmenu {
|
|
449
452
|
display: contents; font-family: var(--crisp-font-sans);
|
|
450
|
-
& .crisp-contextmenu-content { position: fixed; z-index:
|
|
453
|
+
& .crisp-contextmenu-content { position: fixed; z-index: 70; min-width: 200px; box-sizing: border-box; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; transform-origin: top left; @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
451
454
|
& .crisp-contextmenu-item { display: flex; align-items: center; gap: var(--crisp-space-2); width: 100%; height: var(--crisp-size-menuRow); box-sizing: border-box; padding: 0 var(--crisp-space-2); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); text-align: start; white-space: nowrap; cursor: pointer; }
|
|
452
455
|
& .crisp-contextmenu-item svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
453
456
|
& .crisp-contextmenu-item:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); }
|
|
@@ -707,7 +710,7 @@
|
|
|
707
710
|
& .crisp-dialog-card { display: flex; flex-direction: column; flex: 1; min-height: 0; box-sizing: border-box; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); overflow: hidden; }
|
|
708
711
|
& .crisp-dialog-header { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; height: 52px; padding: 0 var(--crisp-space-2) 0 var(--crisp-space-4); border-bottom: 1px solid var(--crisp-border-subtle); }
|
|
709
712
|
& .crisp-dialog-header svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
710
|
-
& .crisp-dialog-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
713
|
+
& .crisp-dialog-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); margin: 0; }
|
|
711
714
|
& .crisp-dialog-close { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 28px; height: 28px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
|
|
712
715
|
& .crisp-dialog-close:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
|
|
713
716
|
& .crisp-dialog-body { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: var(--crisp-space-4); padding: var(--crisp-space-5) var(--crisp-space-4); }
|
|
@@ -970,7 +973,7 @@
|
|
|
970
973
|
|
|
971
974
|
.crisp-menu {
|
|
972
975
|
position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
973
|
-
& .crisp-menu-content { position: fixed; z-index:
|
|
976
|
+
& .crisp-menu-content { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); min-width: 200px; max-height: 360px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
974
977
|
& .crisp-menu-content[data-align="end"] { transform-origin: top right; }
|
|
975
978
|
& .crisp-menu-content[data-up] { transform-origin: bottom left; }
|
|
976
979
|
& .crisp-menu-content[data-up][data-align="end"] { transform-origin: bottom right; }
|
|
@@ -1009,7 +1012,7 @@
|
|
|
1009
1012
|
& .crisp-multiselect-placeholder { color: var(--crisp-fg-muted); }
|
|
1010
1013
|
& .crisp-multiselect-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
|
|
1011
1014
|
& .crisp-multiselect-trigger[data-open] .crisp-multiselect-chevron { transform: rotate(180deg); }
|
|
1012
|
-
& .crisp-multiselect-listbox { position: fixed; z-index:
|
|
1015
|
+
& .crisp-multiselect-listbox { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); max-height: 300px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
1013
1016
|
& .crisp-multiselect-listbox[data-up] { transform-origin: bottom left; }
|
|
1014
1017
|
& .crisp-multiselect-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
1015
1018
|
& .crisp-multiselect-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-1)) calc(-1 * var(--crisp-space-1)) var(--crisp-space-1); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
|
@@ -1042,7 +1045,7 @@
|
|
|
1042
1045
|
|
|
1043
1046
|
.crisp-popover {
|
|
1044
1047
|
display: contents; font-family: var(--crisp-font-sans);
|
|
1045
|
-
& .crisp-popover-content { position: fixed; z-index:
|
|
1048
|
+
& .crisp-popover-content { position: fixed; z-index: 70; box-sizing: border-box; min-width: 200px; max-width: min(360px, 92vw); padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); color: var(--crisp-fg-primary); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); opacity: 1; transform: none; transition: opacity 0.08s ease, transform 0.08s ease; transform-origin: top left; @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
1046
1049
|
& .crisp-popover-content[data-align="end"] { transform-origin: top right; }
|
|
1047
1050
|
& .crisp-popover-content[data-up] { transform-origin: bottom left; }
|
|
1048
1051
|
}
|
|
@@ -1214,7 +1217,7 @@
|
|
|
1214
1217
|
& .crisp-select-placeholder { color: var(--crisp-fg-muted); }
|
|
1215
1218
|
& .crisp-select-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
|
|
1216
1219
|
& .crisp-select-trigger[data-open] .crisp-select-chevron { transform: rotate(180deg); }
|
|
1217
|
-
& .crisp-select-listbox { position: fixed; z-index:
|
|
1220
|
+
& .crisp-select-listbox { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); max-height: 280px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
1218
1221
|
& .crisp-select-listbox[data-up] { transform-origin: bottom; }
|
|
1219
1222
|
& .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
1220
1223
|
& .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-1)) calc(-1 * var(--crisp-space-1)) var(--crisp-space-1); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
|
@@ -2062,6 +2065,12 @@
|
|
|
2062
2065
|
& .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
2063
2066
|
& .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
2064
2067
|
& .crisp-recordpanel-link:hover { text-decoration: underline; }
|
|
2068
|
+
/* #329: an optional slot for record actions (e.g. Edit). Reuses the header's own measured values rather than inventing new ones -- the
|
|
2069
|
+
same horizontal inset (space.3), the same hairline border token
|
|
2070
|
+
(borderSubtle, flipped to border-top since this sits at the opposite
|
|
2071
|
+
edge), and the header/body gap (space.2) for its own vertical padding
|
|
2072
|
+
and for spacing between whatever it's given. */
|
|
2073
|
+
& .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
|
|
2065
2074
|
}
|
|
2066
2075
|
|
|
2067
2076
|
@media (prefers-reduced-motion: reduce) {
|
package/dist/styles.layered.css
CHANGED
|
@@ -284,6 +284,9 @@
|
|
|
284
284
|
& .crisp-bulkbar-count { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); margin: 0; padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: color-mix(in srgb, var(--crisp-fg-primary) 4%, transparent); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
|
|
285
285
|
& .crisp-bulkbar-count:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); color: var(--crisp-fg-primary); }
|
|
286
286
|
& .crisp-bulkbar-count svg { flex-shrink: 0; }
|
|
287
|
+
/* the ", Clear selection" ARIA concatenates onto the pill's name (#324)
|
|
288
|
+
-- read, never drawn. Same technique as Slider's thumblabel. */
|
|
289
|
+
& .crisp-bulkbar-clearlabel { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
287
290
|
& .crisp-bulkbar-btn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-menuRow); padding: 0 var(--crisp-space-2); border: none; border-radius: var(--crisp-radius-md); background: transparent; color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); white-space: nowrap; cursor: pointer; transition: background-color .12s; }
|
|
288
291
|
& .crisp-bulkbar-btn:hover { background: var(--crisp-bg-raised); }
|
|
289
292
|
& .crisp-bulkbar-btn--danger { color: var(--crisp-bg-danger); }
|
|
@@ -448,7 +451,7 @@
|
|
|
448
451
|
|
|
449
452
|
.crisp-contextmenu {
|
|
450
453
|
display: contents; font-family: var(--crisp-font-sans);
|
|
451
|
-
& .crisp-contextmenu-content { position: fixed; z-index:
|
|
454
|
+
& .crisp-contextmenu-content { position: fixed; z-index: 70; min-width: 200px; box-sizing: border-box; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; transform-origin: top left; @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
452
455
|
& .crisp-contextmenu-item { display: flex; align-items: center; gap: var(--crisp-space-2); width: 100%; height: var(--crisp-size-menuRow); box-sizing: border-box; padding: 0 var(--crisp-space-2); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-lg); text-align: start; white-space: nowrap; cursor: pointer; }
|
|
453
456
|
& .crisp-contextmenu-item svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
454
457
|
& .crisp-contextmenu-item:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); }
|
|
@@ -708,7 +711,7 @@
|
|
|
708
711
|
& .crisp-dialog-card { display: flex; flex-direction: column; flex: 1; min-height: 0; box-sizing: border-box; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); box-shadow: 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); overflow: hidden; }
|
|
709
712
|
& .crisp-dialog-header { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; height: 52px; padding: 0 var(--crisp-space-2) 0 var(--crisp-space-4); border-bottom: 1px solid var(--crisp-border-subtle); }
|
|
710
713
|
& .crisp-dialog-header svg { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
711
|
-
& .crisp-dialog-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
714
|
+
& .crisp-dialog-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); margin: 0; }
|
|
712
715
|
& .crisp-dialog-close { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 28px; height: 28px; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-md); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; }
|
|
713
716
|
& .crisp-dialog-close:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: var(--crisp-fg-primary); }
|
|
714
717
|
& .crisp-dialog-body { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: var(--crisp-space-4); padding: var(--crisp-space-5) var(--crisp-space-4); }
|
|
@@ -971,7 +974,7 @@
|
|
|
971
974
|
|
|
972
975
|
.crisp-menu {
|
|
973
976
|
position: relative; display: inline-flex; font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
974
|
-
& .crisp-menu-content { position: fixed; z-index:
|
|
977
|
+
& .crisp-menu-content { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); min-width: 200px; max-height: 360px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
975
978
|
& .crisp-menu-content[data-align="end"] { transform-origin: top right; }
|
|
976
979
|
& .crisp-menu-content[data-up] { transform-origin: bottom left; }
|
|
977
980
|
& .crisp-menu-content[data-up][data-align="end"] { transform-origin: bottom right; }
|
|
@@ -1010,7 +1013,7 @@
|
|
|
1010
1013
|
& .crisp-multiselect-placeholder { color: var(--crisp-fg-muted); }
|
|
1011
1014
|
& .crisp-multiselect-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
|
|
1012
1015
|
& .crisp-multiselect-trigger[data-open] .crisp-multiselect-chevron { transform: rotate(180deg); }
|
|
1013
|
-
& .crisp-multiselect-listbox { position: fixed; z-index:
|
|
1016
|
+
& .crisp-multiselect-listbox { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); max-height: 300px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
1014
1017
|
& .crisp-multiselect-listbox[data-up] { transform-origin: bottom left; }
|
|
1015
1018
|
& .crisp-multiselect-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
1016
1019
|
& .crisp-multiselect-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-1)) calc(-1 * var(--crisp-space-1)) var(--crisp-space-1); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
|
@@ -1043,7 +1046,7 @@
|
|
|
1043
1046
|
|
|
1044
1047
|
.crisp-popover {
|
|
1045
1048
|
display: contents; font-family: var(--crisp-font-sans);
|
|
1046
|
-
& .crisp-popover-content { position: fixed; z-index:
|
|
1049
|
+
& .crisp-popover-content { position: fixed; z-index: 70; box-sizing: border-box; min-width: 200px; max-width: min(360px, 92vw); padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); color: var(--crisp-fg-primary); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); opacity: 1; transform: none; transition: opacity 0.08s ease, transform 0.08s ease; transform-origin: top left; @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
1047
1050
|
& .crisp-popover-content[data-align="end"] { transform-origin: top right; }
|
|
1048
1051
|
& .crisp-popover-content[data-up] { transform-origin: bottom left; }
|
|
1049
1052
|
}
|
|
@@ -1215,7 +1218,7 @@
|
|
|
1215
1218
|
& .crisp-select-placeholder { color: var(--crisp-fg-muted); }
|
|
1216
1219
|
& .crisp-select-chevron { flex-shrink: 0; color: var(--crisp-fg-muted); transition: transform .15s ease; }
|
|
1217
1220
|
& .crisp-select-trigger[data-open] .crisp-select-chevron { transform: rotate(180deg); }
|
|
1218
|
-
& .crisp-select-listbox { position: fixed; z-index:
|
|
1221
|
+
& .crisp-select-listbox { position: fixed; z-index: 70; box-sizing: border-box; display: flex; flex-direction: column; gap: var(--crisp-space-px); max-height: 280px; overflow-y: auto; padding: var(--crisp-space-1); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-popover); box-shadow: inset 0 0 0 1px var(--crisp-ring-popover), 0 0 0 1px var(--crisp-shadow-popover1), 0 4px 8px -4px var(--crisp-shadow-popover2), 0 4px 12px -2px var(--crisp-shadow-popover3); transform-origin: top left; opacity: 1; transform: none; transition: opacity .08s ease, transform .08s ease; }
|
|
1219
1222
|
& .crisp-select-listbox[data-up] { transform-origin: bottom; }
|
|
1220
1223
|
& .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.97) translateY(-1px); } }
|
|
1221
1224
|
& .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-1)) calc(-1 * var(--crisp-space-1)) var(--crisp-space-1); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-muted); }
|
|
@@ -2063,6 +2066,12 @@
|
|
|
2063
2066
|
& .crisp-recordstable-tag[data-tone="orange"] { background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent); }
|
|
2064
2067
|
& .crisp-recordpanel-link { color: var(--crisp-bg-brand-solid); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
2065
2068
|
& .crisp-recordpanel-link:hover { text-decoration: underline; }
|
|
2069
|
+
/* #329: an optional slot for record actions (e.g. Edit). Reuses the header's own measured values rather than inventing new ones -- the
|
|
2070
|
+
same horizontal inset (space.3), the same hairline border token
|
|
2071
|
+
(borderSubtle, flipped to border-top since this sits at the opposite
|
|
2072
|
+
edge), and the header/body gap (space.2) for its own vertical padding
|
|
2073
|
+
and for spacing between whatever it's given. */
|
|
2074
|
+
& .crisp-recordpanel-footer { flex-shrink: 0; display: flex; align-items: center; gap: var(--crisp-space-2); padding: var(--crisp-space-2) var(--crisp-space-3); border-top: 1px solid var(--crisp-border-subtle); }
|
|
2066
2075
|
}
|
|
2067
2076
|
|
|
2068
2077
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -8,18 +8,27 @@ export type ToolbarSort = {
|
|
|
8
8
|
key: string;
|
|
9
9
|
dir: SortDir;
|
|
10
10
|
};
|
|
11
|
-
export type ToolbarFilterOp = "contains" | "is" | "isnot" | "empty" | "notempty";
|
|
11
|
+
export type ToolbarFilterOp = "contains" | "is" | "isnot" | "isanyof" | "empty" | "notempty";
|
|
12
12
|
export type ToolbarFilter = {
|
|
13
13
|
id: string;
|
|
14
14
|
key: string;
|
|
15
15
|
op: ToolbarFilterOp;
|
|
16
16
|
value: string;
|
|
17
|
+
/** Selected values for `"isanyof"` — ignored by every other op. */
|
|
18
|
+
values?: string[];
|
|
17
19
|
};
|
|
18
20
|
export type TableToolbarColumn = {
|
|
19
21
|
key: string;
|
|
20
22
|
label: string;
|
|
21
23
|
/** Leading field-type icon, shown in the field pickers. */
|
|
22
24
|
icon?: IconType;
|
|
25
|
+
/**
|
|
26
|
+
* This column's distinct values (a status/select field's option set, e.g.).
|
|
27
|
+
* Supplying it adds `"isanyof"` — a searchable checkbox list, Attio's
|
|
28
|
+
* faceted multi-select filter — to the column's condition picker. Omit it
|
|
29
|
+
* for a free-text column; there is nothing to check off.
|
|
30
|
+
*/
|
|
31
|
+
values?: string[];
|
|
23
32
|
};
|
|
24
33
|
export type TableToolbarProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"> & {
|
|
25
34
|
/** The fields that can be sorted and filtered on. */
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Portals a floating layer (a `position: fixed` listbox/menu/popover
|
|
4
|
+
* content) to `document.body` — exactly what Tooltip already did with a
|
|
5
|
+
* bare `createPortal` call, pulled out so `Select`, `MultiSelect`, `Menu`,
|
|
6
|
+
* `Popover` and `ContextMenu` share the one implementation (#339).
|
|
7
|
+
*
|
|
8
|
+
* Needed because a `position: fixed` box resolves against the nearest
|
|
9
|
+
* ancestor that establishes a containing block for it — not necessarily the
|
|
10
|
+
* viewport. `transform` (even the identity `scale(1)`), `filter` and
|
|
11
|
+
* `backdrop-filter` all qualify, and `Dialog`'s own measured surface sets
|
|
12
|
+
* both a resting `transform: scale(1)` (so its `@starting-style` entrance
|
|
13
|
+
* has something to animate from) and `backdrop-filter: blur(15px)` (Attio's
|
|
14
|
+
* frosted-glass modal). A floating layer opened from a trigger inside a
|
|
15
|
+
* `Dialog` was rendering offset by the dialog's own box instead of anchored
|
|
16
|
+
* to its trigger.
|
|
17
|
+
*
|
|
18
|
+
* Every caller renders this conditionally on its own `open` state, which
|
|
19
|
+
* starts `false` and is driven only by client interaction — never a prop a
|
|
20
|
+
* fixture sets true at mount (unlike Dialog/Drawer/Command) — so this never
|
|
21
|
+
* touches `document` during SSR, the same safety Tooltip already had.
|
|
22
|
+
*/
|
|
23
|
+
export declare function FloatingPortal({ children, }: {
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}): React.ReactPortal;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Call when a layer opens; call the returned cleanup when it closes. */
|
|
2
|
+
export declare function registerFloatingLayer(el: HTMLElement): () => void;
|
|
3
|
+
/**
|
|
4
|
+
* True when `target` sits inside a layer that was registered strictly after
|
|
5
|
+
* `self` — a layer that could only have been spawned from inside `self`,
|
|
6
|
+
* directly or through further nesting.
|
|
7
|
+
*
|
|
8
|
+
* Pass `null` for `self` when the caller is a hand-rolled dropdown that
|
|
9
|
+
* doesn't register itself on this stack (RecordsTable's and TableToolbar's
|
|
10
|
+
* own popovers, e.g.) — every registered layer then counts, which is the
|
|
11
|
+
* right query for "was this click inside some floating child I opened".
|
|
12
|
+
*/
|
|
13
|
+
export declare function isInsideLaterFloatingLayer(target: Node, self: HTMLElement | null): boolean;
|
|
@@ -3,6 +3,8 @@ export { cx } from "./cx";
|
|
|
3
3
|
export { defineRecipe } from "./define";
|
|
4
4
|
export { withDescribedBy } from "./dialog-description";
|
|
5
5
|
export { isRtlElement } from "./direction";
|
|
6
|
+
export { FloatingPortal } from "./floating-portal";
|
|
7
|
+
export { isInsideLaterFloatingLayer, registerFloatingLayer, } from "./floating-stack";
|
|
6
8
|
export { formValueStyle } from "./form-value";
|
|
7
9
|
export { type FloatingAlign, type PlaceFloatingOptions, placeFloating, } from "./place-floating";
|
|
8
10
|
export { Primitive } from "./primitive";
|
|
@@ -4,10 +4,20 @@ export type RecordPanelProps = Omit<React.ComponentPropsWithoutRef<"div">, "chil
|
|
|
4
4
|
/** The record to show; render nothing when null. */
|
|
5
5
|
/** Label for the close control. */
|
|
6
6
|
closeLabel?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The panel's heading, and so its accessible name (via `aria-labelledby`,
|
|
9
|
+
* not a stringified `aria-label` — it also drives the visible title, which
|
|
10
|
+
* can be any node). Defaults to the entity column's name, same as before
|
|
11
|
+
* this prop existed; pass it to title the panel by something else, e.g.
|
|
12
|
+
* "{Collection} record".
|
|
13
|
+
*/
|
|
14
|
+
title?: React.ReactNode;
|
|
7
15
|
/** Heading above the field list. */
|
|
8
16
|
detailsLabel?: React.ReactNode;
|
|
9
17
|
/** Shown in place of a field that has no value. */
|
|
10
18
|
emptyLabel?: React.ReactNode;
|
|
19
|
+
/** Rendered below the field list, e.g. an Edit button. Omit for no footer. */
|
|
20
|
+
footer?: React.ReactNode;
|
|
11
21
|
record: Row | null;
|
|
12
22
|
columns: Column[];
|
|
13
23
|
onClose: () => void;
|
|
@@ -19,7 +29,7 @@ export type RecordPanelProps = Omit<React.ComponentPropsWithoutRef<"div">, "chil
|
|
|
19
29
|
* relative` container (e.g. the app main area); it slides in from the right and
|
|
20
30
|
* overlays the content.
|
|
21
31
|
*/
|
|
22
|
-
export declare function RecordPanel({ record, columns, onClose, className, closeLabel, detailsLabel, emptyLabel, ...rest }: RecordPanelProps): React.JSX.Element | null;
|
|
32
|
+
export declare function RecordPanel({ record, columns, onClose, className, closeLabel, title, detailsLabel, emptyLabel, footer, ...rest }: RecordPanelProps): React.JSX.Element | null;
|
|
23
33
|
export declare namespace RecordPanel {
|
|
24
34
|
var displayName: string;
|
|
25
35
|
}
|
|
@@ -40,6 +40,42 @@ export type SidebarListsSection = {
|
|
|
40
40
|
label: string;
|
|
41
41
|
newListLabel: string;
|
|
42
42
|
};
|
|
43
|
+
/** A row in a `groups` section (#325). */
|
|
44
|
+
export type SidebarNavGroupItem = {
|
|
45
|
+
label: string;
|
|
46
|
+
/** 16px icon component, rendered `<Icon />`. Optional — not every group's
|
|
47
|
+
* rows carry one (unlike the main nav's `SidebarNavItem`, where it's
|
|
48
|
+
* required). */
|
|
49
|
+
icon?: React.ComponentType<IconProps>;
|
|
50
|
+
/** Either this or `onSelect` — a plain link, or a handler for anything
|
|
51
|
+
* that isn't real navigation (opening a panel, selecting a view). Both
|
|
52
|
+
* may be set; neither is required to make the row *something* clickable
|
|
53
|
+
* (it still renders as a link, defaulting `href` to "#"). */
|
|
54
|
+
href?: string;
|
|
55
|
+
onSelect?: () => void;
|
|
56
|
+
active?: boolean;
|
|
57
|
+
/** Trailing content — a count, a badge, anything `NavItem`'s own
|
|
58
|
+
* `trailing` slot already takes. */
|
|
59
|
+
count?: React.ReactNode;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* A named, collapsible group of `SidebarNavGroupItem` rows — navigation as
|
|
63
|
+
* data, for a consumer whose sections aren't Attio's Records/Lists/Chats
|
|
64
|
+
* (#325). Pass `groups` to `Sidebar` and it replaces those three sections
|
|
65
|
+
* entirely; a group's `items` can come from runtime data (a re-render with a
|
|
66
|
+
* new array is all a group needs to pick up new rows).
|
|
67
|
+
*/
|
|
68
|
+
export type SidebarNavGroup = {
|
|
69
|
+
/** Identity for this group's own collapse state across renders. Falls
|
|
70
|
+
* back to `label` — set it explicitly if two groups could ever share a
|
|
71
|
+
* label, or if a group's label itself changes at runtime. */
|
|
72
|
+
key?: string;
|
|
73
|
+
label: string;
|
|
74
|
+
items: SidebarNavGroupItem[];
|
|
75
|
+
/** Starts this group collapsed (default: expanded, matching every
|
|
76
|
+
* existing section). Read once, on mount. */
|
|
77
|
+
defaultCollapsed?: boolean;
|
|
78
|
+
};
|
|
43
79
|
/** Footer copy: the onboarding pill, the invite row, and the trial banner. */
|
|
44
80
|
export type SidebarFooter = {
|
|
45
81
|
gettingStartedLabel: string;
|
|
@@ -67,6 +103,16 @@ export type SidebarProps = React.ComponentPropsWithoutRef<"nav"> & {
|
|
|
67
103
|
listsSection?: SidebarListsSection;
|
|
68
104
|
/** The Chats section (label + nav-item rows). */
|
|
69
105
|
chatsSection?: SidebarSection;
|
|
106
|
+
/**
|
|
107
|
+
* Navigation as data (#325): any number of named, collapsible groups,
|
|
108
|
+
* reusing the same section markup/recipe as Records/Lists/Chats. When
|
|
109
|
+
* given, it REPLACES those three sections entirely — a consumer whose
|
|
110
|
+
* sections aren't Attio's (internal/grc's Activity, Governance, Identity,
|
|
111
|
+
* Organization, System Administration, plus user-built registers) passes
|
|
112
|
+
* `groups` instead of the three fixed props. Omit it and `<Sidebar />`
|
|
113
|
+
* renders exactly as before this prop existed.
|
|
114
|
+
*/
|
|
115
|
+
groups?: SidebarNavGroup[];
|
|
70
116
|
/** Footer copy (onboarding pill, invite row, trial banner). */
|
|
71
117
|
footer?: SidebarFooter;
|
|
72
118
|
};
|
|
@@ -102,6 +148,16 @@ export declare const Sidebar: React.ForwardRefExoticComponent<Omit<React.Detaile
|
|
|
102
148
|
listsSection?: SidebarListsSection;
|
|
103
149
|
/** The Chats section (label + nav-item rows). */
|
|
104
150
|
chatsSection?: SidebarSection;
|
|
151
|
+
/**
|
|
152
|
+
* Navigation as data (#325): any number of named, collapsible groups,
|
|
153
|
+
* reusing the same section markup/recipe as Records/Lists/Chats. When
|
|
154
|
+
* given, it REPLACES those three sections entirely — a consumer whose
|
|
155
|
+
* sections aren't Attio's (internal/grc's Activity, Governance, Identity,
|
|
156
|
+
* Organization, System Administration, plus user-built registers) passes
|
|
157
|
+
* `groups` instead of the three fixed props. Omit it and `<Sidebar />`
|
|
158
|
+
* renders exactly as before this prop existed.
|
|
159
|
+
*/
|
|
160
|
+
groups?: SidebarNavGroup[];
|
|
105
161
|
/** Footer copy (onboarding pill, invite row, trial banner). */
|
|
106
162
|
footer?: SidebarFooter;
|
|
107
163
|
} & React.RefAttributes<HTMLDivElement>>;
|