@crisp-ui-kit/crisp 0.53.5 → 0.54.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/cjs/components/bulkbar/bulkbar.js +5 -1
- package/dist/cjs/components/fileupload/fileupload.js +19 -3
- package/dist/cjs/components/formfield/formfield.js +8 -1
- package/dist/cjs/components/heatmapchart/heatmapchart.js +14 -2
- package/dist/cjs/components/skiplink/index.js +17 -0
- package/dist/cjs/components/skiplink/skiplink.js +16 -0
- package/dist/cjs/components/skiplink/skiplink.recipe.js +33 -0
- package/dist/cjs/components/textlink/index.js +7 -0
- package/dist/cjs/components/textlink/textlink.js +16 -0
- package/dist/cjs/components/textlink/textlink.recipe.js +35 -0
- package/dist/cjs/components/visuallyhidden/index.js +17 -0
- package/dist/cjs/components/visuallyhidden/visuallyhidden.js +16 -0
- package/dist/cjs/components/visuallyhidden/visuallyhidden.recipe.js +20 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/product/board/board.js +11 -2
- package/dist/cjs/product/command/command.js +13 -1
- package/dist/cjs/product/flowcanvas/flowcanvas.js +9 -2
- package/dist/cjs/product/headerbar/headerbar.js +15 -0
- package/dist/cjs/product/headerbar/headerbar.recipe.js +35 -0
- package/dist/cjs/product/headerbar/index.js +17 -0
- package/dist/cjs/product/inbox/inbox.js +13 -1
- package/dist/cjs/product/onboarding/onboarding.js +22 -1
- package/dist/cjs/product/recordpage/index.js +2 -1
- package/dist/cjs/product/recordpage/recordpage.js +197 -123
- package/dist/cjs/product/recordpage/recordpage.recipe.js +5 -0
- package/dist/cjs/product/tasklist/tasklist.js +8 -1
- package/dist/esm/components/bulkbar/bulkbar.js +5 -1
- package/dist/esm/components/fileupload/fileupload.js +20 -4
- package/dist/esm/components/formfield/formfield.js +8 -1
- package/dist/esm/components/heatmapchart/heatmapchart.js +14 -2
- package/dist/esm/components/skiplink/index.js +1 -0
- package/dist/esm/components/skiplink/skiplink.js +13 -0
- package/dist/esm/components/skiplink/skiplink.recipe.js +30 -0
- package/dist/esm/components/textlink/index.js +2 -0
- package/dist/esm/components/textlink/textlink.js +13 -0
- package/dist/esm/components/textlink/textlink.recipe.js +32 -0
- package/dist/esm/components/visuallyhidden/index.js +1 -0
- package/dist/esm/components/visuallyhidden/visuallyhidden.js +13 -0
- package/dist/esm/components/visuallyhidden/visuallyhidden.recipe.js +17 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/product/board/board.js +12 -3
- package/dist/esm/product/command/command.js +14 -2
- package/dist/esm/product/flowcanvas/flowcanvas.js +9 -2
- package/dist/esm/product/headerbar/headerbar.js +12 -0
- package/dist/esm/product/headerbar/headerbar.recipe.js +32 -0
- package/dist/esm/product/headerbar/index.js +1 -0
- package/dist/esm/product/inbox/inbox.js +13 -1
- package/dist/esm/product/onboarding/onboarding.js +22 -1
- package/dist/esm/product/recordpage/index.js +1 -1
- package/dist/esm/product/recordpage/recordpage.js +197 -124
- package/dist/esm/product/recordpage/recordpage.recipe.js +5 -0
- package/dist/esm/product/tasklist/tasklist.js +8 -1
- package/dist/headerbar.css +7 -0
- package/dist/headerbar.d.ts +7 -0
- package/dist/headerbar.layered.css +9 -0
- package/dist/recordpage.css +17 -31
- package/dist/recordpage.layered.css +17 -31
- package/dist/skiplink.css +5 -0
- package/dist/skiplink.d.ts +7 -0
- package/dist/skiplink.layered.css +7 -0
- package/dist/styles.css +47 -31
- package/dist/styles.layered.css +47 -31
- package/dist/textlink.css +11 -0
- package/dist/textlink.d.ts +7 -0
- package/dist/textlink.layered.css +13 -0
- package/dist/types/components/bulkbar/bulkbar.d.ts +1 -1
- package/dist/types/components/heatmapchart/heatmapchart.d.ts +1 -1
- package/dist/types/components/skiplink/index.d.ts +1 -0
- package/dist/types/components/skiplink/skiplink.d.ts +18 -0
- package/dist/types/components/skiplink/skiplink.recipe.d.ts +3 -0
- package/dist/types/components/textlink/index.d.ts +2 -0
- package/dist/types/components/textlink/textlink.d.ts +19 -0
- package/dist/types/components/textlink/textlink.recipe.d.ts +13 -0
- package/dist/types/components/visuallyhidden/index.d.ts +1 -0
- package/dist/types/components/visuallyhidden/visuallyhidden.d.ts +15 -0
- package/dist/types/components/visuallyhidden/visuallyhidden.recipe.d.ts +3 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/product/board/board.d.ts +1 -1
- package/dist/types/product/command/command.d.ts +1 -1
- package/dist/types/product/flowcanvas/flowcanvas.d.ts +1 -1
- package/dist/types/product/headerbar/headerbar.d.ts +27 -0
- package/dist/types/product/headerbar/headerbar.recipe.d.ts +3 -0
- package/dist/types/product/headerbar/index.d.ts +1 -0
- package/dist/types/product/inbox/inbox.d.ts +1 -1
- package/dist/types/product/onboarding/onboarding.d.ts +1 -1
- package/dist/types/product/recordpage/index.d.ts +1 -1
- package/dist/types/product/recordpage/recordpage.d.ts +90 -1
- package/dist/types/product/tasklist/tasklist.d.ts +1 -1
- package/dist/visuallyhidden.css +3 -0
- package/dist/visuallyhidden.d.ts +7 -0
- package/dist/visuallyhidden.layered.css +5 -0
- package/package.json +21 -1
package/dist/styles.layered.css
CHANGED
|
@@ -1491,6 +1491,12 @@
|
|
|
1491
1491
|
}
|
|
1492
1492
|
}
|
|
1493
1493
|
|
|
1494
|
+
.crisp-skiplink {
|
|
1495
|
+
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; text-decoration: none; font-family: var(--crisp-font-sans); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary);
|
|
1496
|
+
&:focus { position: fixed; top: var(--crisp-space-3); inset-inline-start: var(--crisp-space-3); z-index: 90; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; white-space: normal; padding: var(--crisp-space-2) var(--crisp-space-3); border-radius: var(--crisp-radius-md); 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); }
|
|
1497
|
+
&:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 1px; }
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1494
1500
|
.crisp-slider {
|
|
1495
1501
|
display: flex; flex-direction: column; align-items: stretch; width: 100%; min-width: 0; gap: var(--crisp-space-0-5); font-family: var(--crisp-font-sans); user-select: none; touch-action: none; /* the position words ("minimum"/"maximum") that ARIA concatenates onto a thumb's name — read, never drawn */
|
|
1496
1502
|
& .crisp-slider-thumblabel {
|
|
@@ -1785,6 +1791,18 @@
|
|
|
1785
1791
|
}
|
|
1786
1792
|
}
|
|
1787
1793
|
|
|
1794
|
+
.crisp-textlink {
|
|
1795
|
+
display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
|
|
1796
|
+
&:hover { text-decoration: underline; }
|
|
1797
|
+
}
|
|
1798
|
+
.crisp-textlink--tone_brand {
|
|
1799
|
+
font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
|
|
1800
|
+
}
|
|
1801
|
+
.crisp-textlink--tone_muted {
|
|
1802
|
+
font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
|
|
1803
|
+
&:hover { color: var(--crisp-bg-brand-solid); }
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1788
1806
|
.crisp-toast {
|
|
1789
1807
|
display: contents; font-family: var(--crisp-font-sans);
|
|
1790
1808
|
& .crisp-toast-viewport { position: fixed; z-index: 80; inset-inline-end: var(--crisp-space-4); top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-2); width: 360px; max-width: calc(100vw - var(--crisp-space-8)); pointer-events: none; }
|
|
@@ -1824,6 +1842,10 @@
|
|
|
1824
1842
|
}
|
|
1825
1843
|
}
|
|
1826
1844
|
|
|
1845
|
+
.crisp-visuallyhidden {
|
|
1846
|
+
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1827
1849
|
.crisp-wheelpicker {
|
|
1828
1850
|
position: relative; box-sizing: border-box; width: 100%; overflow: hidden; background: var(--crisp-bg-surface); font-family: var(--crisp-font-sans); /* the band the selected row sits in; behind the items, never hit-tested */
|
|
1829
1851
|
& .crisp-wheelpicker-indicator { position: absolute; z-index: 0; inset-inline: var(--crisp-space-4); top: 50%; transform: translateY(-50%); border-radius: var(--crisp-radius-md); background: var(--crisp-bg-neutral-weak); pointer-events: none; }
|
|
@@ -2020,6 +2042,14 @@
|
|
|
2020
2042
|
& .crisp-flowcanvas-tool-sep { width: 1px; height: 18px; background: var(--crisp-border-subtle); }
|
|
2021
2043
|
}
|
|
2022
2044
|
|
|
2045
|
+
.crisp-headerbar {
|
|
2046
|
+
box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: var(--crisp-space-2); height: var(--crisp-size-header); flex-shrink: 0; padding: 0 var(--crisp-space-3); font-family: var(--crisp-font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
2047
|
+
&[data-bordered] { border-bottom: 1px solid var(--crisp-border-subtle); }
|
|
2048
|
+
& .crisp-headerbar-leading { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; min-width: 0; }
|
|
2049
|
+
& .crisp-headerbar-title { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--crisp-space-2); overflow: hidden; }
|
|
2050
|
+
& .crisp-headerbar-trailing { display: flex; align-items: center; gap: var(--crisp-space-2); flex-shrink: 0; }
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2023
2053
|
.crisp-inbox {
|
|
2024
2054
|
display: flex; flex-direction: column; box-sizing: border-box; width: 380px; max-height: 588px; border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); font-family: var(--crisp-font-sans); overflow: hidden; 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); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
|
|
2025
2055
|
& .crisp-inbox-head { padding: var(--crisp-space-3) var(--crisp-space-3) 0; }
|
|
@@ -2180,6 +2210,10 @@
|
|
|
2180
2210
|
& .crisp-recordpage-detailsearch { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: var(--crisp-size-chip); flex-shrink: 0; padding: 0; margin: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; color: var(--crisp-fg-muted); font-family: inherit; cursor: pointer; transition: background-color .12s, color .12s; }
|
|
2181
2211
|
& .crisp-recordpage-detailsearch:hover, & .crisp-recordpage-detailsearch[data-active] { background: var(--crisp-bg-raised); color: var(--crisp-fg-primary); }
|
|
2182
2212
|
& .crisp-recordpage-noresults { padding: var(--crisp-space-1-5) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
2213
|
+
/* A caller-supplied `sections` grouping (#528) is not an Attio-measured
|
|
2214
|
+
shape (its own Details column is flat) -- this heading reuses
|
|
2215
|
+
.crisp-recordpage-section-title's own type treatment verbatim, just spaced from the group above it. */
|
|
2216
|
+
& .crisp-recordpage-fieldsection-title { margin-top: var(--crisp-space-3); }
|
|
2183
2217
|
& .crisp-recordpage-morevalues { display: inline-flex; align-items: center; padding: 0; margin: 0; border: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-muted); cursor: pointer; }
|
|
2184
2218
|
& .crisp-recordpage-morevalues:hover { color: var(--crisp-fg-primary); }
|
|
2185
2219
|
& .crisp-recordpage-viewall { flex-basis: 100%; margin-top: var(--crisp-space-0-5); border: none; background: none; padding: 0; color: color-mix(in srgb, var(--crisp-fg-primary) 55%, transparent); font-family: inherit; font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-regular); cursor: pointer; text-align: start; }
|
|
@@ -2194,31 +2228,25 @@
|
|
|
2194
2228
|
& .crisp-recordpage-field-label-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2195
2229
|
& .crisp-recordpage-field-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); padding-top: 2px; line-height: 20px; font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
2196
2230
|
& .crisp-recordpage-field-value[data-editable] { cursor: pointer; }
|
|
2197
|
-
/* the click-to-edit trigger is a real <button> (keyboard-operable),
|
|
2198
|
-
|
|
2199
|
-
own -- FieldValue can render several chips (tags), which still need
|
|
2200
|
-
to wrap the way they did before this had a button around them at
|
|
2201
|
-
all. It wraps only FieldValue, never the error slot beside it (see
|
|
2202
|
-
the component's own comment) -- NOT `display: contents`, which drops a button's accessible semantics in some engines. */
|
|
2231
|
+
/* the click-to-edit trigger is a real <button> (keyboard-operable), reset back to plain inline text and made a flex-wrap container of its own -- FieldValue can render several chips (tags), which still need to wrap the way they did before this had a button around them at all. It wraps only FieldValue, never the error slot beside it (see the component's own comment) -- NOT `display: contents`, which
|
|
2232
|
+
drops a button's accessible semantics in some engines. */
|
|
2203
2233
|
& .crisp-recordpage-edit-trigger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); margin: 0; padding: 0; border: none; background: none; text-align: start; font: inherit; color: inherit; cursor: pointer; }
|
|
2204
2234
|
& .crisp-recordpage-empty { color: var(--crisp-fg-muted); }
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
above already carries the "this is interactive" affordance; the
|
|
2209
|
-
|
|
2210
|
-
`bgDanger`), per #385/#430. */
|
|
2235
|
+
/* #431: measured live on app.attio.com's record page Details column --
|
|
2236
|
+
clicking a field's value opens a plain, borderless field exactly filling the value's own box (no border, no background, no
|
|
2237
|
+
box-shadow), same font as the value it replaces (hence `font:
|
|
2238
|
+
inherit`, not a restated size/weight). A field row's own hover tint above already carries the "this is interactive" affordance; the pending/error treatment isn't Attio-measured -- it reuses the same
|
|
2239
|
+
tokens DataTable's identical states already use (opacity 0.5, `bgDanger`), per #385/#430. */
|
|
2211
2240
|
& .crisp-recordpage-edit { display: block; width: 100%; margin: 0; padding: 0; border: none; border-radius: var(--crisp-radius-sm); background: none; box-shadow: none; outline: none; font: inherit; color: inherit; }
|
|
2212
|
-
/* not Attio-measured (its own field shows no focus ring either, caret
|
|
2213
|
-
|
|
2214
|
-
other crisp field already shows on focus (DataTable's identical .crisp-datatable-edit:focus, e.g.). */
|
|
2241
|
+
/* not Attio-measured (its own field shows no focus ring either, caret only) -- kept for real keyboard users, the same brand ring every other crisp field already shows on focus (DataTable's identical
|
|
2242
|
+
.crisp-datatable-edit:focus, e.g.). */
|
|
2215
2243
|
& .crisp-recordpage-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
2216
2244
|
& .crisp-recordpage-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
2217
2245
|
& .crisp-recordpage-edit-pending { flex-shrink: 0; color: var(--crisp-fg-muted); }
|
|
2218
2246
|
& .crisp-recordpage-edit-error { flex-basis: 100%; margin-top: var(--crisp-space-0-5); font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
2219
|
-
/* #457: an `editor: "select"` field's at-rest chip -- same shape as
|
|
2220
|
-
|
|
2221
|
-
classnames verbatim here would resolve to nothing. */
|
|
2247
|
+
/* #457: an `editor: "select"` field's at-rest chip -- same shape as RecordsTable's own `.crisp-recordstable-status[-dot]` (already
|
|
2248
|
+
measured against Attio there), but its own classes: that pair is
|
|
2249
|
+
scoped under `.crisp-recordstable`'s own recipe root, so reusing the classnames verbatim here would resolve to nothing. */
|
|
2222
2250
|
& .crisp-recordpage-status { display: inline-flex; align-items: center; gap: var(--crisp-space-1-5); min-width: 0; }
|
|
2223
2251
|
& .crisp-recordpage-status-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: var(--crisp-radius-full); }
|
|
2224
2252
|
& .crisp-recordpage-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); width: 100%; }
|
|
@@ -2226,23 +2254,18 @@
|
|
|
2226
2254
|
& .crisp-recordpage-link { color: var(--crisp-fg-primary); text-decoration: none; overflow: hidden; text-overflow: ellipsis; }
|
|
2227
2255
|
& .crisp-recordpage-link:hover { text-decoration: underline; }
|
|
2228
2256
|
& .crisp-recordpage-emptystate { padding: var(--crisp-space-2) var(--crisp-space-1); font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
2229
|
-
|
|
2230
2257
|
& .crisp-recordpage-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; overflow-y: auto; padding: var(--crisp-space-3) var(--crisp-space-5); }
|
|
2231
|
-
|
|
2232
2258
|
& .crisp-recordpage-panel { padding-top: var(--crisp-space-4); display: flex; flex-direction: column; gap: var(--crisp-space-4); }
|
|
2233
2259
|
& .crisp-recordpage-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); background: var(--crisp-bg-surface); overflow: hidden; }
|
|
2234
2260
|
& .crisp-recordpage-card-title { font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-semibold); letter-spacing: -0.14px; color: var(--crisp-fg-primary); padding: var(--crisp-space-3) var(--crisp-space-3) var(--crisp-space-2); }
|
|
2235
2261
|
& .crisp-recordpage-hl-card { border: 1px solid var(--crisp-border-subtle); border-radius: var(--crisp-radius-2xl); overflow: hidden; }
|
|
2236
|
-
/* gap-as-gridlines: a 1px gap over the border colour draws dividers at any
|
|
2237
|
-
column count, so the grid stays responsive (auto-fit) without per-cell
|
|
2238
|
-
nth-child border hacks that break when the column count changes. */
|
|
2262
|
+
/* gap-as-gridlines: a 1px gap over the border colour draws dividers at any column count, so the grid stays responsive (auto-fit) without per-cell nth-child border hacks that break when the column count changes. */
|
|
2239
2263
|
& .crisp-recordpage-hl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--crisp-border-subtle); }
|
|
2240
2264
|
& .crisp-recordpage-hl-cell { position: relative; min-height: 84px; padding: var(--crisp-space-2-5) var(--crisp-space-3); background: var(--crisp-bg-surface); }
|
|
2241
2265
|
& .crisp-recordpage-hl-icon { position: absolute; top: var(--crisp-space-2-5); inset-inline-end: var(--crisp-space-3); color: var(--crisp-fg-muted); }
|
|
2242
2266
|
& .crisp-recordpage-hl-label { font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: color-mix(in srgb, var(--crisp-fg-primary) 63%, transparent); margin-bottom: var(--crisp-space-2-5); padding-inline-end: var(--crisp-space-4); }
|
|
2243
2267
|
& .crisp-recordpage-hl-value { display: flex; flex-wrap: wrap; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-lg); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
2244
2268
|
& .crisp-recordpage-hl-value--empty { color: var(--crisp-fg-muted); font-weight: var(--crisp-weight-regular); }
|
|
2245
|
-
|
|
2246
2269
|
& .crisp-recordpage-feed { display: flex; flex-direction: column; }
|
|
2247
2270
|
& .crisp-recordpage-feed-item { display: flex; align-items: flex-start; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2) 0; }
|
|
2248
2271
|
& .crisp-recordpage-feed-dot { position: relative; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex-shrink: 0; border-radius: var(--crisp-radius-full); background: var(--crisp-bg-raised); color: var(--crisp-fg-muted); }
|
|
@@ -2251,7 +2274,6 @@
|
|
|
2251
2274
|
& .crisp-recordpage-feed-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); margin-top: 2px; }
|
|
2252
2275
|
& .crisp-recordpage-feed-more { align-self: flex-start; margin-top: var(--crisp-space-1); border: none; background: none; padding: var(--crisp-space-1) 0; color: var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
|
|
2253
2276
|
& .crisp-recordpage-feed-more:hover { text-decoration: underline; }
|
|
2254
|
-
|
|
2255
2277
|
& .crisp-recordpage-section-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-1); }
|
|
2256
2278
|
& .crisp-recordpage-section-head .crisp-recordpage-section-title { padding: 0; }
|
|
2257
2279
|
& .crisp-recordpage-section-count { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-sm); background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); font-size: var(--crisp-text-xs); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
@@ -2259,7 +2281,6 @@
|
|
|
2259
2281
|
& .crisp-recordpage-addbtn { display: inline-flex; align-items: center; gap: var(--crisp-space-1); height: 26px; padding: 0 var(--crisp-space-1-5); margin: 0; border: none; border-radius: var(--crisp-radius-md); background: var(--crisp-bg-surface); 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); color: var(--crisp-fg-primary); font-family: inherit; font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); cursor: pointer; }
|
|
2260
2282
|
& .crisp-recordpage-addbtn:hover { background: var(--crisp-bg-raised); }
|
|
2261
2283
|
& .crisp-recordpage-addbtn svg { flex-shrink: 0; }
|
|
2262
|
-
|
|
2263
2284
|
& .crisp-recordpage-composer { display: flex; flex-direction: column; gap: var(--crisp-space-2); padding: var(--crisp-space-2); border: 1px solid var(--crisp-border-default); border-radius: var(--crisp-radius-xl); background: var(--crisp-bg-surface); margin-bottom: var(--crisp-space-2); }
|
|
2264
2285
|
& .crisp-recordpage-composer textarea { width: 100%; min-height: 56px; resize: vertical; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
2265
2286
|
& .crisp-recordpage-composer textarea:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); border-radius: var(--crisp-radius-md); }
|
|
@@ -2269,23 +2290,18 @@
|
|
|
2269
2290
|
& .crisp-recordpage-btn:hover { background: var(--crisp-bg-raised); }
|
|
2270
2291
|
& .crisp-recordpage-btn--primary { box-shadow: none; background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); }
|
|
2271
2292
|
& .crisp-recordpage-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
2272
|
-
|
|
2273
2293
|
& .crisp-recordpage-note { display: flex; gap: var(--crisp-space-2-5); padding: var(--crisp-space-2-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
|
|
2274
2294
|
& .crisp-recordpage-note-body { flex: 1; min-width: 0; }
|
|
2275
2295
|
& .crisp-recordpage-note-head { display: flex; align-items: center; gap: var(--crisp-space-1-5); margin-bottom: var(--crisp-space-0-5); }
|
|
2276
2296
|
& .crisp-recordpage-note-author { font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-primary); }
|
|
2277
2297
|
& .crisp-recordpage-note-time { font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); }
|
|
2278
2298
|
& .crisp-recordpage-note-text { font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); white-space: pre-wrap; word-break: break-word; }
|
|
2279
|
-
|
|
2280
2299
|
& .crisp-recordpage-task { display: flex; align-items: flex-start; gap: var(--crisp-space-2); padding: var(--crisp-space-1-5) 0; border-top: 1px solid var(--crisp-border-subtle); }
|
|
2281
2300
|
& .crisp-recordpage-task-text { flex: 1; min-width: 0; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); padding-top: 1px; }
|
|
2282
2301
|
& .crisp-recordpage-task[data-done] .crisp-recordpage-task-text { text-decoration: line-through; color: var(--crisp-fg-muted); }
|
|
2283
|
-
|
|
2284
2302
|
& .crisp-recordpage-emptycard { display: flex; flex-direction: column; align-items: center; gap: var(--crisp-space-1-5); padding: var(--crisp-space-6) var(--crisp-space-3); border: 1px dashed var(--crisp-border-default); border-radius: var(--crisp-radius-xl); color: var(--crisp-fg-muted); font-size: var(--crisp-text-md); text-align: center; }
|
|
2285
2303
|
& .crisp-recordpage-emptycard svg { color: var(--crisp-fg-muted); opacity: 0.7; }
|
|
2286
|
-
|
|
2287
2304
|
& .crisp-recordpage-action[data-active] svg { color: #f5b83d; fill: #f5b83d; }
|
|
2288
|
-
|
|
2289
2305
|
& .crisp-recordstable-tag { display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding: 0 var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap; background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); }
|
|
2290
2306
|
& .crisp-recordstable-tag[data-tone="brand"] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); }
|
|
2291
2307
|
& .crisp-recordstable-tag[data-tone="success"] { background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.crisp-textlink {
|
|
2
|
+
display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
|
|
3
|
+
&:hover { text-decoration: underline; }
|
|
4
|
+
}
|
|
5
|
+
.crisp-textlink--tone_brand {
|
|
6
|
+
font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
|
|
7
|
+
}
|
|
8
|
+
.crisp-textlink--tone_muted {
|
|
9
|
+
font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
|
|
10
|
+
&:hover { color: var(--crisp-bg-brand-solid); }
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@layer crisp-components {
|
|
2
|
+
.crisp-textlink {
|
|
3
|
+
display: inline; font-family: var(--crisp-font-sans); text-decoration: none; cursor: pointer;
|
|
4
|
+
&:hover { text-decoration: underline; }
|
|
5
|
+
}
|
|
6
|
+
.crisp-textlink--tone_brand {
|
|
7
|
+
font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
|
|
8
|
+
}
|
|
9
|
+
.crisp-textlink--tone_muted {
|
|
10
|
+
font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
|
|
11
|
+
&:hover { color: var(--crisp-bg-brand-solid); }
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -25,7 +25,7 @@ export type BulkBarProps = Omit<React.ComponentPropsWithoutRef<"div">, "children
|
|
|
25
25
|
* positioned ancestor when a selection is active; render it conditionally
|
|
26
26
|
* (e.g. `count > 0 && <BulkBar …/>`). Measured from a records table.
|
|
27
27
|
*/
|
|
28
|
-
export declare function BulkBar({ count, onClear, countLabel, countText, children, className, clearLabel, ...rest }: BulkBarProps): React.JSX.Element;
|
|
28
|
+
export declare function BulkBar({ count, onClear, countLabel: countLabelProp, countText, children, className, clearLabel: clearLabelProp, ...rest }: BulkBarProps): React.JSX.Element;
|
|
29
29
|
export declare namespace BulkBar {
|
|
30
30
|
var displayName: string;
|
|
31
31
|
}
|
|
@@ -45,7 +45,7 @@ export type HeatmapChartProps = Omit<React.ComponentPropsWithoutRef<"div">, "chi
|
|
|
45
45
|
* the recipe's own doc comment for why (and for its measurement — or lack
|
|
46
46
|
* of one — against Attio).
|
|
47
47
|
*/
|
|
48
|
-
export declare function HeatmapChart({ data, rowAxis, colAxis, format, cellTitle, onCellClick, isCellClickable, empty, emptyLabel, "aria-label": ariaLabel, className, ...rest }: HeatmapChartProps): React.JSX.Element;
|
|
48
|
+
export declare function HeatmapChart({ data, rowAxis, colAxis, format, cellTitle, onCellClick, isCellClickable, empty, emptyLabel: emptyLabelProp, "aria-label": ariaLabel, className, ...rest }: HeatmapChartProps): React.JSX.Element;
|
|
49
49
|
export declare namespace HeatmapChart {
|
|
50
50
|
var displayName: string;
|
|
51
51
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./skiplink";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export type SkipLinkProps = Omit<React.ComponentPropsWithoutRef<"a">, "href"> & {
|
|
3
|
+
/** The target to jump to. Default `"#main-content"` — give the page's
|
|
4
|
+
* main landmark that id. */
|
|
5
|
+
href?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A "skip to content" link — invisible until it is the thing with focus
|
|
10
|
+
* (a sighted mouse user never sees it), so a keyboard user's first Tab from
|
|
11
|
+
* a cold load reaches it instead of walking the whole nav first. Render it
|
|
12
|
+
* as the very first thing on the page, before the sidebar/header. See the
|
|
13
|
+
* recipe's own doc comment for why there's no Attio value behind its chrome.
|
|
14
|
+
*/
|
|
15
|
+
export declare function SkipLink({ href, children, className, ...rest }: SkipLinkProps): React.JSX.Element;
|
|
16
|
+
export declare namespace SkipLink {
|
|
17
|
+
var displayName: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export type TextLinkProps = React.ComponentPropsWithoutRef<"a"> & {
|
|
3
|
+
/** `"brand"` — bold, always brand-coloured (a card's trailing "View all →").
|
|
4
|
+
* `"muted"` (default) — quiet until hover, then brand-coloured (an
|
|
5
|
+
* in-context reference link, e.g. a sample record under a finding). */
|
|
6
|
+
tone?: "brand" | "muted";
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Inline navigable text — a real `<a href>` always, the same href+onClick
|
|
11
|
+
* division `StatList` uses: `href` gives ordinary browser behaviour (new
|
|
12
|
+
* tab, copy link, hover status), an `onClick` that calls
|
|
13
|
+
* `event.preventDefault()` pairs it with client-side routing (e.g.
|
|
14
|
+
* react-router's own `Link`).
|
|
15
|
+
*/
|
|
16
|
+
export declare function TextLink({ tone, className, ...rest }: TextLinkProps): React.JSX.Element;
|
|
17
|
+
export declare namespace TextLink {
|
|
18
|
+
var displayName: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const config: import("../..").RecipeConfig<{
|
|
2
|
+
tone: {
|
|
3
|
+
brand: string;
|
|
4
|
+
muted: string;
|
|
5
|
+
};
|
|
6
|
+
}>;
|
|
7
|
+
export declare const textlinkRecipe: import("../..").RecipeFn<{
|
|
8
|
+
tone: {
|
|
9
|
+
brand: string;
|
|
10
|
+
muted: string;
|
|
11
|
+
};
|
|
12
|
+
}>;
|
|
13
|
+
export default config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./visuallyhidden";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export type VisuallyHiddenProps = React.ComponentPropsWithoutRef<"span"> & {
|
|
3
|
+
className?: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Hides content visually while keeping it in the accessibility tree and
|
|
7
|
+
* the tab order — a label for an icon-only control, extra context for a
|
|
8
|
+
* screen-reader user that a sighted one gets from layout alone. Renders a
|
|
9
|
+
* `<span>`; wrap the element that needs the treatment, or read its content
|
|
10
|
+
* as a `label`/`aria-label` source in a test.
|
|
11
|
+
*/
|
|
12
|
+
export declare function VisuallyHidden({ className, ...rest }: VisuallyHiddenProps): React.JSX.Element;
|
|
13
|
+
export declare namespace VisuallyHidden {
|
|
14
|
+
var displayName: string;
|
|
15
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export * from "./components/resizablepanel";
|
|
|
40
40
|
export * from "./components/segmented";
|
|
41
41
|
export * from "./components/select";
|
|
42
42
|
export * from "./components/skeleton";
|
|
43
|
+
export * from "./components/skiplink";
|
|
43
44
|
export * from "./components/slider";
|
|
44
45
|
export * from "./components/spinner";
|
|
45
46
|
export * from "./components/stagebar";
|
|
@@ -49,9 +50,11 @@ export * from "./components/table";
|
|
|
49
50
|
export * from "./components/tabletoolbar";
|
|
50
51
|
export * from "./components/tabs";
|
|
51
52
|
export * from "./components/textarea";
|
|
53
|
+
export * from "./components/textlink";
|
|
52
54
|
export * from "./components/timepicker";
|
|
53
55
|
export * from "./components/toast";
|
|
54
56
|
export * from "./components/tooltip";
|
|
57
|
+
export * from "./components/visuallyhidden";
|
|
55
58
|
export * from "./components/wheelpicker";
|
|
56
59
|
export * from "./core";
|
|
57
60
|
export * from "./product/appshell";
|
|
@@ -60,6 +63,7 @@ export * from "./product/board";
|
|
|
60
63
|
export * from "./product/command";
|
|
61
64
|
export * from "./product/entitycard";
|
|
62
65
|
export * from "./product/flowcanvas";
|
|
66
|
+
export * from "./product/headerbar";
|
|
63
67
|
export * from "./product/inbox";
|
|
64
68
|
export * from "./product/listpage";
|
|
65
69
|
export * from "./product/navitem";
|
|
@@ -34,7 +34,7 @@ export type BoardProps<T extends BoardCard> = Omit<React.ComponentPropsWithoutRe
|
|
|
34
34
|
* (the parent owns the cards, so the move is a controlled state update).
|
|
35
35
|
* Measured from a deals pipeline.
|
|
36
36
|
*/
|
|
37
|
-
export declare function Board<T extends BoardCard>({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLabel, getCardLabel, announceMove, className, ...rest }: BoardProps<T>): React.JSX.Element;
|
|
37
|
+
export declare function Board<T extends BoardCard>({ columns, cards, onCardsChange, renderCard, onNewCard, newCardLabel: newCardLabelProp, getCardLabel, announceMove: announceMoveProp, className, ...rest }: BoardProps<T>): React.JSX.Element;
|
|
38
38
|
export declare namespace Board {
|
|
39
39
|
var displayName: string;
|
|
40
40
|
}
|
|
@@ -54,4 +54,4 @@ export type CommandProps = Omit<React.ComponentPropsWithoutRef<"div">, "children
|
|
|
54
54
|
* option list) so keyboard/focus correctness comes from the machines, not
|
|
55
55
|
* hand-rolled event handling.
|
|
56
56
|
*/
|
|
57
|
-
export declare function Command({ open, onOpenChange, items, placeholder, "aria-label":
|
|
57
|
+
export declare function Command({ open, onOpenChange, items, placeholder: placeholderProp, "aria-label": ariaLabelProp, navigateLabel: navigateLabelProp, selectLabel: selectLabelProp, emptyLabel: emptyLabelProp, query: queryProp, onQueryChange, filterItems, className, "aria-describedby": describedBy, ...rest }: CommandProps): React.JSX.Element | null;
|
|
@@ -34,7 +34,7 @@ export type FlowCanvasProps<T extends FlowNode> = Omit<React.ComponentPropsWitho
|
|
|
34
34
|
* measured from a workflows editor. Drag a node to move it (fires
|
|
35
35
|
* `onNodesChange`); drag the background to pan; use the toolbar to zoom.
|
|
36
36
|
*/
|
|
37
|
-
export declare function FlowCanvas<T extends FlowNode>({ nodes, edges, onNodesChange, renderNode, nodeWidth, nodeHeight, "aria-label":
|
|
37
|
+
export declare function FlowCanvas<T extends FlowNode>({ nodes, edges, onNodesChange, renderNode, nodeWidth, nodeHeight, "aria-label": ariaLabelProp, className, zoomOutLabel: zoomOutLabelProp, zoomInLabel: zoomInLabelProp, resetLabel: resetLabelProp, edgesLabel: edgesLabelProp, ...rest }: FlowCanvasProps<T>): React.JSX.Element;
|
|
38
38
|
export declare namespace FlowCanvas {
|
|
39
39
|
var displayName: string;
|
|
40
40
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export type HeaderBarProps = Omit<React.ComponentPropsWithoutRef<"div">, "title"> & {
|
|
3
|
+
/** Content before the title — a back button, an icon. Optional. */
|
|
4
|
+
leading?: React.ReactNode;
|
|
5
|
+
/** The bar's main content — plain text, or a `Breadcrumb`. Optional. */
|
|
6
|
+
title?: React.ReactNode;
|
|
7
|
+
/** Trailing action cluster — icon buttons, a search trigger. Optional. */
|
|
8
|
+
trailing?: React.ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Draws the measured bottom divider. Default `true`. Set `false` when
|
|
11
|
+
* stacking two bars (a page header over a view bar) so only the outer one
|
|
12
|
+
* carries it — matches Attio's own two-bar pages, where only the top bar
|
|
13
|
+
* has a border and the one directly under it does not.
|
|
14
|
+
*/
|
|
15
|
+
bordered?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* A page-level header row: an optional leading slot, a flexible title/
|
|
20
|
+
* breadcrumb region, and a trailing action cluster, on the measured 48px
|
|
21
|
+
* bar Attio uses for both its page-header and its view-bar row. See the
|
|
22
|
+
* recipe's own doc comment for the live measurement (crisp#462).
|
|
23
|
+
*/
|
|
24
|
+
export declare function HeaderBar({ leading, title, trailing, bordered, className, ...rest }: HeaderBarProps): React.JSX.Element;
|
|
25
|
+
export declare namespace HeaderBar {
|
|
26
|
+
var displayName: string;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./headerbar";
|
|
@@ -38,7 +38,7 @@ export type InboxProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"
|
|
|
38
38
|
* (avatar + message + time + unread dot) or a centred empty state. Put it inside
|
|
39
39
|
* a Popover for the flyout.
|
|
40
40
|
*/
|
|
41
|
-
export declare function Inbox({ notifications, title, tabs, activeTab, onTabChange, emptyTitle, emptySubtitle, emptyAction, tabsLabel, className, ...rest }: InboxProps): React.JSX.Element;
|
|
41
|
+
export declare function Inbox({ notifications, title: titleProp, tabs, activeTab, onTabChange, emptyTitle: emptyTitleProp, emptySubtitle: emptySubtitleProp, emptyAction, tabsLabel: tabsLabelProp, className, ...rest }: InboxProps): React.JSX.Element;
|
|
42
42
|
export declare namespace Inbox {
|
|
43
43
|
var displayName: string;
|
|
44
44
|
}
|
|
@@ -52,7 +52,7 @@ export declare const onboardingLabels: {
|
|
|
52
52
|
* started" widget. Title + optional menu/minimize, a segmented progress bar,
|
|
53
53
|
* and step rows (completed rows strike through with a brand check).
|
|
54
54
|
*/
|
|
55
|
-
export declare function OnboardingChecklist({ title, steps, encouragement, onStepClick, onMenu, onMinimize, className, optionsLabel, minimizeLabel, progressLabel, progressText, completedStepLabel, ...rest }: OnboardingChecklistProps): React.JSX.Element;
|
|
55
|
+
export declare function OnboardingChecklist({ title: titleProp, steps, encouragement: encouragementProp, onStepClick, onMenu, onMinimize, className, optionsLabel: optionsLabelProp, minimizeLabel: minimizeLabelProp, progressLabel: progressLabelProp, progressText: progressTextProp, completedStepLabel: completedStepLabelProp, ...rest }: OnboardingChecklistProps): React.JSX.Element;
|
|
56
56
|
export declare namespace OnboardingChecklist {
|
|
57
57
|
var displayName: string;
|
|
58
58
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { RecordPage, type RecordPageLabels, type RecordPageLabelsInput, type RecordPageProps, recordPageLabels, } from "./recordpage";
|
|
1
|
+
export { RecordDetails, type RecordDetailsProps, RecordPage, type RecordPageHighlight, type RecordPageLabels, type RecordPageLabelsInput, type RecordPageNote, type RecordPageProps, type RecordPageSection, type RecordPageTab, type RecordPageTask, recordPageLabels, } from "./recordpage";
|
|
2
2
|
export { recordpageRecipe } from "./recordpage.recipe";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LucideIcon } from "lucide-react";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import { type Column, type Row } from "../recordstable";
|
|
3
4
|
export type RecordPageNote = {
|
|
@@ -23,6 +24,39 @@ export type RecordPageTab = {
|
|
|
23
24
|
count?: number;
|
|
24
25
|
render: () => React.ReactNode;
|
|
25
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* One heading in the Details column, grouping a subset of `columns` by key
|
|
29
|
+
* (#528). Attio's own Details column is flat (measured live — no section
|
|
30
|
+
* headings at all), so a caller with no grouping of its own just omits
|
|
31
|
+
* `sections` and keeps that flat list, "View all values" reveal included.
|
|
32
|
+
* A caller that supplies `sections` replaces the flat list WHOLESALE — the
|
|
33
|
+
* same "caller's list replaces the built-in one, never merges with it"
|
|
34
|
+
* choice `tabs` already makes (#379) — so a column key named by no
|
|
35
|
+
* `fields` array here simply doesn't render. Sectioned mode always shows
|
|
36
|
+
* every field in every section (no 5-field reveal/"View all values"): a
|
|
37
|
+
* caller reaching for `sections` at all (GRC's own field groups; Attio has
|
|
38
|
+
* none to match) has already opted out of the flat Attio shape that reveal
|
|
39
|
+
* exists for.
|
|
40
|
+
*/
|
|
41
|
+
export type RecordPageSection = {
|
|
42
|
+
/** Section heading; omit for an untitled group (no heading rendered). */
|
|
43
|
+
title?: React.ReactNode;
|
|
44
|
+
/** Field keys in this section, in the order shown. */
|
|
45
|
+
fields: string[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* One Overview Highlights card — same shape `RecordPanel`'s own
|
|
49
|
+
* `RecordPanelHighlight` uses (#448), plus the empty-state node the CRM
|
|
50
|
+
* default already needed: `RecordPanel`'s peek never shows an empty
|
|
51
|
+
* highlight card, but `RecordPage`'s Overview always has (Attio's own
|
|
52
|
+
* "No connection", "No team", measured live), so that stays here.
|
|
53
|
+
*/
|
|
54
|
+
export type RecordPageHighlight = {
|
|
55
|
+
label: string;
|
|
56
|
+
icon?: LucideIcon;
|
|
57
|
+
value: React.ReactNode | null;
|
|
58
|
+
empty?: React.ReactNode;
|
|
59
|
+
};
|
|
26
60
|
export type RecordPageProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"> & {
|
|
27
61
|
record: Row;
|
|
28
62
|
columns: Column[];
|
|
@@ -70,6 +104,22 @@ export type RecordPageProps = Omit<React.ComponentPropsWithoutRef<"div">, "child
|
|
|
70
104
|
tasks?: RecordPageTask[];
|
|
71
105
|
onAddTask?: (text: string) => void;
|
|
72
106
|
onToggleTask?: (id: string) => void;
|
|
107
|
+
/**
|
|
108
|
+
* Groups the Details column's fields under headings instead of Attio's
|
|
109
|
+
* flat list (#528) — see `RecordPageSection`'s own doc. Omit to keep the
|
|
110
|
+
* flat Attio-parity list.
|
|
111
|
+
*/
|
|
112
|
+
sections?: RecordPageSection[];
|
|
113
|
+
/**
|
|
114
|
+
* Replaces the Overview Highlights cards (#528) — Attio's own set is a
|
|
115
|
+
* fixed CRM shape (Connection strength, Estimated ARR, …) that has
|
|
116
|
+
* nothing to do with a non-CRM domain's data, the same problem #379
|
|
117
|
+
* already solved for `tabs`. `false` omits the whole Highlights section
|
|
118
|
+
* (heading included, matching how `RecordPanel`'s own `highlights` omits
|
|
119
|
+
* its section by being left out, #448). Omit the prop entirely to keep
|
|
120
|
+
* the built-in CRM set.
|
|
121
|
+
*/
|
|
122
|
+
highlights?: RecordPageHighlight[] | false;
|
|
73
123
|
};
|
|
74
124
|
/**
|
|
75
125
|
* Every chrome string RecordPage renders. Supplied as a PARTIAL map, so
|
|
@@ -139,6 +189,10 @@ export type RecordPageLabels = {
|
|
|
139
189
|
recordCreated: (name: React.ReactNode) => React.ReactNode;
|
|
140
190
|
/** Empty state on the Emails tab, given the record's name. */
|
|
141
191
|
noEmailsWith: (name: React.ReactNode) => React.ReactNode;
|
|
192
|
+
/** Field search's own empty state, given the typed query — previously a
|
|
193
|
+
* hardcoded English string; #528 moved it here alongside every other
|
|
194
|
+
* chrome string this component renders, so it translates like the rest. */
|
|
195
|
+
noFieldsMatch: (query: React.ReactNode) => React.ReactNode;
|
|
142
196
|
};
|
|
143
197
|
export declare const recordPageLabels: RecordPageLabels;
|
|
144
198
|
/** Partial override of any chrome string; the keyed maps nest. */
|
|
@@ -147,6 +201,41 @@ export type RecordPageLabelsInput = Partial<Omit<RecordPageLabels, "tabs" | "hig
|
|
|
147
201
|
highlightLabels?: Partial<RecordPageLabels["highlightLabels"]>;
|
|
148
202
|
highlightEmpty?: Partial<RecordPageLabels["highlightEmpty"]>;
|
|
149
203
|
};
|
|
204
|
+
export type RecordDetailsProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"> & {
|
|
205
|
+
record: Row;
|
|
206
|
+
columns: Column[];
|
|
207
|
+
/** Groups fields under headings instead of Attio's flat list — see
|
|
208
|
+
* `RecordPageSection`'s own doc. Omit to keep the flat list. */
|
|
209
|
+
sections?: RecordPageSection[];
|
|
210
|
+
onEdit?: (id: string, key: string, value: string) => Promise<void> | void;
|
|
211
|
+
labels?: RecordPageLabelsInput;
|
|
212
|
+
className?: string;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* The Details column's own field list, on its own (#528) — `RecordPage`'s
|
|
216
|
+
* "Record Details" collapsible + searchable field list, the one piece a
|
|
217
|
+
* consumer with a fixed-width rail of its own (no resize handle, no entity
|
|
218
|
+
* header, no CRM Lists panel — GRC's own persistent 320px column, grc#66)
|
|
219
|
+
* actually needs, rather than rebuilding this same click-to-edit/search/
|
|
220
|
+
* `sections` machinery by hand or pulling in the whole page's chrome for a
|
|
221
|
+
* rail that isn't one. `RecordPage` composes this internally for its own
|
|
222
|
+
* resizable aside (same component either way, not a second copy) — this is
|
|
223
|
+
* that same block, exactly, just not wrapped in `RecordPage`'s own topbar/
|
|
224
|
+
* tabs/resizer.
|
|
225
|
+
*
|
|
226
|
+
* Not wrapped in `recordpageRecipe` itself: doing so would duplicate the
|
|
227
|
+
* recipe's own `display:flex;height:100%` base rule as a nested child
|
|
228
|
+
* inside `RecordPage`'s aside (which already carries that class from
|
|
229
|
+
* `RecordPage`'s own root), breaking that layout. A standalone caller
|
|
230
|
+
* needs exactly one `.crisp-recordpage`-scoped ancestor for this
|
|
231
|
+
* component's classes to resolve — wrap it in one, the same way
|
|
232
|
+
* `RecordPage`'s own root does: `<div className={recordpageRecipe()}>`
|
|
233
|
+
* (also exported from this package).
|
|
234
|
+
*/
|
|
235
|
+
export declare function RecordDetails({ record, columns, sections, onEdit, labels, className, ...rest }: RecordDetailsProps): React.JSX.Element;
|
|
236
|
+
export declare namespace RecordDetails {
|
|
237
|
+
var displayName: string;
|
|
238
|
+
}
|
|
150
239
|
/**
|
|
151
240
|
* The full-page company record view — the page that opens when you click into a
|
|
152
241
|
* record (as opposed to the peek [RecordPanel]). A top breadcrumb bar with
|
|
@@ -155,7 +244,7 @@ export type RecordPageLabelsInput = Partial<Omit<RecordPageLabels, "tabs" | "hig
|
|
|
155
244
|
* Emails sections (Notes & Tasks are live — add and check things off). Drop it
|
|
156
245
|
* into the app's main content area.
|
|
157
246
|
*/
|
|
158
|
-
export declare function RecordPage({ record, columns, collection, labels, onBack, onToggleFull, full, className, onEdit, tabs: tabsProp, defaultTab, notes: notesProp, onAddNote, tasks: tasksProp, onAddTask, onToggleTask, ...rest }: RecordPageProps): React.JSX.Element;
|
|
247
|
+
export declare function RecordPage({ record, columns, collection, labels, onBack, onToggleFull, full, className, onEdit, tabs: tabsProp, defaultTab, notes: notesProp, onAddNote, tasks: tasksProp, onAddTask, onToggleTask, sections, highlights: highlightsProp, ...rest }: RecordPageProps): React.JSX.Element;
|
|
159
248
|
export declare namespace RecordPage {
|
|
160
249
|
var displayName: string;
|
|
161
250
|
}
|
|
@@ -34,7 +34,7 @@ export type TaskListProps = Omit<React.ComponentPropsWithoutRef<"div">, "childre
|
|
|
34
34
|
* count, then rows of a round complete-checkbox + title + trailing meta.
|
|
35
35
|
* Completed rows strike through; overdue dates go red.
|
|
36
36
|
*/
|
|
37
|
-
export declare function TaskList({ tasks, groups, onToggle, emptyLabel, className, completeLabel, incompleteLabel, ...rest }: TaskListProps): React.JSX.Element;
|
|
37
|
+
export declare function TaskList({ tasks, groups, onToggle, emptyLabel: emptyLabelProp, className, completeLabel: completeLabelProp, incompleteLabel: incompleteLabelProp, ...rest }: TaskListProps): React.JSX.Element;
|
|
38
38
|
export declare namespace TaskList {
|
|
39
39
|
var displayName: string;
|
|
40
40
|
}
|