@copilotkit/react-textarea 1.81.0 → 1.82.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/index.cjs +2 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2 -5
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +2 -5
- package/dist/index.umd.js.map +1 -1
- package/package.json +4 -4
- package/src/lib/editor-to-text.test.ts +60 -0
- package/src/lib/editor-to-text.ts +17 -9
- package/src/lib/slatejs-edits/replace-text.test.ts +56 -0
- package/src/lib/slatejs-edits/replace-text.ts +8 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/react-textarea",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.82.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"slate-history": "^0.93.0",
|
|
60
60
|
"slate-react": "^0.98.1",
|
|
61
61
|
"tailwind-merge": "^1.13.2",
|
|
62
|
-
"@copilotkit/
|
|
63
|
-
"@copilotkit/
|
|
64
|
-
"@copilotkit/
|
|
62
|
+
"@copilotkit/runtime-client-gql": "1.82.0",
|
|
63
|
+
"@copilotkit/react-core": "1.82.0",
|
|
64
|
+
"@copilotkit/shared": "1.82.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/lodash.merge": "^4.6.7",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Descendant } from "slate";
|
|
2
|
+
import { createEditor } from "slate";
|
|
3
|
+
import { editorToText } from "./editor-to-text";
|
|
4
|
+
import { getFullEditorTextWithNewlines } from "./get-text-around-cursor";
|
|
5
|
+
|
|
6
|
+
const editorWith = (children: any[]) => {
|
|
7
|
+
const editor = createEditor();
|
|
8
|
+
editor.children = children as Descendant[];
|
|
9
|
+
return editor;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe("editorToText", () => {
|
|
13
|
+
it("does not insert newlines between text nodes inside one block", () => {
|
|
14
|
+
const editor = editorWith([
|
|
15
|
+
{
|
|
16
|
+
type: "paragraph",
|
|
17
|
+
children: [
|
|
18
|
+
{ text: "Hello " },
|
|
19
|
+
{
|
|
20
|
+
type: "suggestion",
|
|
21
|
+
inline: true,
|
|
22
|
+
content: "SUGGESTED",
|
|
23
|
+
children: [{ text: "" }],
|
|
24
|
+
},
|
|
25
|
+
{ text: "world" },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
expect(editorToText(editor)).toBe("Hello world");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("agrees with getFullEditorTextWithNewlines on a split block", () => {
|
|
34
|
+
const editor = editorWith([
|
|
35
|
+
{
|
|
36
|
+
type: "paragraph",
|
|
37
|
+
children: [{ text: "Hello " }, { text: "world" }],
|
|
38
|
+
},
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
expect(editorToText(editor)).toBe(getFullEditorTextWithNewlines(editor));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("still separates blocks with a newline", () => {
|
|
45
|
+
const editor = editorWith([
|
|
46
|
+
{ type: "paragraph", children: [{ text: "one" }] },
|
|
47
|
+
{ type: "paragraph", children: [{ text: "two" }] },
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
expect(editorToText(editor)).toBe("one\ntwo");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("reads a single unsplit block unchanged", () => {
|
|
54
|
+
const editor = editorWith([
|
|
55
|
+
{ type: "paragraph", children: [{ text: "Hello world" }] },
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
expect(editorToText(editor)).toBe("Hello world");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { BaseEditor, Descendant
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { BaseEditor, Descendant } from "slate";
|
|
2
|
+
import { Element } from "slate";
|
|
3
|
+
import type { HistoryEditor } from "slate-history";
|
|
4
|
+
import type { ReactEditor } from "slate-react";
|
|
5
|
+
import type { SuggestionAwareText } from "../types/base/custom-editor";
|
|
5
6
|
|
|
6
7
|
function nodeChildrenToTextComponents(
|
|
7
8
|
editor: BaseEditor & ReactEditor & HistoryEditor,
|
|
@@ -56,9 +57,16 @@ function nodeChildrenToTextComponents(
|
|
|
56
57
|
export const editorToText = (
|
|
57
58
|
editor: BaseEditor & ReactEditor & HistoryEditor,
|
|
58
59
|
) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
// Join blocks with a newline, but never join the text nodes *inside* a block
|
|
61
|
+
// with one: Slate splits a single paragraph's text into several nodes whenever
|
|
62
|
+
// an inline void (a suggestion) or a leaf mark (bold) sits in the middle, and
|
|
63
|
+
// joining those with "\n" injected a phantom line break that the sibling
|
|
64
|
+
// `getFullEditorTextWithNewlines` does not produce for the same document.
|
|
65
|
+
return editor.children
|
|
66
|
+
.map((node) =>
|
|
67
|
+
nodeChildrenToTextComponents(editor, [node])
|
|
68
|
+
.map((textComponent) => textComponent.text)
|
|
69
|
+
.join(""),
|
|
70
|
+
)
|
|
71
|
+
.join("\n");
|
|
64
72
|
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createEditor, Editor, Transforms } from "slate";
|
|
2
|
+
import { replaceEditorText } from "./replace-text";
|
|
3
|
+
import { getFullEditorTextWithNewlines } from "../get-text-around-cursor";
|
|
4
|
+
|
|
5
|
+
const seedEditor = () => {
|
|
6
|
+
const editor = createEditor();
|
|
7
|
+
editor.children = [
|
|
8
|
+
{ type: "paragraph", children: [{ text: "seed" }] } as any,
|
|
9
|
+
];
|
|
10
|
+
Transforms.select(editor, { path: [0, 0], offset: 4 });
|
|
11
|
+
return editor;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe("replaceEditorText", () => {
|
|
15
|
+
it("fills the cleared block instead of adding a second one", () => {
|
|
16
|
+
const editor = seedEditor();
|
|
17
|
+
|
|
18
|
+
replaceEditorText(editor, "hello");
|
|
19
|
+
|
|
20
|
+
expect(editor.children).toHaveLength(1);
|
|
21
|
+
expect(getFullEditorTextWithNewlines(editor)).toBe("hello");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("round-trips the exact value it was given", () => {
|
|
25
|
+
const editor = seedEditor();
|
|
26
|
+
|
|
27
|
+
replaceEditorText(editor, "hello");
|
|
28
|
+
expect(getFullEditorTextWithNewlines(editor)).toBe("hello");
|
|
29
|
+
|
|
30
|
+
replaceEditorText(editor, "goodbye");
|
|
31
|
+
expect(editor.children).toHaveLength(1);
|
|
32
|
+
expect(getFullEditorTextWithNewlines(editor)).toBe("goodbye");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("replaces a multi-block document with a single block", () => {
|
|
36
|
+
const editor = createEditor();
|
|
37
|
+
editor.children = [
|
|
38
|
+
{ type: "paragraph", children: [{ text: "one" }] } as any,
|
|
39
|
+
{ type: "paragraph", children: [{ text: "two" }] } as any,
|
|
40
|
+
];
|
|
41
|
+
Transforms.select(editor, Editor.end(editor, []));
|
|
42
|
+
|
|
43
|
+
replaceEditorText(editor, "fresh");
|
|
44
|
+
|
|
45
|
+
expect(editor.children).toHaveLength(1);
|
|
46
|
+
expect(getFullEditorTextWithNewlines(editor)).toBe("fresh");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("still leaves the document empty when given an empty string", () => {
|
|
50
|
+
const editor = seedEditor();
|
|
51
|
+
|
|
52
|
+
replaceEditorText(editor, "");
|
|
53
|
+
|
|
54
|
+
expect(getFullEditorTextWithNewlines(editor)).toBe("");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -11,18 +11,13 @@ export function replaceEditorText(editor: Editor, newText: string) {
|
|
|
11
11
|
|
|
12
12
|
// insert new text
|
|
13
13
|
if (newText && newText !== "") {
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
],
|
|
23
|
-
{
|
|
24
|
-
at: [0],
|
|
25
|
-
},
|
|
26
|
-
);
|
|
14
|
+
// Don't insert empty text - results in strange visual behavior.
|
|
15
|
+
// Insert into the empty block the delete above left behind rather than
|
|
16
|
+
// adding a new one: `insertNodes` at [0] would prepend a second block and
|
|
17
|
+
// leave a trailing empty paragraph, so the text would read back with a
|
|
18
|
+
// trailing newline and grow on every call.
|
|
19
|
+
Transforms.insertText(editor, newText, {
|
|
20
|
+
at: Editor.start(editor, []),
|
|
21
|
+
});
|
|
27
22
|
}
|
|
28
23
|
}
|