@crisp-ui-kit/crisp 0.50.0 → 0.52.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/composewindow/composewindow.js +144 -0
- package/dist/cjs/components/composewindow/composewindow.recipe.js +45 -0
- package/dist/cjs/components/composewindow/index.js +8 -0
- package/dist/cjs/components/datatable/datatable.js +224 -43
- package/dist/cjs/components/datatable/datatable.recipe.js +37 -3
- package/dist/cjs/components/datatable/index.js +6 -0
- package/dist/cjs/components/datepickerfield/datepickerfield.js +25 -15
- package/dist/cjs/components/datepickerfield/datepickerfield.recipe.js +25 -8
- package/dist/cjs/components/dialog/dialog.recipe.js +9 -1
- package/dist/cjs/components/menu/menu.js +4 -2
- package/dist/cjs/components/multiselect/multiselect.recipe.js +14 -8
- package/dist/cjs/components/select/select.js +2 -1
- package/dist/cjs/components/table/table.recipe.js +12 -3
- package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +1 -1
- package/dist/cjs/components/tabletoolbar/tabletoolbar.js +18 -7
- package/dist/cjs/core/caret-rect.js +73 -0
- package/dist/cjs/core/cell-date.js +11 -0
- package/dist/cjs/core/index.js +8 -1
- package/dist/cjs/core/mention.js +32 -0
- package/dist/cjs/core/use-mention-trigger.js +124 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/product/recordpage/recordpage.js +88 -10
- package/dist/cjs/product/recordpage/recordpage.recipe.js +30 -0
- package/dist/cjs/product/recordpanel/recordpanel.js +11 -29
- package/dist/cjs/product/recordpanel/recordpanel.recipe.js +55 -17
- package/dist/cjs/product/recordstable/editable-field.js +113 -0
- package/dist/cjs/product/recordstable/index.js +4 -1
- package/dist/cjs/product/recordstable/recordstable.js +67 -11
- package/dist/cjs/product/recordstable/recordstable.recipe.js +9 -1
- package/dist/cjs/product/recordstable/recordstable.tag.js +8 -3
- package/dist/cjs/product/richtext/index.js +2 -1
- package/dist/cjs/product/richtext/richtext.js +440 -23
- package/dist/cjs/product/richtext/richtext.recipe.js +59 -9
- package/dist/cjs/product/settingsshell/settingsshell.recipe.js +13 -4
- package/dist/cjs/product/sidebar/sidebar.js +15 -3
- package/dist/cjs/product/sidebar/sidebar.recipe.js +21 -2
- package/dist/composewindow.css +24 -0
- package/dist/composewindow.d.ts +7 -0
- package/dist/composewindow.layered.css +26 -0
- package/dist/datatable.css +33 -14
- package/dist/datatable.layered.css +33 -14
- package/dist/datepickerfield.css +9 -4
- package/dist/datepickerfield.layered.css +9 -4
- package/dist/dialog.css +2 -1
- package/dist/dialog.layered.css +2 -1
- package/dist/esm/components/composewindow/composewindow.js +107 -0
- package/dist/esm/components/composewindow/composewindow.recipe.js +42 -0
- package/dist/esm/components/composewindow/index.js +2 -0
- package/dist/esm/components/datatable/datatable.js +226 -45
- package/dist/esm/components/datatable/datatable.recipe.js +37 -3
- package/dist/esm/components/datatable/index.js +6 -0
- package/dist/esm/components/datepickerfield/datepickerfield.js +26 -16
- package/dist/esm/components/datepickerfield/datepickerfield.recipe.js +25 -8
- package/dist/esm/components/dialog/dialog.recipe.js +9 -1
- package/dist/esm/components/menu/menu.js +4 -2
- package/dist/esm/components/multiselect/multiselect.recipe.js +14 -8
- package/dist/esm/components/select/select.js +2 -1
- package/dist/esm/components/table/table.recipe.js +12 -3
- package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +1 -1
- package/dist/esm/components/tabletoolbar/tabletoolbar.js +18 -7
- package/dist/esm/core/caret-rect.js +70 -0
- package/dist/esm/core/cell-date.js +10 -0
- package/dist/esm/core/index.js +4 -1
- package/dist/esm/core/mention.js +29 -0
- package/dist/esm/core/use-mention-trigger.js +88 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/product/recordpage/recordpage.js +89 -11
- package/dist/esm/product/recordpage/recordpage.recipe.js +30 -0
- package/dist/esm/product/recordpanel/index.js +1 -1
- package/dist/esm/product/recordpanel/recordpanel.js +13 -31
- package/dist/esm/product/recordpanel/recordpanel.recipe.js +56 -18
- package/dist/esm/product/recordstable/editable-field.js +76 -0
- package/dist/esm/product/recordstable/index.js +1 -0
- package/dist/esm/product/recordstable/recordstable.js +69 -13
- package/dist/esm/product/recordstable/recordstable.recipe.js +9 -1
- package/dist/esm/product/recordstable/recordstable.tag.js +8 -3
- package/dist/esm/product/richtext/index.js +1 -1
- package/dist/esm/product/richtext/richtext.js +439 -22
- package/dist/esm/product/richtext/richtext.recipe.js +60 -10
- package/dist/esm/product/settingsshell/settingsshell.recipe.js +13 -4
- package/dist/esm/product/sidebar/sidebar.js +15 -3
- package/dist/esm/product/sidebar/sidebar.recipe.js +21 -2
- package/dist/multiselect.css +8 -8
- package/dist/multiselect.layered.css +8 -8
- package/dist/recordpage.css +25 -13
- package/dist/recordpage.layered.css +25 -13
- package/dist/recordpanel.css +43 -20
- package/dist/recordpanel.layered.css +43 -20
- package/dist/recordstable.css +9 -2
- package/dist/recordstable.layered.css +9 -2
- package/dist/richtext.css +31 -5
- package/dist/richtext.layered.css +31 -5
- package/dist/settingsshell.css +2 -2
- package/dist/settingsshell.layered.css +2 -2
- package/dist/sidebar.css +7 -2
- package/dist/sidebar.layered.css +7 -2
- package/dist/styles.css +199 -74
- package/dist/styles.layered.css +199 -74
- package/dist/table.css +4 -2
- package/dist/table.layered.css +4 -2
- package/dist/tabletoolbar.css +1 -1
- package/dist/tabletoolbar.layered.css +1 -1
- package/dist/types/components/composewindow/composewindow.d.ts +80 -0
- package/dist/types/components/composewindow/composewindow.recipe.d.ts +3 -0
- package/dist/types/components/composewindow/index.d.ts +2 -0
- package/dist/types/components/datatable/datatable.d.ts +58 -4
- package/dist/types/components/datatable/index.d.ts +1 -1
- package/dist/types/components/datepickerfield/datepickerfield.d.ts +18 -4
- package/dist/types/components/menu/menu.d.ts +10 -1
- package/dist/types/components/select/select.d.ts +6 -1
- package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +29 -5
- package/dist/types/core/caret-rect.d.ts +16 -0
- package/dist/types/core/cell-date.d.ts +17 -0
- package/dist/types/core/index.d.ts +4 -1
- package/dist/types/core/mention.d.ts +27 -0
- package/dist/types/core/use-mention-trigger.d.ts +41 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/product/recordpage/recordpage.d.ts +59 -1
- package/dist/types/product/recordpanel/index.d.ts +1 -1
- package/dist/types/product/recordpanel/recordpanel.d.ts +81 -17
- package/dist/types/product/recordstable/editable-field.d.ts +48 -0
- package/dist/types/product/recordstable/index.d.ts +1 -0
- package/dist/types/product/recordstable/recordstable.d.ts +29 -0
- package/dist/types/product/recordstable/recordstable.tag.d.ts +8 -3
- package/dist/types/product/richtext/index.d.ts +1 -1
- package/dist/types/product/richtext/richtext.d.ts +168 -7
- package/dist/types/product/sidebar/sidebar.d.ts +60 -4
- package/package.json +6 -1
|
@@ -1,35 +1,99 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { type
|
|
2
|
+
import { type AvatarProps } from "../../components/avatar";
|
|
3
|
+
import type { Row } from "../recordstable";
|
|
4
|
+
type IconType = React.ComponentType<{
|
|
5
|
+
size?: number;
|
|
6
|
+
strokeWidth?: number;
|
|
7
|
+
}>;
|
|
8
|
+
/** One Highlights card — label, value and an optional icon, laid out the
|
|
9
|
+
* way Attio's peek panel lays its own out (measured live, #448): a 2-column
|
|
10
|
+
* grid, no card chrome (no border/background/shadow), a muted label row
|
|
11
|
+
* with a trailing icon, a filled-colour value below it. */
|
|
12
|
+
export type RecordPanelHighlight = {
|
|
13
|
+
key: string;
|
|
14
|
+
label: string;
|
|
15
|
+
value: React.ReactNode;
|
|
16
|
+
icon?: IconType;
|
|
17
|
+
};
|
|
3
18
|
export type RecordPanelProps = Omit<React.ComponentPropsWithoutRef<"div">, "children" | "title"> & {
|
|
4
|
-
/** The record to show; render nothing when null. */
|
|
5
19
|
/** Label for the close control. */
|
|
6
20
|
closeLabel?: string;
|
|
21
|
+
/**
|
|
22
|
+
* A toolbar row above the panel's own identity header — measured live on
|
|
23
|
+
* app.attio.com's peek (hover a Companies row, click "Open preview"):
|
|
24
|
+
* Close, then Previous/Next record on the left, an "Open record" icon on
|
|
25
|
+
* the right, a hairline border beneath separating it from the identity
|
|
26
|
+
* block below. Close always renders (`onClose` is required); Previous/
|
|
27
|
+
* Next/Open record each render only when given a handler — a consumer
|
|
28
|
+
* with no adjacent-row concept, or nowhere to open the record's own full
|
|
29
|
+
* page, simply omits them, leaving just Close.
|
|
30
|
+
*/
|
|
31
|
+
onOpenRecord?: () => void;
|
|
32
|
+
openRecordLabel?: string;
|
|
33
|
+
onPrevious?: () => void;
|
|
34
|
+
previousRecordLabel?: string;
|
|
35
|
+
onNext?: () => void;
|
|
36
|
+
nextRecordLabel?: string;
|
|
7
37
|
/**
|
|
8
38
|
* The panel's heading, and so its accessible name (via `aria-labelledby`,
|
|
9
39
|
* not a stringified `aria-label` — it also drives the visible title, which
|
|
10
|
-
* can be any node). Defaults to
|
|
11
|
-
* this prop existed; pass it to title the panel by something else, e.g.
|
|
12
|
-
* "{Collection} record".
|
|
40
|
+
* can be any node). Defaults to `record.name`.
|
|
13
41
|
*/
|
|
14
42
|
title?: React.ReactNode;
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
43
|
+
/** Avatar image URL beside the title. Omit for an initials tile built
|
|
44
|
+
* from `record.name`'s first character. */
|
|
45
|
+
avatar?: string;
|
|
46
|
+
/** Tone for the initials tile when no `avatar` image is given (default
|
|
47
|
+
* "brand", matching Attio's own peek). */
|
|
48
|
+
avatarTone?: NonNullable<AvatarProps["tone"]>;
|
|
49
|
+
/** The record to show; render nothing when null. Only `id`/`name` are
|
|
50
|
+
* read directly here — everything else the panel shows comes from
|
|
51
|
+
* `highlights`/`activity`, the consumer's own data. */
|
|
52
|
+
record: (Row & {
|
|
53
|
+
name?: string;
|
|
54
|
+
}) | null;
|
|
55
|
+
/** Heading above the highlight cards (default "Highlights"). Omit the
|
|
56
|
+
* whole section by omitting `highlights`. */
|
|
57
|
+
highlightsLabel?: React.ReactNode;
|
|
58
|
+
/**
|
|
59
|
+
* Highlight cards — label, value, optional icon (#448). Attio's own peek
|
|
60
|
+
* shows these as a fixed set of business-pipeline stats (Connection
|
|
61
|
+
* strength, Estimated ARR, …); crisp has no such fixed set, so this is
|
|
62
|
+
* fully consumer-supplied, laid out in Attio's own measured 2-column
|
|
63
|
+
* grid. Omit for no Highlights section at all.
|
|
64
|
+
*/
|
|
65
|
+
highlights?: RecordPanelHighlight[];
|
|
66
|
+
/** Heading above the activity feed (default "Activity"). */
|
|
67
|
+
activityLabel?: React.ReactNode;
|
|
68
|
+
/** Label for the trailing "View all" action beside the Activity heading.
|
|
69
|
+
* Only rendered when `onViewAllActivity` is given. */
|
|
70
|
+
viewAllActivityLabel?: React.ReactNode;
|
|
71
|
+
onViewAllActivity?: () => void;
|
|
72
|
+
/**
|
|
73
|
+
* Activity feed content (#448) — a consumer-supplied slot. crisp has no
|
|
74
|
+
* activity-feed model of its own (no fixed shape for "who did what,
|
|
75
|
+
* when" — that's app data); this only wraps whatever's given with the
|
|
76
|
+
* measured "Activity" heading Attio's peek shows above its own feed. Omit
|
|
77
|
+
* for no Activity section at all.
|
|
78
|
+
*/
|
|
79
|
+
activity?: React.ReactNode;
|
|
80
|
+
/** Rendered below the panel's content, e.g. an Edit button. Omit for no footer. */
|
|
20
81
|
footer?: React.ReactNode;
|
|
21
|
-
record: Row | null;
|
|
22
|
-
columns: Column[];
|
|
23
82
|
onClose: () => void;
|
|
24
83
|
className?: string;
|
|
25
84
|
};
|
|
26
85
|
/**
|
|
27
|
-
* Right-side record peek panel —
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
86
|
+
* Right-side record peek panel — Attio's own peek shows a Highlights card
|
|
87
|
+
* area and an Activity feed (measured live: hover a Companies row, click its
|
|
88
|
+
* "Open preview" trigger), never an editable field list (#448 — a "Details"
|
|
89
|
+
* list was this component's own invention before, and #431's editable API
|
|
90
|
+
* had nothing real in this panel to attach to; that API stays on
|
|
91
|
+
* `RecordPage`'s own Details column, where Attio does let you edit in
|
|
92
|
+
* place). Render it inside a `position: relative` container (e.g. the app
|
|
93
|
+
* main area); it slides in from the right and overlays the content.
|
|
31
94
|
*/
|
|
32
|
-
export declare function RecordPanel({ record,
|
|
95
|
+
export declare function RecordPanel({ record, onClose, className, closeLabel, onOpenRecord, openRecordLabel, onPrevious, previousRecordLabel, onNext, nextRecordLabel, title, avatar, avatarTone, highlightsLabel, highlights, activityLabel, viewAllActivityLabel, onViewAllActivity, activity, footer, ...rest }: RecordPanelProps): React.JSX.Element | null;
|
|
33
96
|
export declare namespace RecordPanel {
|
|
34
97
|
var displayName: string;
|
|
35
98
|
}
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** A `select`-editor field's choices — same shape DataTable's own
|
|
2
|
+
* `DataEditableOption` uses (#385/#430), kept as its own type (not
|
|
3
|
+
* `Column.options`/`StatusOption`, whose `color` is required for the
|
|
4
|
+
* `status` picker) so this stays purely additive. */
|
|
5
|
+
export type EditableOption = {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
color?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The async-commit state machine behind `RecordPage`'s editable Details
|
|
12
|
+
* column (#431) — the same shape `DataTable`'s own `commitEdit` uses
|
|
13
|
+
* (#385/#430): a sync `onEdit` (returns `undefined`) commits and closes
|
|
14
|
+
* immediately; a Promise-returning `onEdit` keeps the field open and pending
|
|
15
|
+
* while it settles, then either closes it (resolve) or closes it AND
|
|
16
|
+
* reverts while showing the rejection's message (reject). The revert needs
|
|
17
|
+
* no extra code here either: `RecordPage` never mutates `record` itself, so
|
|
18
|
+
* once `editingKey` clears, the field simply renders `record[key]` again —
|
|
19
|
+
* whatever it still says.
|
|
20
|
+
*
|
|
21
|
+
* `RecordPanel` (the peek panel) used to share this hook too, before #448
|
|
22
|
+
* found that Attio's own peek has no editable field at all to attach it to
|
|
23
|
+
* — only `RecordPage`'s Details column does. Kept as its own module rather
|
|
24
|
+
* than folded back into `recordpage.tsx`: a second consumer turning up
|
|
25
|
+
* again is a smaller change than re-extracting it would be.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useEditableField(onEdit?: (id: string, key: string, value: string) => Promise<void> | void): {
|
|
28
|
+
editingKey: string | null;
|
|
29
|
+
pendingKey: string | null;
|
|
30
|
+
error: {
|
|
31
|
+
key: string;
|
|
32
|
+
message: string;
|
|
33
|
+
} | null;
|
|
34
|
+
openEditing: (key: string) => void;
|
|
35
|
+
closeEditing: () => void;
|
|
36
|
+
commit: (id: string, key: string, value: string) => void;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Which plain editor a column gets when it's `editable` without an
|
|
40
|
+
* `editor: "select" | "switch"` — identical to `DataTable`'s own
|
|
41
|
+
* `editorFor` (#385): number/currency get a numeric field, date a native
|
|
42
|
+
* date field, everything else (text, entity, tags, url, status, reference)
|
|
43
|
+
* a plain text field. Kept as one function so the two never drift apart.
|
|
44
|
+
*/
|
|
45
|
+
export declare function editableInputType(colType: string | undefined): {
|
|
46
|
+
type: string;
|
|
47
|
+
inputMode?: "decimal" | "text";
|
|
48
|
+
};
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
export { type EditableOption, editableInputType, useEditableField, } from "./editable-field";
|
|
1
2
|
export { type Column, type ColumnType, defaultColumns, defaultRows, type EntityValue, RecordsTable, type RecordsTableProps, type Row, tagTone, } from "./recordstable";
|
|
2
3
|
export { recordstableRecipe } from "./recordstable.recipe";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import type { EditableOption } from "./editable-field";
|
|
2
3
|
type IconType = React.ComponentType<{
|
|
3
4
|
size?: number;
|
|
4
5
|
strokeWidth?: number;
|
|
@@ -29,6 +30,14 @@ export type Column = {
|
|
|
29
30
|
options?: StatusOption[];
|
|
30
31
|
/** Choices for a `reference` column (a searchable record picker). */
|
|
31
32
|
refOptions?: ReferenceOption[];
|
|
33
|
+
/** Adds a trailing "Create {createLabel}" row to the picker (Attio's own
|
|
34
|
+
* always has one) — rendered only when this is provided. Picking it hands
|
|
35
|
+
* back the picker's current search text, e.g. to open a create flow
|
|
36
|
+
* pre-seeded with it. */
|
|
37
|
+
onCreateReference?: (query: string) => void;
|
|
38
|
+
/** The object noun in "Create {createLabel}" (Attio: "Create Person").
|
|
39
|
+
* Only used with `onCreateReference`; defaults to "record". */
|
|
40
|
+
createLabel?: string;
|
|
32
41
|
/**
|
|
33
42
|
* Full custom cell content — an escape hatch for a display crisp can't
|
|
34
43
|
* express via `type` (sign-coloured currency, a maskable amount, a custom
|
|
@@ -65,6 +74,26 @@ export type Column = {
|
|
|
65
74
|
* currency string still sums and sorts numerically.
|
|
66
75
|
*/
|
|
67
76
|
format?: (value: unknown, row: Row) => string;
|
|
77
|
+
/**
|
|
78
|
+
* Opts this column into `RecordPanel`/`RecordPage`'s editable-field API
|
|
79
|
+
* (#431) — click-to-edit there (not this table's own type-driven
|
|
80
|
+
* mechanism, which those two components don't use). Ignored by
|
|
81
|
+
* `RecordsTable` itself. A plain `editable` column, with no `editor`,
|
|
82
|
+
* opens a text/number/date field (inferred from `type`, same inference
|
|
83
|
+
* `DataTable`'s own `editable` columns use — #385); `editor` below picks
|
|
84
|
+
* a `select`/`switch` picker instead. Both consumers require `onEdit` to
|
|
85
|
+
* actually be given for a field to open at all.
|
|
86
|
+
*/
|
|
87
|
+
editable?: boolean;
|
|
88
|
+
/** `select`/`switch` render as the field's own live, always-interactive
|
|
89
|
+
* content instead of opening on click — see `DataTableColumn.editor`
|
|
90
|
+
* (#385) for the identical convention and reasoning. `select` reads
|
|
91
|
+
* `editOptions`. */
|
|
92
|
+
editor?: "select" | "switch";
|
|
93
|
+
/** Options for `editor: "select"` — same shape `DataTable`'s own
|
|
94
|
+
* `DataEditableOption` uses. Not `options` (`StatusOption` requires
|
|
95
|
+
* `color`, for this type's own `status` picker) so this stays additive. */
|
|
96
|
+
editOptions?: EditableOption[];
|
|
68
97
|
};
|
|
69
98
|
export type EntityValue = {
|
|
70
99
|
name: string;
|
|
@@ -3,8 +3,13 @@
|
|
|
3
3
|
* `border-radius: ${c.radius.chip}`, 14px/20px at weight 500, and a 1px inset ring in the
|
|
4
4
|
* tone's colour.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* to be
|
|
8
|
-
*
|
|
6
|
+
* Its own module (not pasted into `recordstable.recipe.ts`) because it used
|
|
7
|
+
* to be shared with `RecordPanel`'s own Details field list too, and the two
|
|
8
|
+
* copies had already started to drift before that sharing existed — adding
|
|
9
|
+
* the measured inset ring meant patching the same rules twice. `RecordPanel`
|
|
10
|
+
* no longer renders a Details list (#448, Attio's own peek doesn't have
|
|
11
|
+
* one), so `RecordsTable` is this module's only consumer now; kept as its
|
|
12
|
+
* own file rather than folded back in, since a second consumer showing up
|
|
13
|
+
* again is exactly how the drift happened the first time.
|
|
9
14
|
*/
|
|
10
15
|
export declare const recordTagCss: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { RichTextEditor, type RichTextEditorProps, type RichTextValue, } from "./richtext";
|
|
1
|
+
export { RICHTEXT_COLOR_TONES, type RichTextColorTone, RichTextEditor, type RichTextEditorHandle, type RichTextEditorProps, type RichTextMention, type RichTextMentionTriggerState, type RichTextValue, } from "./richtext";
|
|
2
2
|
export { richtextRecipe } from "./richtext.recipe";
|
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type MentionAnchor } from "../../core";
|
|
2
3
|
export type RichTextValue = {
|
|
3
4
|
title: string;
|
|
4
5
|
html: string;
|
|
5
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* A named text-color / highlight-color pair — the 12 tones Attio's own note
|
|
9
|
+
* editor offers as inline marks (measured live, read-only, 2026-09-24;
|
|
10
|
+
* re-verified against the same note before shipping — see HANDOFF). Exported
|
|
11
|
+
* so a consumer wanting the same palette elsewhere (a tag picker, a legend)
|
|
12
|
+
* doesn't have to re-type it.
|
|
13
|
+
*/
|
|
14
|
+
export type RichTextColorTone = {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
/** Value passed to `execCommand("foreColor", …)`. */
|
|
18
|
+
text: string;
|
|
19
|
+
/** Value passed to `execCommand("hiliteColor", …)`. */
|
|
20
|
+
highlight: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const RICHTEXT_COLOR_TONES: RichTextColorTone[];
|
|
23
|
+
/** A reference to insert as an atomic mention chip (#428). */
|
|
24
|
+
export type RichTextMention = {
|
|
25
|
+
id: string;
|
|
26
|
+
label: string;
|
|
27
|
+
};
|
|
28
|
+
/** State handed to `renderMentionPicker` each time it's asked to show. */
|
|
29
|
+
export type RichTextMentionTriggerState = {
|
|
30
|
+
/** Text typed after the trigger character so far. */
|
|
31
|
+
query: string;
|
|
32
|
+
/** Where to anchor the picker, in viewport coordinates. */
|
|
33
|
+
anchor: MentionAnchor;
|
|
34
|
+
/** Insert `mention` as a chip in place of the "@query" text, and dismiss. */
|
|
35
|
+
select: (mention: RichTextMention) => void;
|
|
36
|
+
/** Dismiss without inserting anything — e.g. on Escape or an outside click. */
|
|
37
|
+
close: () => void;
|
|
38
|
+
};
|
|
39
|
+
export type RichTextEditorHandle = {
|
|
40
|
+
/** Insert `mention` as an atomic, non-editable chip — in place of the
|
|
41
|
+
* active "@query" trigger text when one is open, otherwise at the current
|
|
42
|
+
* caret (or the end of the body, with no caret in it at all). */
|
|
43
|
+
insertMention: (mention: RichTextMention) => void;
|
|
44
|
+
/** Focus the body editor. */
|
|
45
|
+
focus: () => void;
|
|
46
|
+
};
|
|
6
47
|
export type RichTextEditorProps = Omit<React.ComponentPropsWithoutRef<"div">, "children" | "onChange" | "placeholder"> & {
|
|
7
48
|
/** Accessible name for the title field. */
|
|
8
49
|
titleLabel?: string;
|
|
@@ -10,21 +51,141 @@ export type RichTextEditorProps = Omit<React.ComponentPropsWithoutRef<"div">, "c
|
|
|
10
51
|
bodyLabel?: string;
|
|
11
52
|
/** Message shown when asking for a link URL. */
|
|
12
53
|
linkPromptLabel?: string;
|
|
54
|
+
/** Message shown when asking for an image URL. Attio uploads a file
|
|
55
|
+
* through its own storage; crisp is dependency-free, so this follows the
|
|
56
|
+
* same `window.prompt` pattern as `linkPromptLabel` rather than inventing
|
|
57
|
+
* an upload pipeline. */
|
|
58
|
+
imagePromptLabel?: string;
|
|
59
|
+
/** The text-color picker's trigger button — its visible label and
|
|
60
|
+
* accessible name (default "Text", matching Attio's own copy). */
|
|
61
|
+
textColorLabel?: string;
|
|
62
|
+
/** The highlight-color picker's trigger button (default "Highlight"). */
|
|
63
|
+
highlightColorLabel?: string;
|
|
64
|
+
/** aria-label for each picker's "clear" swatch. */
|
|
65
|
+
clearColorLabel?: string;
|
|
66
|
+
/** The block-type toolbar button — visible label and accessible name
|
|
67
|
+
* (default "Body", matching Attio's own copy for the current-block
|
|
68
|
+
* indicator, even though the seven choices behind it include far more
|
|
69
|
+
* than "Body"). */
|
|
70
|
+
blockMenuLabel?: string;
|
|
71
|
+
/** Placeholder for the block menu's search field, shown when it's opened
|
|
72
|
+
* from the toolbar (default "Search items…", matching Attio's own copy). */
|
|
73
|
+
blockMenuSearchPlaceholder?: string;
|
|
74
|
+
/** Shown when the search field matches nothing. */
|
|
75
|
+
blockMenuEmptyLabel?: string;
|
|
76
|
+
/** Character that opens the mention picker. Default `"@"`. */
|
|
77
|
+
mentionTrigger?: string;
|
|
78
|
+
/** Renders a consumer-supplied picker anchored at the caret when
|
|
79
|
+
* `mentionTrigger` is typed (#372, #428). crisp detects the trigger,
|
|
80
|
+
* measures where it sits, and inserts whatever is picked — the picker
|
|
81
|
+
* itself (avatars, grouping, a "create new" row) is the caller's, since
|
|
82
|
+
* that varies too much by app to have one measured shape. */
|
|
83
|
+
renderMentionPicker?: (state: RichTextMentionTriggerState) => React.ReactNode;
|
|
13
84
|
defaultTitle?: string;
|
|
14
85
|
/** Initial body HTML. */
|
|
15
86
|
defaultHtml?: string;
|
|
16
87
|
titlePlaceholder?: string;
|
|
17
88
|
placeholder?: string;
|
|
18
89
|
onChange?: (value: RichTextValue) => void;
|
|
90
|
+
/** Renders both fields as read-only — Attio's own note preview (the
|
|
91
|
+
* sidebar list, a record's Notes tab) is the SAME editor with
|
|
92
|
+
* `contentEditable` toggled off, not a separate stripped-text summary, so
|
|
93
|
+
* headings/lists/marks all survive into it. No toolbar renders in this
|
|
94
|
+
* mode. */
|
|
95
|
+
readOnly?: boolean;
|
|
19
96
|
className?: string;
|
|
20
97
|
};
|
|
21
98
|
/**
|
|
22
|
-
* A block rich-text editor — measured from
|
|
23
|
-
* a prose body (
|
|
24
|
-
*
|
|
99
|
+
* A block rich-text editor — measured from Attio's own notes editor. A large
|
|
100
|
+
* title, a prose body (h1/h2/h3, bulleted/numbered lists, an image block,
|
|
101
|
+
* marks), a floating selection toolbar, a searchable block-type menu, and a
|
|
102
|
+
* caret-anchored mention trigger. Built on contentEditable, dependency-free.
|
|
25
103
|
* Uncontrolled: seed with `defaultTitle`/`defaultHtml`, read via `onChange`.
|
|
104
|
+
* Imperative actions (`insertMention`, `focus`) go through a ref handle
|
|
105
|
+
* rather than a new prop each — the rest of the surface stays uncontrolled.
|
|
106
|
+
*
|
|
107
|
+
* **No underline, no inline code, no blockquote** — all three confirmed
|
|
108
|
+
* absent from Attio's live toolbar (7 controls) and its exhaustive 7-item
|
|
109
|
+
* block-type menu; the generic baseline this component used to ship
|
|
110
|
+
* overshot Attio on all three. `.crisp-rte-body blockquote` still renders
|
|
111
|
+
* correctly for content pasted in from elsewhere — only the control for it
|
|
112
|
+
* is gone.
|
|
113
|
+
*
|
|
114
|
+
* **The block menu's own chrome (356px, radius 12px, `elevation.floating`,
|
|
115
|
+
* a "Search items…" input, 7 rows at 52px with a 16px icon) was measured
|
|
116
|
+
* through the in-editor "Insert" button, not the toolbar's "Body ▾".**
|
|
117
|
+
* Clicking "Body ▾" itself was tried repeatedly, with both synthetic and
|
|
118
|
+
* real CDP-dispatched trusted clicks, single- and multi-step sessions, and
|
|
119
|
+
* consistently closed the ENTIRE note a fraction of a second after opening
|
|
120
|
+
* something (confirmed via a 0/50/150/400ms readback: the toolbar portal was
|
|
121
|
+
* still there at +50ms, everything was gone by +150ms) — a nested-popover
|
|
122
|
+
* dismissable-layer interaction synthetic input in this environment could
|
|
123
|
+
* not reliably drive. The Insert button opens the identical shape ("The
|
|
124
|
+
* same-shaped popover... is also what opens from the 'Body' button" — the
|
|
125
|
+
* source measurement's own finding, and Insert's own DOM confirms the exact
|
|
126
|
+
* same `role="dialog"`/search-input/`role="option"` structure), so the
|
|
127
|
+
* chrome below is that measurement, reused for both entry points. What's
|
|
128
|
+
* NOT independently confirmed is "Body ▾"'s own anchor side — Insert opens
|
|
129
|
+
* `data-side="right"` (it sits at the end of a line, with no room below);
|
|
130
|
+
* the toolbar sits at the TOP of the selection, so this component opens the
|
|
131
|
+
* menu below it, a reasoned default rather than a reading. The `/`-in-body
|
|
132
|
+
* trigger, and the "@" mention trigger, both anchor at the caret and do not
|
|
133
|
+
* steal focus from the body — the toolbar's own "Body ▾" click DOES focus a
|
|
134
|
+
* real search input, since there's no in-document query to read a filter
|
|
135
|
+
* from until one exists.
|
|
136
|
+
*
|
|
137
|
+
* Not built: Attio's own separate "Insert" trigger button (a third way to
|
|
138
|
+
* reach the identical menu, sitting at the end of the body's last line) —
|
|
139
|
+
* only the two entry points #426 asked for.
|
|
26
140
|
*/
|
|
27
|
-
export declare
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
141
|
+
export declare const RichTextEditor: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "onChange" | "placeholder"> & {
|
|
142
|
+
/** Accessible name for the title field. */
|
|
143
|
+
titleLabel?: string;
|
|
144
|
+
/** Accessible name for the body editor. */
|
|
145
|
+
bodyLabel?: string;
|
|
146
|
+
/** Message shown when asking for a link URL. */
|
|
147
|
+
linkPromptLabel?: string;
|
|
148
|
+
/** Message shown when asking for an image URL. Attio uploads a file
|
|
149
|
+
* through its own storage; crisp is dependency-free, so this follows the
|
|
150
|
+
* same `window.prompt` pattern as `linkPromptLabel` rather than inventing
|
|
151
|
+
* an upload pipeline. */
|
|
152
|
+
imagePromptLabel?: string;
|
|
153
|
+
/** The text-color picker's trigger button — its visible label and
|
|
154
|
+
* accessible name (default "Text", matching Attio's own copy). */
|
|
155
|
+
textColorLabel?: string;
|
|
156
|
+
/** The highlight-color picker's trigger button (default "Highlight"). */
|
|
157
|
+
highlightColorLabel?: string;
|
|
158
|
+
/** aria-label for each picker's "clear" swatch. */
|
|
159
|
+
clearColorLabel?: string;
|
|
160
|
+
/** The block-type toolbar button — visible label and accessible name
|
|
161
|
+
* (default "Body", matching Attio's own copy for the current-block
|
|
162
|
+
* indicator, even though the seven choices behind it include far more
|
|
163
|
+
* than "Body"). */
|
|
164
|
+
blockMenuLabel?: string;
|
|
165
|
+
/** Placeholder for the block menu's search field, shown when it's opened
|
|
166
|
+
* from the toolbar (default "Search items…", matching Attio's own copy). */
|
|
167
|
+
blockMenuSearchPlaceholder?: string;
|
|
168
|
+
/** Shown when the search field matches nothing. */
|
|
169
|
+
blockMenuEmptyLabel?: string;
|
|
170
|
+
/** Character that opens the mention picker. Default `"@"`. */
|
|
171
|
+
mentionTrigger?: string;
|
|
172
|
+
/** Renders a consumer-supplied picker anchored at the caret when
|
|
173
|
+
* `mentionTrigger` is typed (#372, #428). crisp detects the trigger,
|
|
174
|
+
* measures where it sits, and inserts whatever is picked — the picker
|
|
175
|
+
* itself (avatars, grouping, a "create new" row) is the caller's, since
|
|
176
|
+
* that varies too much by app to have one measured shape. */
|
|
177
|
+
renderMentionPicker?: (state: RichTextMentionTriggerState) => React.ReactNode;
|
|
178
|
+
defaultTitle?: string;
|
|
179
|
+
/** Initial body HTML. */
|
|
180
|
+
defaultHtml?: string;
|
|
181
|
+
titlePlaceholder?: string;
|
|
182
|
+
placeholder?: string;
|
|
183
|
+
onChange?: (value: RichTextValue) => void;
|
|
184
|
+
/** Renders both fields as read-only — Attio's own note preview (the
|
|
185
|
+
* sidebar list, a record's Notes tab) is the SAME editor with
|
|
186
|
+
* `contentEditable` toggled off, not a separate stripped-text summary, so
|
|
187
|
+
* headings/lists/marks all survive into it. No toolbar renders in this
|
|
188
|
+
* mode. */
|
|
189
|
+
readOnly?: boolean;
|
|
190
|
+
className?: string;
|
|
191
|
+
} & React.RefAttributes<RichTextEditorHandle>>;
|
|
@@ -11,6 +11,14 @@ export type SidebarNavItem = {
|
|
|
11
11
|
icon: React.ComponentType<IconProps>;
|
|
12
12
|
active?: boolean;
|
|
13
13
|
trailing?: React.ReactNode;
|
|
14
|
+
/** Either this or `onSelect` — a plain link, or a handler for anything
|
|
15
|
+
* that isn't real navigation. Both may be set; neither is required to
|
|
16
|
+
* make the row *something* clickable (it still renders as a link,
|
|
17
|
+
* defaulting `href` to "#"). Same shape as a `groups` row's
|
|
18
|
+
* `SidebarNavGroupItem` (#384) — `items` is the only place that used to
|
|
19
|
+
* be missing this wiring. */
|
|
20
|
+
href?: string;
|
|
21
|
+
onSelect?: () => void;
|
|
14
22
|
};
|
|
15
23
|
/** A row in the Records section — rendered as a tinted 20px glyph avatar. */
|
|
16
24
|
export type SidebarRecordItem = {
|
|
@@ -96,6 +104,20 @@ export type SidebarProps = React.ComponentPropsWithoutRef<"nav"> & {
|
|
|
96
104
|
onToggleCollapse?: () => void;
|
|
97
105
|
/** Workspace switcher content. Defaults to the measured workspace. */
|
|
98
106
|
workspace?: SidebarWorkspace;
|
|
107
|
+
/**
|
|
108
|
+
* Menu content for the workspace switcher — `MenuItem`/`MenuSeparator`/
|
|
109
|
+
* `MenuLabel` children, the same as a consumer would give `Menu` directly.
|
|
110
|
+
* Omit to leave the switcher a plain (still real, focusable) button with
|
|
111
|
+
* no popup, as before. When given, the switcher becomes a real menu
|
|
112
|
+
* trigger (`aria-haspopup="menu"`, `aria-expanded`, keyboard-openable —
|
|
113
|
+
* rents `Menu`'s own machine, no new one) that opens it — router-agnostic
|
|
114
|
+
* and consistent with the nav API (#384): a `MenuItem`'s own `onSelect` is
|
|
115
|
+
* how a consumer reaches its own navigation, the same as a nav row's
|
|
116
|
+
* (#415: Attio's switcher opens "Account settings" / "Workspace settings",
|
|
117
|
+
* among others — crisp ships no fixed items of its own, since which
|
|
118
|
+
* settings exist is entirely the consumer's).
|
|
119
|
+
*/
|
|
120
|
+
workspaceMenu?: React.ReactNode;
|
|
99
121
|
/** Main nav rows (Home, Tasks, …). Defaults to the measured nav. */
|
|
100
122
|
items?: SidebarNavItem[];
|
|
101
123
|
/** The Records section (label + glyph-avatar rows). */
|
|
@@ -114,8 +136,18 @@ export type SidebarProps = React.ComponentPropsWithoutRef<"nav"> & {
|
|
|
114
136
|
* renders exactly as before this prop existed.
|
|
115
137
|
*/
|
|
116
138
|
groups?: SidebarNavGroup[];
|
|
117
|
-
/**
|
|
118
|
-
|
|
139
|
+
/**
|
|
140
|
+
* The footer slot. Defaults to Attio's own onboarding pill + invite row +
|
|
141
|
+
* trial banner (`ATTIO_SIDEBAR_FOOTER`). Pass a `SidebarFooter` object to
|
|
142
|
+
* override just the strings in that fixed shape (as before), any other
|
|
143
|
+
* `ReactNode` — an account/user menu, say — to replace the slot's content
|
|
144
|
+
* entirely (still pinned to the bottom of the nav), or `false` to render
|
|
145
|
+
* no footer at all so a consumer can compose their own element directly
|
|
146
|
+
* below `<Sidebar>` instead (#408: GRC has no onboarding checklist, no
|
|
147
|
+
* invite flow and no trial banner, so none of the fixed copy had anything
|
|
148
|
+
* real to say, and there was no way to put a real account menu here).
|
|
149
|
+
*/
|
|
150
|
+
footer?: SidebarFooter | React.ReactNode;
|
|
119
151
|
/**
|
|
120
152
|
* Command-palette items, forwarded to the internal `Command`'s own
|
|
121
153
|
* `items` prop. Omit for Command's built-in Attio set (#364: GRC's
|
|
@@ -162,6 +194,20 @@ export declare const Sidebar: React.ForwardRefExoticComponent<Omit<React.Detaile
|
|
|
162
194
|
onToggleCollapse?: () => void;
|
|
163
195
|
/** Workspace switcher content. Defaults to the measured workspace. */
|
|
164
196
|
workspace?: SidebarWorkspace;
|
|
197
|
+
/**
|
|
198
|
+
* Menu content for the workspace switcher — `MenuItem`/`MenuSeparator`/
|
|
199
|
+
* `MenuLabel` children, the same as a consumer would give `Menu` directly.
|
|
200
|
+
* Omit to leave the switcher a plain (still real, focusable) button with
|
|
201
|
+
* no popup, as before. When given, the switcher becomes a real menu
|
|
202
|
+
* trigger (`aria-haspopup="menu"`, `aria-expanded`, keyboard-openable —
|
|
203
|
+
* rents `Menu`'s own machine, no new one) that opens it — router-agnostic
|
|
204
|
+
* and consistent with the nav API (#384): a `MenuItem`'s own `onSelect` is
|
|
205
|
+
* how a consumer reaches its own navigation, the same as a nav row's
|
|
206
|
+
* (#415: Attio's switcher opens "Account settings" / "Workspace settings",
|
|
207
|
+
* among others — crisp ships no fixed items of its own, since which
|
|
208
|
+
* settings exist is entirely the consumer's).
|
|
209
|
+
*/
|
|
210
|
+
workspaceMenu?: React.ReactNode;
|
|
165
211
|
/** Main nav rows (Home, Tasks, …). Defaults to the measured nav. */
|
|
166
212
|
items?: SidebarNavItem[];
|
|
167
213
|
/** The Records section (label + glyph-avatar rows). */
|
|
@@ -180,8 +226,18 @@ export declare const Sidebar: React.ForwardRefExoticComponent<Omit<React.Detaile
|
|
|
180
226
|
* renders exactly as before this prop existed.
|
|
181
227
|
*/
|
|
182
228
|
groups?: SidebarNavGroup[];
|
|
183
|
-
/**
|
|
184
|
-
|
|
229
|
+
/**
|
|
230
|
+
* The footer slot. Defaults to Attio's own onboarding pill + invite row +
|
|
231
|
+
* trial banner (`ATTIO_SIDEBAR_FOOTER`). Pass a `SidebarFooter` object to
|
|
232
|
+
* override just the strings in that fixed shape (as before), any other
|
|
233
|
+
* `ReactNode` — an account/user menu, say — to replace the slot's content
|
|
234
|
+
* entirely (still pinned to the bottom of the nav), or `false` to render
|
|
235
|
+
* no footer at all so a consumer can compose their own element directly
|
|
236
|
+
* below `<Sidebar>` instead (#408: GRC has no onboarding checklist, no
|
|
237
|
+
* invite flow and no trial banner, so none of the fixed copy had anything
|
|
238
|
+
* real to say, and there was no way to put a real account menu here).
|
|
239
|
+
*/
|
|
240
|
+
footer?: SidebarFooter | React.ReactNode;
|
|
185
241
|
/**
|
|
186
242
|
* Command-palette items, forwarded to the internal `Command`'s own
|
|
187
243
|
* `items` prop. Omit for Command's built-in Attio set (#364: GRC's
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crisp-ui-kit/crisp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"description": "A lean React design system, measured pixel-for-pixel from Attio.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -98,6 +98,11 @@
|
|
|
98
98
|
"import": "./dist/esm/components/columncalc/index.js",
|
|
99
99
|
"require": "./dist/cjs/components/columncalc/index.js"
|
|
100
100
|
},
|
|
101
|
+
"./composewindow": {
|
|
102
|
+
"types": "./dist/types/components/composewindow/index.d.ts",
|
|
103
|
+
"import": "./dist/esm/components/composewindow/index.js",
|
|
104
|
+
"require": "./dist/cjs/components/composewindow/index.js"
|
|
105
|
+
},
|
|
101
106
|
"./contextmenu": {
|
|
102
107
|
"types": "./dist/types/components/contextmenu/index.d.ts",
|
|
103
108
|
"import": "./dist/esm/components/contextmenu/index.js",
|