@crisp-ui-kit/crisp 0.51.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/core/caret-rect.js +73 -0
- package/dist/cjs/core/index.js +7 -1
- package/dist/cjs/core/mention.js +32 -0
- package/dist/cjs/core/use-mention-trigger.js +124 -0
- package/dist/cjs/product/recordpanel/recordpanel.js +13 -81
- package/dist/cjs/product/recordpanel/recordpanel.recipe.js +53 -44
- package/dist/cjs/product/recordstable/editable-field.js +11 -8
- 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/esm/core/caret-rect.js +70 -0
- package/dist/esm/core/index.js +3 -0
- package/dist/esm/core/mention.js +29 -0
- package/dist/esm/core/use-mention-trigger.js +88 -0
- package/dist/esm/product/recordpanel/index.js +1 -1
- package/dist/esm/product/recordpanel/recordpanel.js +15 -83
- package/dist/esm/product/recordpanel/recordpanel.recipe.js +54 -45
- package/dist/esm/product/recordstable/editable-field.js +11 -8
- 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/recordpanel.css +47 -41
- package/dist/recordpanel.layered.css +47 -41
- package/dist/richtext.css +31 -5
- package/dist/richtext.layered.css +31 -5
- package/dist/styles.css +79 -47
- package/dist/styles.layered.css +79 -47
- package/dist/types/core/caret-rect.d.ts +16 -0
- package/dist/types/core/index.d.ts +3 -0
- package/dist/types/core/mention.d.ts +27 -0
- package/dist/types/core/use-mention-trigger.d.ts +41 -0
- package/dist/types/product/recordpanel/index.d.ts +1 -1
- package/dist/types/product/recordpanel/recordpanel.d.ts +81 -27
- package/dist/types/product/recordstable/editable-field.d.ts +11 -8
- 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/package.json +1 -1
|
@@ -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>>;
|