@crisp-ui-kit/crisp 0.54.0 → 0.54.2
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/activityfeed.css +12 -0
- package/dist/activityfeed.d.ts +7 -0
- package/dist/activityfeed.layered.css +14 -0
- package/dist/badge.css +3 -0
- package/dist/badge.d.ts +2 -2
- package/dist/badge.layered.css +3 -0
- package/dist/cjs/components/badge/badge.recipe.js +10 -0
- package/dist/cjs/components/datatable/datatable.js +2 -1
- package/dist/cjs/components/datatable/datatable.recipe.js +4 -0
- package/dist/cjs/components/mentionchip/index.js +7 -0
- package/dist/cjs/components/mentionchip/mentionchip.js +57 -0
- package/dist/cjs/components/mentionchip/mentionchip.recipe.js +38 -0
- package/dist/cjs/components/table/table.recipe.js +15 -3
- package/dist/cjs/core/floating-stack.js +18 -0
- package/dist/cjs/core/index.js +2 -1
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/product/activityfeed/activityfeed.js +38 -0
- package/dist/cjs/product/activityfeed/activityfeed.recipe.js +35 -0
- package/dist/cjs/product/activityfeed/index.js +10 -0
- package/dist/cjs/product/formdialog/formdialog.js +171 -0
- package/dist/cjs/product/formdialog/formdialog.recipe.js +26 -0
- package/dist/cjs/product/formdialog/index.js +8 -0
- package/dist/cjs/product/importdialog/importdialog.js +134 -0
- package/dist/cjs/product/importdialog/importdialog.recipe.js +92 -0
- package/dist/cjs/product/importdialog/index.js +18 -0
- package/dist/cjs/product/richtext/richtext.js +43 -0
- package/dist/cjs/product/savedviews/index.js +7 -0
- package/dist/cjs/product/savedviews/savedviews.js +207 -0
- package/dist/cjs/product/savedviews/savedviews.recipe.js +103 -0
- package/dist/cjs/product/taskstable/index.js +7 -0
- package/dist/cjs/product/taskstable/taskstable.js +27 -0
- package/dist/cjs/product/taskstable/taskstable.recipe.js +47 -0
- package/dist/cjs/product/themepicker/index.js +17 -0
- package/dist/cjs/product/themepicker/themepicker.js +32 -0
- package/dist/cjs/product/themepicker/themepicker.recipe.js +98 -0
- package/dist/cjs/tokens/palette.js +31 -0
- package/dist/cjs/tokens/semantic.js +11 -0
- package/dist/datatable.css +20 -21
- package/dist/datatable.layered.css +20 -21
- package/dist/esm/components/badge/badge.recipe.js +10 -0
- package/dist/esm/components/datatable/datatable.js +2 -1
- package/dist/esm/components/datatable/datatable.recipe.js +4 -0
- package/dist/esm/components/mentionchip/index.js +2 -0
- package/dist/esm/components/mentionchip/mentionchip.js +21 -0
- package/dist/esm/components/mentionchip/mentionchip.recipe.js +35 -0
- package/dist/esm/components/table/table.recipe.js +15 -3
- package/dist/esm/core/floating-stack.js +17 -0
- package/dist/esm/core/index.js +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/product/activityfeed/activityfeed.js +32 -0
- package/dist/esm/product/activityfeed/activityfeed.recipe.js +32 -0
- package/dist/esm/product/activityfeed/index.js +2 -0
- package/dist/esm/product/formdialog/formdialog.js +134 -0
- package/dist/esm/product/formdialog/formdialog.recipe.js +23 -0
- package/dist/esm/product/formdialog/index.js +2 -0
- package/dist/esm/product/importdialog/importdialog.js +97 -0
- package/dist/esm/product/importdialog/importdialog.recipe.js +89 -0
- package/dist/esm/product/importdialog/index.js +2 -0
- package/dist/esm/product/richtext/richtext.js +43 -0
- package/dist/esm/product/savedviews/index.js +2 -0
- package/dist/esm/product/savedviews/savedviews.js +171 -0
- package/dist/esm/product/savedviews/savedviews.recipe.js +100 -0
- package/dist/esm/product/taskstable/index.js +2 -0
- package/dist/esm/product/taskstable/taskstable.js +24 -0
- package/dist/esm/product/taskstable/taskstable.recipe.js +44 -0
- package/dist/esm/product/themepicker/index.js +1 -0
- package/dist/esm/product/themepicker/themepicker.js +29 -0
- package/dist/esm/product/themepicker/themepicker.recipe.js +95 -0
- package/dist/esm/tokens/palette.js +31 -0
- package/dist/esm/tokens/semantic.js +11 -0
- package/dist/formdialog.css +6 -0
- package/dist/formdialog.d.ts +7 -0
- package/dist/formdialog.layered.css +8 -0
- package/dist/importdialog.css +38 -0
- package/dist/importdialog.d.ts +7 -0
- package/dist/importdialog.layered.css +40 -0
- package/dist/mentionchip.css +3 -0
- package/dist/mentionchip.d.ts +7 -0
- package/dist/mentionchip.layered.css +5 -0
- package/dist/native/tokens.d.ts +1 -1
- package/dist/native/tokens.js +24 -4
- package/dist/savedviews.css +78 -0
- package/dist/savedviews.d.ts +7 -0
- package/dist/savedviews.layered.css +80 -0
- package/dist/styles.css +242 -27
- package/dist/styles.layered.css +242 -27
- package/dist/table.css +15 -6
- package/dist/table.layered.css +15 -6
- package/dist/taskstable.css +23 -0
- package/dist/taskstable.d.ts +7 -0
- package/dist/taskstable.layered.css +25 -0
- package/dist/themepicker.css +27 -0
- package/dist/themepicker.d.ts +7 -0
- package/dist/themepicker.layered.css +29 -0
- package/dist/tokens.css +10 -0
- package/dist/tokens.json +24 -4
- package/dist/types/components/badge/badge.d.ts +2 -0
- package/dist/types/components/badge/badge.recipe.d.ts +8 -0
- package/dist/types/components/datatable/datatable.d.ts +12 -1
- package/dist/types/components/mentionchip/index.d.ts +2 -0
- package/dist/types/components/mentionchip/mentionchip.d.ts +20 -0
- package/dist/types/components/mentionchip/mentionchip.recipe.d.ts +18 -0
- package/dist/types/core/floating-stack.d.ts +14 -0
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/product/activityfeed/activityfeed.d.ts +57 -0
- package/dist/types/product/activityfeed/activityfeed.recipe.d.ts +3 -0
- package/dist/types/product/activityfeed/index.d.ts +2 -0
- package/dist/types/product/formdialog/formdialog.d.ts +57 -0
- package/dist/types/product/formdialog/formdialog.recipe.d.ts +3 -0
- package/dist/types/product/formdialog/index.d.ts +2 -0
- package/dist/types/product/importdialog/importdialog.d.ts +86 -0
- package/dist/types/product/importdialog/importdialog.recipe.d.ts +3 -0
- package/dist/types/product/importdialog/index.d.ts +2 -0
- package/dist/types/product/savedviews/index.d.ts +2 -0
- package/dist/types/product/savedviews/savedviews.d.ts +55 -0
- package/dist/types/product/savedviews/savedviews.recipe.d.ts +3 -0
- package/dist/types/product/taskstable/index.d.ts +2 -0
- package/dist/types/product/taskstable/taskstable.d.ts +54 -0
- package/dist/types/product/taskstable/taskstable.recipe.d.ts +3 -0
- package/dist/types/product/themepicker/index.d.ts +1 -0
- package/dist/types/product/themepicker/themepicker.d.ts +21 -0
- package/dist/types/product/themepicker/themepicker.recipe.d.ts +3 -0
- package/dist/types/tokens/contract.d.ts +5 -0
- package/dist/types/tokens/palette.d.ts +20 -0
- package/dist/types/tokens/semantic.d.ts +11 -0
- package/package.json +36 -1
|
@@ -13,6 +13,8 @@ exports.semantic = {
|
|
|
13
13
|
bgRaised: "gray50",
|
|
14
14
|
borderDefault: "line200",
|
|
15
15
|
borderSubtle: "line100",
|
|
16
|
+
/** ImportDialog's dashed dropzone border — see palette.ts's `line150`. */
|
|
17
|
+
borderDropzone: "line150",
|
|
16
18
|
ringNeutral: "ringNeutral",
|
|
17
19
|
ringField: "ringField",
|
|
18
20
|
ringSwitch: "ringSwitch",
|
|
@@ -32,6 +34,10 @@ exports.semantic = {
|
|
|
32
34
|
bgDanger: "red600",
|
|
33
35
|
/** Fill for a SOLID destructive control that carries white text. */
|
|
34
36
|
bgDangerSolid: "red700",
|
|
37
|
+
/** Solid critical/destructive TEXT (not a fill) — an overdue due-date, a
|
|
38
|
+
* destructive menu item's label. Distinct from `bgDanger` (a fill colour)
|
|
39
|
+
* and `fgDangerSoft` (a soft badge pill's text, a different measured hex). */
|
|
40
|
+
fgDanger: "red500",
|
|
35
41
|
/** The 2px ring a text field shows while focused. */
|
|
36
42
|
strokeFieldFocus: "fieldFocus",
|
|
37
43
|
/** Unavailable/disabled content: unselected wheel rows, unpickable dates. */
|
|
@@ -63,4 +69,9 @@ exports.semantic = {
|
|
|
63
69
|
fgWarningSoft: "softWarningText",
|
|
64
70
|
fgDangerSoft: "softDangerText",
|
|
65
71
|
fgNeutralSoft: "softNeutralText",
|
|
72
|
+
/** Badge's purple/role-pill tone (crisp#506) — see palette.ts's comment
|
|
73
|
+
* on `purpleTint`/`softPurpleText`/`purpleRing` for the measurement. */
|
|
74
|
+
bgPurpleSoft: "purpleTint",
|
|
75
|
+
fgPurpleSoft: "softPurpleText",
|
|
76
|
+
ringPurpleSoft: "purpleRing",
|
|
66
77
|
};
|
package/dist/datatable.css
CHANGED
|
@@ -46,6 +46,9 @@
|
|
|
46
46
|
/* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
|
|
47
47
|
& th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: var(--crisp-bg-surface); }
|
|
48
48
|
& th[data-sticky] { z-index: 3; }
|
|
49
|
+
/* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
50
|
+
`tfoot td { z-index: 2 }`), which `td[data-sticky]`'s own higher-specificity `z-index: 1` would otherwise undercut -- keep it level with the row it's in. */
|
|
51
|
+
& tfoot td[data-sticky] { z-index: 2; }
|
|
49
52
|
& tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
|
|
50
53
|
& tbody tr:hover td[data-sticky] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
|
|
51
54
|
& .crisp-table-scroll[data-scrolled-x] [data-sticky-edge] { clip-path: inset(0 -38px 0 0); box-shadow: 6px 0 16px 4px rgba(0,0,0,0.12); }
|
|
@@ -63,23 +66,25 @@
|
|
|
63
66
|
& .crisp-datatable-editable:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); cursor: text; }
|
|
64
67
|
& .crisp-datatable-edit { width: 100%; height: 28px; margin: 0; padding: 0 var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; vertical-align: middle; }
|
|
65
68
|
& .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
66
|
-
/* An async onEdit's in-flight state (#385) -- the field/picker dims and
|
|
69
|
+
/* An async onEdit's in-flight state (#385) -- the field/picker dims and
|
|
70
|
+
stops accepting input rather than disappearing, so the just-typed or
|
|
71
|
+
just-chosen value stays visible while its commit is pending. Same
|
|
72
|
+
treatment Input already gives its own disabled state. */
|
|
67
73
|
& .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
68
74
|
& .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
|
|
69
|
-
/* The rejection's message, beside the cell's own content -- a sibling in
|
|
70
|
-
hover-only wrapper (a Tooltip, say) around a custom render can't hide
|
|
71
|
-
|
|
75
|
+
/* The rejection's message, beside the cell's own content -- a sibling in
|
|
76
|
+
the TableCell, never nested inside a column's own render output, so a hover-only wrapper (a Tooltip, say) around a custom render can't hide
|
|
77
|
+
it. Block-level: the row grows to fit it rather than floating over
|
|
78
|
+
the row below, so it can never end up clipped by the scroll
|
|
79
|
+
container's overflow the way a position:fixed escape would need guarding against. */
|
|
72
80
|
& .crisp-datatable-edit-error { display: block; padding: var(--crisp-space-0-5) 0 0; font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
73
|
-
/* editor: "select"/"switch" -- always live, no separate edit mode, so
|
|
74
|
-
|
|
75
|
-
RecordsTable's own --picker cells (measured there already; DataTable shares RecordsTable's grid, Golden Rule 0). */
|
|
81
|
+
/* editor: "select"/"switch" -- always live, no separate edit mode, so the cell IS the picker: same chromeless-fill treatment as RecordsTable's own --picker cells (measured there already; DataTable
|
|
82
|
+
shares RecordsTable's grid, Golden Rule 0). */
|
|
76
83
|
& .crisp-datatable-td--picker { padding: 0; }
|
|
77
84
|
& .crisp-datatable-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
78
85
|
& .crisp-datatable-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; height: 100%; min-height: 0; border-radius: 0; box-shadow: none; padding: 0; }
|
|
79
86
|
& .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
|
|
80
|
-
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
81
|
-
"Create X" row when the consumer supplies one (#449) -- same measured
|
|
82
|
-
values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
87
|
+
/* reference picker: a leading 16px avatar per option, plus a trailing "Create X" row when the consumer supplies one (#449) -- same measured values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
83
88
|
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
84
89
|
& .crisp-datatable-refoption-avatar { flex-shrink: 0; }
|
|
85
90
|
& .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
|
|
@@ -96,12 +101,7 @@
|
|
|
96
101
|
& .crisp-datatable-entity:hover .crisp-datatable-entity-name { text-decoration: underline; }
|
|
97
102
|
& button.crisp-datatable-entity-name--link { margin: 0; padding: 0; border: none; background: none; font: inherit; color: inherit; letter-spacing: inherit; text-align: start; cursor: pointer; max-width: 100%; }
|
|
98
103
|
& .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: var(--crisp-radius-sm); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-brand); background: var(--crisp-bg-brand-solid); }
|
|
99
|
-
& .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); }
|
|
100
|
-
& .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); }
|
|
101
|
-
& .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); }
|
|
102
|
-
& .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); }
|
|
103
|
-
& .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); }
|
|
104
|
-
& .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
|
|
104
|
+
& .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); } & .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); } & .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); } & .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); } & .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); } & .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
|
|
105
105
|
& .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
|
|
106
106
|
& .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
|
|
107
107
|
& .crisp-datatable-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); }
|
|
@@ -114,11 +114,10 @@
|
|
|
114
114
|
& .crisp-datatable-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)); }
|
|
115
115
|
& .crisp-datatable-num { font-variant-numeric: tabular-nums; }
|
|
116
116
|
& .crisp-datatable-muted { color: var(--crisp-fg-muted); }
|
|
117
|
-
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
|
|
118
|
-
hairline doubling as the drop indicator (it tints toward the brand
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
pointer-events implementation. */
|
|
117
|
+
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
|
|
118
|
+
a leading 20px grip column, a 16px grip icon, and the row's own hairline doubling as the drop indicator (it tints toward the brand colour as the active drop target). The affordance + geometry are measured; the drag MECHANISM is crisp's existing house idiom -- HTML5
|
|
119
|
+
draggable + dataTransfer, the same one column reorder already uses
|
|
120
|
+
(RecordsTable's reorderColumn) -- not a proprietary pointer-events implementation. */
|
|
122
121
|
& .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
|
|
123
122
|
& .crisp-datatable-grip { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 0; border: none; border-radius: 0; background: none; font-family: inherit; color: var(--crisp-fg-muted); cursor: grab; }
|
|
124
123
|
& .crisp-datatable-grip:active { cursor: grabbing; }
|
|
@@ -47,6 +47,9 @@
|
|
|
47
47
|
/* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
|
|
48
48
|
& th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: var(--crisp-bg-surface); }
|
|
49
49
|
& th[data-sticky] { z-index: 3; }
|
|
50
|
+
/* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
51
|
+
`tfoot td { z-index: 2 }`), which `td[data-sticky]`'s own higher-specificity `z-index: 1` would otherwise undercut -- keep it level with the row it's in. */
|
|
52
|
+
& tfoot td[data-sticky] { z-index: 2; }
|
|
50
53
|
& tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, var(--crisp-bg-brand-solid) 10%, var(--crisp-bg-surface)); }
|
|
51
54
|
& tbody tr:hover td[data-sticky] { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); }
|
|
52
55
|
& .crisp-table-scroll[data-scrolled-x] [data-sticky-edge] { clip-path: inset(0 -38px 0 0); box-shadow: 6px 0 16px 4px rgba(0,0,0,0.12); }
|
|
@@ -64,23 +67,25 @@
|
|
|
64
67
|
& .crisp-datatable-editable:hover { background: color-mix(in srgb, var(--crisp-fg-primary) 4%, var(--crisp-bg-surface)); cursor: text; }
|
|
65
68
|
& .crisp-datatable-edit { width: 100%; height: 28px; margin: 0; padding: 0 var(--crisp-space-1-5); border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); outline: none; vertical-align: middle; }
|
|
66
69
|
& .crisp-datatable-edit:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
67
|
-
/* An async onEdit's in-flight state (#385) -- the field/picker dims and
|
|
70
|
+
/* An async onEdit's in-flight state (#385) -- the field/picker dims and
|
|
71
|
+
stops accepting input rather than disappearing, so the just-typed or
|
|
72
|
+
just-chosen value stays visible while its commit is pending. Same
|
|
73
|
+
treatment Input already gives its own disabled state. */
|
|
68
74
|
& .crisp-datatable-edit:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
69
75
|
& .crisp-datatable-edit-pending { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); color: var(--crisp-fg-muted); vertical-align: middle; }
|
|
70
|
-
/* The rejection's message, beside the cell's own content -- a sibling in
|
|
71
|
-
hover-only wrapper (a Tooltip, say) around a custom render can't hide
|
|
72
|
-
|
|
76
|
+
/* The rejection's message, beside the cell's own content -- a sibling in
|
|
77
|
+
the TableCell, never nested inside a column's own render output, so a hover-only wrapper (a Tooltip, say) around a custom render can't hide
|
|
78
|
+
it. Block-level: the row grows to fit it rather than floating over
|
|
79
|
+
the row below, so it can never end up clipped by the scroll
|
|
80
|
+
container's overflow the way a position:fixed escape would need guarding against. */
|
|
73
81
|
& .crisp-datatable-edit-error { display: block; padding: var(--crisp-space-0-5) 0 0; font-size: var(--crisp-text-sm); color: var(--crisp-bg-danger); }
|
|
74
|
-
/* editor: "select"/"switch" -- always live, no separate edit mode, so
|
|
75
|
-
|
|
76
|
-
RecordsTable's own --picker cells (measured there already; DataTable shares RecordsTable's grid, Golden Rule 0). */
|
|
82
|
+
/* editor: "select"/"switch" -- always live, no separate edit mode, so the cell IS the picker: same chromeless-fill treatment as RecordsTable's own --picker cells (measured there already; DataTable
|
|
83
|
+
shares RecordsTable's grid, Golden Rule 0). */
|
|
77
84
|
& .crisp-datatable-td--picker { padding: 0; }
|
|
78
85
|
& .crisp-datatable-edit-picker { display: flex; align-items: center; gap: var(--crisp-space-1); height: var(--crisp-size-tableRow); padding: 0 var(--crisp-space-2); }
|
|
79
86
|
& .crisp-datatable-edit-picker .crisp-select-trigger { flex: 1; min-width: 0; height: 100%; min-height: 0; border-radius: 0; box-shadow: none; padding: 0; }
|
|
80
87
|
& .crisp-datatable-td--picker .crisp-datatable-edit-error { padding-inline-start: var(--crisp-space-2); }
|
|
81
|
-
/* reference picker: a leading 16px avatar per option, plus a trailing
|
|
82
|
-
"Create X" row when the consumer supplies one (#449) -- same measured
|
|
83
|
-
values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
88
|
+
/* reference picker: a leading 16px avatar per option, plus a trailing "Create X" row when the consumer supplies one (#449) -- same measured values as RecordsTable's own .crisp-recordstable-refoption*. */
|
|
84
89
|
& .crisp-datatable-refoption { display: flex; align-items: center; gap: var(--crisp-space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
85
90
|
& .crisp-datatable-refoption-avatar { flex-shrink: 0; }
|
|
86
91
|
& .crisp-datatable-refoption--create { color: var(--crisp-fg-muted); }
|
|
@@ -97,12 +102,7 @@
|
|
|
97
102
|
& .crisp-datatable-entity:hover .crisp-datatable-entity-name { text-decoration: underline; }
|
|
98
103
|
& button.crisp-datatable-entity-name--link { margin: 0; padding: 0; border: none; background: none; font: inherit; color: inherit; letter-spacing: inherit; text-align: start; cursor: pointer; max-width: 100%; }
|
|
99
104
|
& .crisp-datatable-avatar { width: var(--crisp-size-icon); height: var(--crisp-size-icon); border-radius: var(--crisp-radius-sm); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: var(--crisp-weight-semibold); text-transform: uppercase; color: var(--crisp-fg-on-brand); background: var(--crisp-bg-brand-solid); }
|
|
100
|
-
& .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); }
|
|
101
|
-
& .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); }
|
|
102
|
-
& .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); }
|
|
103
|
-
& .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); }
|
|
104
|
-
& .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); }
|
|
105
|
-
& .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
|
|
105
|
+
& .crisp-datatable-avatar[data-tone="success"] { background: var(--crisp-bg-success); } & .crisp-datatable-avatar[data-tone="warning"] { background: var(--crisp-bg-warning); } & .crisp-datatable-avatar[data-tone="danger"] { background: var(--crisp-bg-danger); } & .crisp-datatable-avatar[data-tone="purple"] { background: var(--crisp-bg-purple); } & .crisp-datatable-avatar[data-tone="cyan"] { background: var(--crisp-bg-cyan); } & .crisp-datatable-avatar[data-tone="orange"] { background: var(--crisp-bg-orange); }
|
|
106
106
|
& .crisp-datatable-avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
|
|
107
107
|
& .crisp-datatable-tags { display: flex; align-items: center; gap: var(--crisp-space-1); overflow: hidden; }
|
|
108
108
|
& .crisp-datatable-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); }
|
|
@@ -115,11 +115,10 @@
|
|
|
115
115
|
& .crisp-datatable-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)); }
|
|
116
116
|
& .crisp-datatable-num { font-variant-numeric: tabular-nums; }
|
|
117
117
|
& .crisp-datatable-muted { color: var(--crisp-fg-muted); }
|
|
118
|
-
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
|
|
119
|
-
hairline doubling as the drop indicator (it tints toward the brand
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
pointer-events implementation. */
|
|
118
|
+
/* row drag-to-reorder -- a Settings > Objects > Attributes screen measures
|
|
119
|
+
a leading 20px grip column, a 16px grip icon, and the row's own hairline doubling as the drop indicator (it tints toward the brand colour as the active drop target). The affordance + geometry are measured; the drag MECHANISM is crisp's existing house idiom -- HTML5
|
|
120
|
+
draggable + dataTransfer, the same one column reorder already uses
|
|
121
|
+
(RecordsTable's reorderColumn) -- not a proprietary pointer-events implementation. */
|
|
123
122
|
& .crisp-datatable-col-grip { width: 20px; padding: 0; text-align: center; }
|
|
124
123
|
& .crisp-datatable-grip { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 0; border: none; border-radius: 0; background: none; font-family: inherit; color: var(--crisp-fg-muted); cursor: grab; }
|
|
125
124
|
& .crisp-datatable-grip:active { cursor: grabbing; }
|
|
@@ -60,6 +60,16 @@ const spec = defineSpec({
|
|
|
60
60
|
color: c.fgDangerSoft,
|
|
61
61
|
boxShadow: ring(c.bgDanger, 30),
|
|
62
62
|
},
|
|
63
|
+
// crisp#506: a distinct purple used for role-style labels (Attio's own
|
|
64
|
+
// "Admin" role pill), not a status/severity colour -- the other five
|
|
65
|
+
// tones don't cover this hue. Unlike those, these are the measured
|
|
66
|
+
// *solid* values directly (not a color-mix tint of a base accent):
|
|
67
|
+
// Attio's own pill background reads a flat, opaque rgb(), no alpha.
|
|
68
|
+
purple: {
|
|
69
|
+
background: c.bgPurpleSoft,
|
|
70
|
+
color: c.fgPurpleSoft,
|
|
71
|
+
boxShadow: `inset 0 0 0 1px ${c.ringPurpleSoft}`,
|
|
72
|
+
},
|
|
63
73
|
},
|
|
64
74
|
size: {
|
|
65
75
|
small: {
|
|
@@ -301,7 +301,7 @@ function DataReferenceEditor({ col, value, isPending, onCommit, onCancel, }) {
|
|
|
301
301
|
onCommit(v);
|
|
302
302
|
} }) }));
|
|
303
303
|
}
|
|
304
|
-
export function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel: selectAllLabelProp, selectRowLabel = (row) => `Select row ${row.id}`, selectionAnnouncement, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, onEdit, stickyFirst = true, stickyLast = false, locale: localeProp, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel: addRowLabelProp, empty: emptyProp, showCount = true, countLabel, toolbar, className, reorderRowLabel: reorderRowLabelProp, sortAscendingLabel: sortAscendingLabelProp, sortDescendingLabel: sortDescendingLabelProp, moveColumnLeftLabel: moveColumnLeftLabelProp, moveColumnRightLabel: moveColumnRightLabelProp, editColumnLabel: editColumnLabelProp, hideColumnLabel: hideColumnLabelProp, renameColumnLabel: renameColumnLabelProp, viewSettingsLabel: viewSettingsLabelProp, columnsGroupLabel: columnsGroupLabelProp, ...rest }) {
|
|
304
|
+
export function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel: selectAllLabelProp, selectRowLabel = (row) => `Select row ${row.id}`, selectionAnnouncement, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder: searchPlaceholderProp, searchLabel: searchLabelProp, onEdit, stickyFirst = true, stickyLast = false, scrollProps, locale: localeProp, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel: addRowLabelProp, empty: emptyProp, showCount = true, countLabel, toolbar, className, reorderRowLabel: reorderRowLabelProp, sortAscendingLabel: sortAscendingLabelProp, sortDescendingLabel: sortDescendingLabelProp, moveColumnLeftLabel: moveColumnLeftLabelProp, moveColumnRightLabel: moveColumnRightLabelProp, editColumnLabel: editColumnLabelProp, hideColumnLabel: hideColumnLabelProp, renameColumnLabel: renameColumnLabelProp, viewSettingsLabel: viewSettingsLabelProp, columnsGroupLabel: columnsGroupLabelProp, ...rest }) {
|
|
305
305
|
// crisp/#471: same resolution order as TableToolbar's own — an explicit
|
|
306
306
|
// prop wins, then the provider's translation of the built-in English
|
|
307
307
|
// default, then that default itself with no provider in the tree.
|
|
@@ -782,6 +782,7 @@ export function DataTable({ columns: columnsProp, data, selectable = false, sele
|
|
|
782
782
|
return (_jsx(ChevronsUpDown, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 }));
|
|
783
783
|
}
|
|
784
784
|
return (_jsxs("div", { ref: gridRef, className: datatableRecipe({ className }), tabIndex: -1, onKeyDown: onGridKeyDown, ...rest, children: [_jsx("div", { className: "crisp-datatable-live", role: "status", "aria-live": "polite", children: selectionText }), (filterable || showCount || toolbar || columnMenu) && (_jsxs("div", { className: "crisp-datatable-toolbar", children: [columnMenu && (_jsxs(Menu, { align: "start", trigger: _jsxs("button", { type: "button", className: "crisp-datatable-viewsettings", children: [_jsx(SlidersHorizontal, { size: 14, strokeWidth: 1.75 }), viewSettingsLabel] }), children: [_jsx("div", { className: "crisp-datatable-group-label", children: columnsGroupLabel }), allColumns.map((c) => (_jsxs(MenuItem, { onSelect: () => c.hidden ? showColumn(c.key) : hideColumn(c.key), children: [_jsx(Check, { size: 14, strokeWidth: 2, style: { opacity: c.hidden ? 0 : 1 } }), typeof c.header === "string" ? c.header : c.key] }, c.key)))] })), filterable && (_jsxs("span", { className: "crisp-datatable-search", children: [_jsx(Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), _jsx("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": searchLabel })] })), showCount && (_jsx("span", { className: "crisp-datatable-count", children: resolvedCountLabel(rows.length, data.length) })), toolbar] })), _jsxs(Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
|
|
785
|
+
...scrollProps,
|
|
785
786
|
ref: scrollRef,
|
|
786
787
|
onScroll: (e) => {
|
|
787
788
|
const el = e.currentTarget;
|
|
@@ -66,6 +66,10 @@ const config = defineRecipe({
|
|
|
66
66
|
/* sticky first column(s) + horizontal scroll shadow — RecordsTable's feel */
|
|
67
67
|
& th[data-sticky], & td[data-sticky] { position: sticky; z-index: 1; background: ${c.bgSurface}; }
|
|
68
68
|
& th[data-sticky] { z-index: 3; }
|
|
69
|
+
/* #554: a footer sticky-column cell sits in the bottom-sticky row (table.recipe.ts's
|
|
70
|
+
\`tfoot td { z-index: 2 }\`), which \`td[data-sticky]\`'s own higher-specificity
|
|
71
|
+
\`z-index: 1\` would otherwise undercut -- keep it level with the row it's in. */
|
|
72
|
+
& tfoot td[data-sticky] { z-index: 2; }
|
|
69
73
|
& tbody tr[data-selected] td[data-sticky] { background: color-mix(in srgb, ${c.bgBrandSolid} 10%, ${c.bgSurface}); }
|
|
70
74
|
& tbody tr:hover td[data-sticky] { background: color-mix(in srgb, ${c.fgPrimary} 4%, ${c.bgSurface}); }
|
|
71
75
|
& .crisp-table-scroll[data-scrolled-x] [data-sticky-edge] { clip-path: inset(0 -38px 0 0); box-shadow: 6px 0 16px 4px rgba(0,0,0,0.12); }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Primitive } from "../../core/index.js";
|
|
4
|
+
import { mentionChipRecipe } from "./mentionchip.recipe.js";
|
|
5
|
+
/**
|
|
6
|
+
* A standalone "@mention" chip — the same look `RichTextEditor` draws
|
|
7
|
+
* inline while an editor is live (`.crisp-rte-mention`), exported on its
|
|
8
|
+
* own for a consumer rendering a mention OUTSIDE a mounted editor: a
|
|
9
|
+
* comment thread, a note's collapsed preview, anywhere a stored
|
|
10
|
+
* `@[Name](actor:id)`-shaped token needs to read as a person, not literal
|
|
11
|
+
* markup. Renders whatever `children` is given (the trigger character
|
|
12
|
+
* included, if the caller wants one, matching how `RichTextEditor`'s own
|
|
13
|
+
* chip includes it) rather than assuming an `@` prefix itself — plain text,
|
|
14
|
+
* no built-in click/remove behaviour (none was asked for; add one once a
|
|
15
|
+
* real interaction is measured, the same reasoning `Chip`'s own doc gives
|
|
16
|
+
* for not guessing a remove affordance).
|
|
17
|
+
*/
|
|
18
|
+
export const MentionChip = React.forwardRef(({ className, asChild, ...props }, ref) => {
|
|
19
|
+
return (_jsx(Primitive.span, { ref: ref, asChild: asChild, className: mentionChipRecipe({ className }), ...props }));
|
|
20
|
+
});
|
|
21
|
+
MentionChip.displayName = "MentionChip";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineSpec, resolveRecipe, specToRecipe } from "../../core/index.js";
|
|
2
|
+
import { contract as c } from "../../tokens/index.js";
|
|
3
|
+
// The exact same values `product/richtext`'s own inline "@mention" span
|
|
4
|
+
// uses (`.crisp-rte-mention`, richtext.recipe.ts) — not re-measured against
|
|
5
|
+
// Attio independently (#428's own doc: no live @mention was reachable to
|
|
6
|
+
// read computed styles from, and typing one to create one is off-limits),
|
|
7
|
+
// reused verbatim from the one measured "brand" tag/chip this repo already
|
|
8
|
+
// has (Chip's own `tone="brand"`). Pulled out to its own top-level recipe,
|
|
9
|
+
// rather than importing richtext's, because `.crisp-rte-mention`'s CSS is
|
|
10
|
+
// nested under richtext's own root selector (`&`, i.e. native CSS
|
|
11
|
+
// nesting) — it only resolves inside a mounted `RichTextEditor`. A
|
|
12
|
+
// standalone consumer rendering a mention OUTSIDE an editor (a comment
|
|
13
|
+
// thread, a note preview list) needs the same look with no such ancestor,
|
|
14
|
+
// which is what this recipe is for. Kept deliberately un-pill-shaped (no
|
|
15
|
+
// fixed height, no ring) unlike Chip's own `brand` tone: this reads as
|
|
16
|
+
// tinted text flowing inside a sentence, the same as a live mention does
|
|
17
|
+
// mid-edit, not a standalone tag sitting in its own table cell.
|
|
18
|
+
const spec = defineSpec({
|
|
19
|
+
name: "mention-chip",
|
|
20
|
+
base: {
|
|
21
|
+
display: "inline",
|
|
22
|
+
borderRadius: c.radius.chip,
|
|
23
|
+
paddingInline: c.space["1"],
|
|
24
|
+
background: `color-mix(in srgb, ${c.bgBrandSolid} 14%, transparent)`,
|
|
25
|
+
color: `color-mix(in srgb, ${c.bgBrandSolid} 82%, ${c.fgPrimary})`,
|
|
26
|
+
fontWeight: c.weight.medium,
|
|
27
|
+
cursor: "default",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const config = specToRecipe(spec);
|
|
31
|
+
export const mentionChipRecipe = Object.assign(resolveRecipe(config), {
|
|
32
|
+
config,
|
|
33
|
+
});
|
|
34
|
+
export { spec };
|
|
35
|
+
export default config;
|
|
@@ -8,18 +8,30 @@ import { contract as c } from "../../tokens/index.js";
|
|
|
8
8
|
const config = defineRecipe({
|
|
9
9
|
name: "table",
|
|
10
10
|
base: `display: block; box-sizing: border-box; background: ${c.bgSurface};
|
|
11
|
-
|
|
11
|
+
/* #554: both axes -- a consumer bounds the height via \`scrollProps\`
|
|
12
|
+
(style/className on this element), and the header/footer below pin
|
|
13
|
+
inside it exactly the way Attio's own grid does ("Both the header and
|
|
14
|
+
the summary row are sticky, on the scroll container rather than the
|
|
15
|
+
cells" -- docs/study/attio-table.md). Unbounded, \`overflow: auto\`
|
|
16
|
+
shows no vertical scrollbar and nothing sticks, so this is a no-op
|
|
17
|
+
for every existing consumer that never set a height. */
|
|
18
|
+
& .crisp-table-scroll { overflow: auto; }
|
|
12
19
|
& table { width: 100%; border-collapse: separate; border-spacing: 0; font-family: ${c.font.sans}; font-size: ${c.text.lg}; color: ${c.fgPrimary}; }
|
|
13
20
|
/* #465: 12px, not crisp's old 8px -- measured on a live header cell
|
|
14
21
|
(padding: 0 12px) and independently on a body cell's text inset
|
|
15
22
|
(getBoundingClientRect delta from the cell edge). Matches
|
|
16
23
|
ColumnCalc's own already-correct 12px trigger inset. */
|
|
17
24
|
& th, & td { position: relative; height: ${c.size.tableRow}; padding: 0 ${c.space["3"]}; border-bottom: 1px solid ${c.borderSubtle}; border-inline-end: 1px solid ${c.borderSubtle}; text-align: start; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
18
|
-
|
|
25
|
+
/* #554: sticky on the vertical axis, mirroring RecordsTable's own
|
|
26
|
+
\`.crisp-recordstable-th\`. z-index 2 sits above a plain body cell (auto)
|
|
27
|
+
and below a sticky-column corner cell (DataTable's \`th[data-sticky]\`,
|
|
28
|
+
z-index 3), so the corner always wins. */
|
|
29
|
+
& th { position: sticky; top: 0; z-index: 2; height: ${c.size.tableHeader}; background: ${c.bgSurface}; border-top: 1px solid ${c.borderSubtle}; font-size: ${c.text.lg}; font-weight: ${c.weight.medium}; letter-spacing: -0.14px; color: color-mix(in srgb, ${c.fgPrimary} 63%, transparent); user-select: none; }
|
|
19
30
|
& td { color: ${c.fgPrimary}; background: ${c.bgSurface}; }
|
|
20
31
|
& th:last-child, & td:last-child { border-inline-end: none; }
|
|
21
32
|
& tbody tr:last-child td { border-bottom: none; }
|
|
22
|
-
|
|
33
|
+
/* #554: sticky to the bottom, mirroring \`.crisp-recordstable-sum\`. */
|
|
34
|
+
& tfoot td { position: sticky; bottom: 0; z-index: 2; border-top: 1px solid ${c.borderSubtle}; border-bottom: 1px solid ${c.borderSubtle}; font-weight: ${c.weight.medium}; color: ${c.fgMuted}; }
|
|
23
35
|
& caption { padding: ${c.space["2"]} ${c.space["2"]}; text-align: start; font-size: ${c.text.sm}; color: ${c.fgMuted}; caption-side: bottom; }
|
|
24
36
|
& td[data-align="right"], & th[data-align="right"] { text-align: end; }
|
|
25
37
|
& td[data-align="center"], & th[data-align="center"] { text-align: center; }`,
|
|
@@ -48,6 +48,23 @@ export function isInsideLaterFloatingLayer(target, self) {
|
|
|
48
48
|
}
|
|
49
49
|
return false;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* True when a layer is registered strictly after `self` — i.e. `self` has
|
|
53
|
+
* spawned a still-open nested layer of its own (a row's kebab `Menu` inside
|
|
54
|
+
* `SavedViews`' own panel, e.g.).
|
|
55
|
+
*
|
|
56
|
+
* This is `hasOpenFloatingLayer`'s sibling for a caller that DOES register
|
|
57
|
+
* itself on this stack: `hasOpenFloatingLayer` reads "is the stack
|
|
58
|
+
* non-empty", which is always true for such a caller once its own layer is
|
|
59
|
+
* open — checking that before closing on Escape would defer to itself
|
|
60
|
+
* forever and Escape would never close it. `self`'s own position on the
|
|
61
|
+
* stack has to be excluded from the count, which `hasOpenFloatingLayer`
|
|
62
|
+
* cannot do since it takes no argument.
|
|
63
|
+
*/
|
|
64
|
+
export function hasNestedFloatingLayer(self) {
|
|
65
|
+
const selfIndex = self ? stack.indexOf(self) : -1;
|
|
66
|
+
return selfIndex + 1 < stack.length;
|
|
67
|
+
}
|
|
51
68
|
/**
|
|
52
69
|
* True when at least one `Select`/`MultiSelect`/`Menu`/`Popover`/
|
|
53
70
|
* `ContextMenu` is currently open, anywhere (#361).
|
package/dist/esm/core/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { defineRecipe } from "./define.js";
|
|
|
5
5
|
export { withDescribedBy } from "./dialog-description.js";
|
|
6
6
|
export { isRtlElement } from "./direction.js";
|
|
7
7
|
export { FloatingPortal } from "./floating-portal.js";
|
|
8
|
-
export { hasOpenFloatingLayer, isInsideLaterFloatingLayer, registerFloatingLayer, } from "./floating-stack.js";
|
|
8
|
+
export { hasNestedFloatingLayer, hasOpenFloatingLayer, isInsideLaterFloatingLayer, registerFloatingLayer, } from "./floating-stack.js";
|
|
9
9
|
export { formValueStyle } from "./form-value.js";
|
|
10
10
|
export { CrispMessagesProvider, useCrispComponentDefaults, useCrispMessage, useCrispMessages, } from "./i18n.js";
|
|
11
11
|
export { matchMentionTrigger, } from "./mention.js";
|
package/dist/esm/index.js
CHANGED
|
@@ -33,6 +33,7 @@ export * from "./components/heatmapchart/index.js";
|
|
|
33
33
|
export * from "./components/input/index.js";
|
|
34
34
|
export * from "./components/kbd/index.js";
|
|
35
35
|
export * from "./components/linechart/index.js";
|
|
36
|
+
export * from "./components/mentionchip/index.js";
|
|
36
37
|
export * from "./components/menu/index.js";
|
|
37
38
|
export * from "./components/middletruncate/index.js";
|
|
38
39
|
export * from "./components/multiselect/index.js";
|
|
@@ -65,13 +66,16 @@ export * from "./core/index.js";
|
|
|
65
66
|
// product screens (Sidebar, RecordsTable, RecordPage, Inbox, …). Use them as-is
|
|
66
67
|
// or as composition references for your own data; `components/` above holds
|
|
67
68
|
// the generic primitives (Table, DataTable, Button, …) to build your own UI from.
|
|
69
|
+
export * from "./product/activityfeed/index.js";
|
|
68
70
|
export * from "./product/appshell/index.js";
|
|
69
71
|
export * from "./product/authshell/index.js";
|
|
70
72
|
export * from "./product/board/index.js";
|
|
71
73
|
export * from "./product/command/index.js";
|
|
72
74
|
export * from "./product/entitycard/index.js";
|
|
73
75
|
export * from "./product/flowcanvas/index.js";
|
|
76
|
+
export * from "./product/formdialog/index.js";
|
|
74
77
|
export * from "./product/headerbar/index.js";
|
|
78
|
+
export * from "./product/importdialog/index.js";
|
|
75
79
|
export * from "./product/inbox/index.js";
|
|
76
80
|
export * from "./product/listpage/index.js";
|
|
77
81
|
export * from "./product/navitem/index.js";
|
|
@@ -80,11 +84,14 @@ export * from "./product/recordpage/index.js";
|
|
|
80
84
|
export * from "./product/recordpanel/index.js";
|
|
81
85
|
export * from "./product/recordstable/index.js";
|
|
82
86
|
export * from "./product/richtext/index.js";
|
|
87
|
+
export * from "./product/savedviews/index.js";
|
|
83
88
|
export * from "./product/settingssection/index.js";
|
|
84
89
|
export * from "./product/settingsshell/index.js";
|
|
85
90
|
export * from "./product/sidebar/index.js";
|
|
86
91
|
export * from "./product/statlist/index.js";
|
|
87
92
|
export * from "./product/tasklist/index.js";
|
|
93
|
+
export * from "./product/taskstable/index.js";
|
|
94
|
+
export * from "./product/themepicker/index.js";
|
|
88
95
|
export * from "./product/trialbanner/index.js";
|
|
89
96
|
export * from "./product/viewtoggle/index.js";
|
|
90
97
|
// design tokens + recipe core (for building custom components)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { activityfeedRecipe } from "./activityfeed.recipe.js";
|
|
3
|
+
/**
|
|
4
|
+
* A record's own event timeline — a vertically stacked, bordered list of
|
|
5
|
+
* `ActivityFeedRow`s, capped at a readable content width. Built for
|
|
6
|
+
* internal/grc's per-record "Activity" tab (crisp#462 SHELL/forms gap): it
|
|
7
|
+
* replaces a hand-rolled `<div className="mx-auto max-w-3xl space-y-4
|
|
8
|
+
* p-6">`. No live Attio re-measurement behind its own chrome this pass (the
|
|
9
|
+
* CDP bridge was unreachable when this was built) — see the recipe's own
|
|
10
|
+
* doc comment for which already-measured crisp values it reuses instead of
|
|
11
|
+
* a new guess.
|
|
12
|
+
*/
|
|
13
|
+
export function ActivityFeed({ className, children, ...rest }) {
|
|
14
|
+
return (_jsx("div", { className: activityfeedRecipe({ className }), ...rest, children: children }));
|
|
15
|
+
}
|
|
16
|
+
ActivityFeed.displayName = "ActivityFeed";
|
|
17
|
+
/** One event row: actor + action + timestamp, with an optional diff list
|
|
18
|
+
* underneath. The last row in an `ActivityFeed` draws no divider. */
|
|
19
|
+
export function ActivityFeedRow({ actor, action, when, children, }) {
|
|
20
|
+
return (_jsxs("div", { className: "crisp-activityfeed-row", children: [_jsxs("div", { className: "crisp-activityfeed-row-head", children: [actor, action, _jsx("span", { className: "crisp-activityfeed-row-spacer" }), _jsx("span", { className: "crisp-activityfeed-row-when", children: when })] }), children] }));
|
|
21
|
+
}
|
|
22
|
+
ActivityFeedRow.displayName = "ActivityFeedRow";
|
|
23
|
+
/** One changed-field line under an `ActivityFeedRow` — "Field: before →
|
|
24
|
+
* after", or "Field: set to after" when there is no known prior value. */
|
|
25
|
+
export function ActivityFeedDiffItem({ field, before, after, }) {
|
|
26
|
+
return (_jsxs("li", { className: "crisp-activityfeed-diff-item", children: [_jsx("span", { className: "crisp-activityfeed-diff-field", children: field }), " ", before !== undefined ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "crisp-activityfeed-diff-before", children: before }), " ", _jsx("span", { "aria-hidden": "true", children: "\u2192" }), " ", _jsx("span", { children: after })] })) : (_jsx("span", { children: after }))] }));
|
|
27
|
+
}
|
|
28
|
+
ActivityFeedDiffItem.displayName = "ActivityFeedDiffItem";
|
|
29
|
+
export function ActivityFeedDiffList({ children, }) {
|
|
30
|
+
return _jsx("ul", { className: "crisp-activityfeed-diff", children: children });
|
|
31
|
+
}
|
|
32
|
+
ActivityFeedDiffList.displayName = "ActivityFeedDiffList";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineRecipe, resolveRecipe } from "../../core/index.js";
|
|
2
|
+
import { contract as c } from "../../tokens/index.js";
|
|
3
|
+
// A record's own event timeline (crisp#462 gap: internal/grc's ActivityTab
|
|
4
|
+
// hand-rolled this as a bare `<div className="mx-auto max-w-3xl space-y-4
|
|
5
|
+
// p-6">` list of bordered rows). No live Attio re-measurement behind these
|
|
6
|
+
// values this pass -- the CDP bridge to the owner's Vivaldi was unreachable
|
|
7
|
+
// when this was built (documented in the component's own doc comment) --
|
|
8
|
+
// so this reuses already-measured crisp values throughout rather than a new
|
|
9
|
+
// guess: `space["6"]` (24px) padding is RecordPanel's own content padding,
|
|
10
|
+
// the row's bottom border reuses `borderSubtle` (the same divider every
|
|
11
|
+
// other bordered row in this codebase draws with), and the 767px content
|
|
12
|
+
// cap matches SettingsSection's own measured content width.
|
|
13
|
+
const config = defineRecipe({
|
|
14
|
+
name: "activityfeed",
|
|
15
|
+
base: `box-sizing: border-box; max-width: 767px; margin-inline: auto; padding: ${c.space["6"]};
|
|
16
|
+
display: flex; flex-direction: column; gap: ${c.space["4"]};
|
|
17
|
+
& .crisp-activityfeed-row { display: flex; flex-direction: column; gap: ${c.space["2"]}; padding-bottom: ${c.space["4"]}; border-bottom: 1px solid ${c.borderSubtle}; }
|
|
18
|
+
& .crisp-activityfeed-row:last-of-type { border-bottom: none; padding-bottom: 0; }
|
|
19
|
+
& .crisp-activityfeed-row-head { display: flex; align-items: center; gap: ${c.space["2"]}; }
|
|
20
|
+
& .crisp-activityfeed-row-spacer { flex: 1; }
|
|
21
|
+
& .crisp-activityfeed-row-when { font-size: ${c.text.xs}; color: ${c.fgMuted}; white-space: nowrap; }
|
|
22
|
+
& .crisp-activityfeed-diff { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: ${c.space["1"]}; }
|
|
23
|
+
& .crisp-activityfeed-diff-item { padding-inline-start: ${c.space["8"]}; font-size: ${c.text.md}; }
|
|
24
|
+
& .crisp-activityfeed-diff-field { color: ${c.fgMuted}; }
|
|
25
|
+
& .crisp-activityfeed-diff-before { color: ${c.fgMuted}; text-decoration: line-through; }
|
|
26
|
+
`,
|
|
27
|
+
variants: {},
|
|
28
|
+
defaultVariants: {},
|
|
29
|
+
compoundVariants: [],
|
|
30
|
+
});
|
|
31
|
+
export const activityfeedRecipe = resolveRecipe(config);
|
|
32
|
+
export default config;
|