@fluentui-copilot/chat-input-plugins 0.4.2-hotfix.2 → 0.4.2-hotfix.3
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/CHANGELOG.json +4 -4
- package/CHANGELOG.md +5 -5
- package/lib/BasicFunctionality/BasicFunctionality.base.js +92 -92
- package/lib/BasicFunctionality/SentinelNode.js +30 -29
- package/lib/BasicFunctionality/SentinelNodeHandlers.js +78 -73
- package/lib/BasicFunctionality/index.js +1 -0
- package/lib/ChatInputEntity/ChatInputEntityPlugin.base.js +114 -109
- package/lib/ChatInputEntity/ChatInputEntityPlugin.types.js +2 -1
- package/lib/ChatInputEntity/index.js +1 -0
- package/lib/GhostText/GhostText.base.js +145 -142
- package/lib/GhostText/index.js +1 -0
- package/lib/ImperativeControl/ImperativeControl.base.js +83 -82
- package/lib/ImperativeControl/index.js +1 -0
- package/lib/ManualGhostText/ManualGhostText.base.js +67 -68
- package/lib/ManualGhostText/index.js +1 -0
- package/lib/PasteUnfurling/PasteUnfurling.base.js +57 -52
- package/lib/PasteUnfurling/PasteUnfurling.types.js +2 -1
- package/lib/PasteUnfurling/PasteUnfurlingTestUtils.js +139 -138
- package/lib/PasteUnfurling/index.js +1 -0
- package/lib/index.js +1 -0
- package/lib-commonjs/BasicFunctionality/BasicFunctionality.base.js +3 -2
- package/lib-commonjs/BasicFunctionality/BasicFunctionality.base.js.map +1 -1
- package/lib-commonjs/BasicFunctionality/SentinelNode.js +1 -1
- package/lib-commonjs/BasicFunctionality/SentinelNode.js.map +1 -1
- package/lib-commonjs/BasicFunctionality/SentinelNodeHandlers.js +5 -3
- package/lib-commonjs/BasicFunctionality/SentinelNodeHandlers.js.map +1 -1
- package/lib-commonjs/BasicFunctionality/index.js +1 -0
- package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.base.js +5 -3
- package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.base.js.map +1 -1
- package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.types.js +1 -0
- package/lib-commonjs/ChatInputEntity/index.js +1 -0
- package/lib-commonjs/GhostText/GhostText.base.js +3 -2
- package/lib-commonjs/GhostText/GhostText.base.js.map +1 -1
- package/lib-commonjs/GhostText/index.js +1 -0
- package/lib-commonjs/ImperativeControl/ImperativeControl.base.js +1 -1
- package/lib-commonjs/ImperativeControl/ImperativeControl.base.js.map +1 -1
- package/lib-commonjs/ImperativeControl/index.js +1 -0
- package/lib-commonjs/ManualGhostText/ManualGhostText.base.js +1 -1
- package/lib-commonjs/ManualGhostText/ManualGhostText.base.js.map +1 -1
- package/lib-commonjs/ManualGhostText/index.js +1 -0
- package/lib-commonjs/PasteUnfurling/PasteUnfurling.base.js +1 -1
- package/lib-commonjs/PasteUnfurling/PasteUnfurling.base.js.map +1 -1
- package/lib-commonjs/PasteUnfurling/PasteUnfurling.types.js +1 -0
- package/lib-commonjs/PasteUnfurling/PasteUnfurlingTestUtils.js +1 -1
- package/lib-commonjs/PasteUnfurling/PasteUnfurlingTestUtils.js.map +1 -1
- package/lib-commonjs/PasteUnfurling/index.js +1 -0
- package/lib-commonjs/index.js +1 -0
- package/package.json +2 -2
|
@@ -1,117 +1,122 @@
|
|
|
1
1
|
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
2
|
import { $createParagraphNode, $createTextNode, $getNodeByKey, $getSelection, $insertNodes, $isDecoratorNode, $isRangeSelection, $isRootOrShadowRoot, $nodesOfType, $wrapNodeInElement, COMMAND_PRIORITY_CRITICAL, DELETE_CHARACTER_COMMAND, mergeRegister } from '@fluentui-copilot/text-editor';
|
|
3
3
|
export class ChatInputEntityPluginBase {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
cleanup() {
|
|
5
|
+
this._cleanup();
|
|
6
|
+
}
|
|
7
|
+
insertChatInputEntity(props) {
|
|
8
|
+
let key = undefined;
|
|
9
|
+
this.__editor.update(() => {
|
|
10
|
+
const {
|
|
11
|
+
text,
|
|
12
|
+
data,
|
|
13
|
+
entityProps
|
|
14
|
+
} = props;
|
|
15
|
+
const entityNode = this.__$createNode(this.__id, text, data, entityProps);
|
|
16
|
+
$insertNodes([entityNode]);
|
|
17
|
+
entityNode.selectEnd();
|
|
18
|
+
if ($isRootOrShadowRoot(entityNode.getParentOrThrow())) {
|
|
19
|
+
$wrapNodeInElement(entityNode, $createParagraphNode).selectEnd();
|
|
20
|
+
}
|
|
21
|
+
key = entityNode.getKey();
|
|
22
|
+
});
|
|
23
|
+
return key;
|
|
24
|
+
}
|
|
25
|
+
removeChatInputEntity(keyOrPredicate) {
|
|
26
|
+
this.__editor.update(() => {
|
|
27
|
+
if (typeof keyOrPredicate === 'function') {
|
|
28
|
+
$nodesOfType(this.__nodeClass).filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i)).forEach(node => node.remove());
|
|
29
|
+
} else {
|
|
30
|
+
var _$getNodeByKey;
|
|
31
|
+
(_$getNodeByKey = $getNodeByKey(keyOrPredicate)) === null || _$getNodeByKey === void 0 ? void 0 : _$getNodeByKey.remove();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
updateChatInputEntityProps(keyOrPredicate, props) {
|
|
36
|
+
const updateNode = node => {
|
|
37
|
+
const newProps = typeof props === 'function' ? props(node.getEntityData()) : props;
|
|
38
|
+
node.updateEntityData(newProps);
|
|
39
|
+
};
|
|
40
|
+
this.__editor.update(() => {
|
|
41
|
+
if (typeof keyOrPredicate === 'function') {
|
|
42
|
+
$nodesOfType(this.__nodeClass).filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i)).forEach(updateNode);
|
|
43
|
+
} else {
|
|
44
|
+
const node = $getNodeByKey(keyOrPredicate);
|
|
45
|
+
if (node) {
|
|
46
|
+
updateNode(node);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}, {
|
|
50
|
+
tag: 'historic'
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
getActiveEntities() {
|
|
54
|
+
return this.__editor.getEditorState().read(() => $nodesOfType(this.__nodeClass).filter(node => node.__pluginId === this.__id).map(node => node.getEntityData()));
|
|
55
|
+
}
|
|
56
|
+
constructor(editor, id, nodeClass, $createNode, $isChatInputEntityNode, onChatInputEntityAdded, onChatInputEntityDeleted) {
|
|
57
|
+
_define_property(this, "__nodeClass", void 0);
|
|
58
|
+
_define_property(this, "__editor", void 0);
|
|
59
|
+
_define_property(this, "__id", void 0);
|
|
60
|
+
_define_property(this, "__deleteDirection", null);
|
|
61
|
+
_define_property(this, "__$createNode", void 0);
|
|
62
|
+
_define_property(this, "_cleanup", void 0);
|
|
63
|
+
this.__$createNode = $createNode;
|
|
64
|
+
this.__editor = editor;
|
|
65
|
+
this.__id = id;
|
|
66
|
+
this.__nodeClass = nodeClass;
|
|
67
|
+
this._cleanup = mergeRegister(
|
|
68
|
+
// Keep track of delete direction so we know where to put the selection after adding back a space
|
|
69
|
+
editor.registerCommand(DELETE_CHARACTER_COMMAND, isBackward => {
|
|
70
|
+
this.__deleteDirection = isBackward ? 'backward' : 'forward';
|
|
71
|
+
return false;
|
|
72
|
+
}, COMMAND_PRIORITY_CRITICAL),
|
|
73
|
+
// Always maintain a space before, after, and between entities in order for selection to work properly
|
|
74
|
+
editor.registerNodeTransform(this.__nodeClass, node => {
|
|
75
|
+
const nextSibling = node.getNextSibling();
|
|
76
|
+
if (!nextSibling || $isDecoratorNode(nextSibling)) {
|
|
77
|
+
const selection = $getSelection();
|
|
78
|
+
// If selection is between the two nodes, that means the user is trying to delete the space
|
|
79
|
+
// If they deleted to the left, we should move the cursor to the end of the entity
|
|
80
|
+
// If they delete to the right, we should move the cursor to the end of the newly added space
|
|
81
|
+
// This mimics changing the delete into a cursor move action
|
|
82
|
+
const shouldMoveSelection = selection && $isRangeSelection(selection) && selection.isCollapsed() && selection.anchor.offset === node.getIndexWithinParent() + 1;
|
|
83
|
+
const text = $createTextNode(' ');
|
|
84
|
+
node.insertAfter(text);
|
|
85
|
+
if (shouldMoveSelection) {
|
|
86
|
+
if (this.__deleteDirection === 'forward') {
|
|
87
|
+
text.selectEnd();
|
|
88
|
+
} else {
|
|
89
|
+
node.selectEnd();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// In the case the entity is the first node, we need a space before it.
|
|
94
|
+
if (!node.getPreviousSibling()) {
|
|
95
|
+
const text = $createTextNode(' ');
|
|
96
|
+
node.insertBefore(text);
|
|
97
|
+
}
|
|
98
|
+
}), onChatInputEntityAdded || onChatInputEntityDeleted ? editor.registerMutationListener(this.__nodeClass, (nodes, payload) => {
|
|
99
|
+
for (const [nodeKey, mutation] of nodes) {
|
|
100
|
+
if (onChatInputEntityDeleted && mutation === 'destroyed') {
|
|
101
|
+
payload.prevEditorState.read(() => {
|
|
102
|
+
const node = $getNodeByKey(nodeKey);
|
|
103
|
+
if ($isChatInputEntityNode(node) && node.__pluginId === id) {
|
|
104
|
+
onChatInputEntityDeleted(node.getEntityData(), nodeKey);
|
|
18
105
|
}
|
|
19
|
-
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (typeof keyOrPredicate === 'function') {
|
|
26
|
-
$nodesOfType(this.__nodeClass).filter((node, i)=>node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i)).forEach((node)=>node.remove());
|
|
27
|
-
} else {
|
|
28
|
-
var _$getNodeByKey;
|
|
29
|
-
(_$getNodeByKey = $getNodeByKey(keyOrPredicate)) === null || _$getNodeByKey === void 0 ? void 0 : _$getNodeByKey.remove();
|
|
106
|
+
});
|
|
107
|
+
} else if (onChatInputEntityAdded && mutation === 'created') {
|
|
108
|
+
editor.getEditorState().read(() => {
|
|
109
|
+
const node = $getNodeByKey(nodeKey);
|
|
110
|
+
if ($isChatInputEntityNode(node) && node.__pluginId === id) {
|
|
111
|
+
onChatInputEntityAdded(node.getEntityData(), nodeKey);
|
|
30
112
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
node.updateEntityData(newProps);
|
|
37
|
-
};
|
|
38
|
-
this.__editor.update(()=>{
|
|
39
|
-
if (typeof keyOrPredicate === 'function') {
|
|
40
|
-
$nodesOfType(this.__nodeClass).filter((node, i)=>node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i)).forEach(updateNode);
|
|
41
|
-
} else {
|
|
42
|
-
const node = $getNodeByKey(keyOrPredicate);
|
|
43
|
-
if (node) {
|
|
44
|
-
updateNode(node);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}, {
|
|
48
|
-
tag: 'historic'
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
getActiveEntities() {
|
|
52
|
-
return this.__editor.getEditorState().read(()=>$nodesOfType(this.__nodeClass).filter((node)=>node.__pluginId === this.__id).map((node)=>node.getEntityData()));
|
|
53
|
-
}
|
|
54
|
-
constructor(editor, id, nodeClass, $createNode, $isChatInputEntityNode, onChatInputEntityAdded, onChatInputEntityDeleted){
|
|
55
|
-
_define_property(this, "__nodeClass", void 0);
|
|
56
|
-
_define_property(this, "__editor", void 0);
|
|
57
|
-
_define_property(this, "__id", void 0);
|
|
58
|
-
_define_property(this, "__deleteDirection", null);
|
|
59
|
-
_define_property(this, "__$createNode", void 0);
|
|
60
|
-
_define_property(this, "_cleanup", void 0);
|
|
61
|
-
this.__$createNode = $createNode;
|
|
62
|
-
this.__editor = editor;
|
|
63
|
-
this.__id = id;
|
|
64
|
-
this.__nodeClass = nodeClass;
|
|
65
|
-
this._cleanup = mergeRegister(// Keep track of delete direction so we know where to put the selection after adding back a space
|
|
66
|
-
editor.registerCommand(DELETE_CHARACTER_COMMAND, (isBackward)=>{
|
|
67
|
-
this.__deleteDirection = isBackward ? 'backward' : 'forward';
|
|
68
|
-
return false;
|
|
69
|
-
}, COMMAND_PRIORITY_CRITICAL), // Always maintain a space before, after, and between entities in order for selection to work properly
|
|
70
|
-
editor.registerNodeTransform(this.__nodeClass, (node)=>{
|
|
71
|
-
const nextSibling = node.getNextSibling();
|
|
72
|
-
if (!nextSibling || $isDecoratorNode(nextSibling)) {
|
|
73
|
-
const selection = $getSelection();
|
|
74
|
-
// If selection is between the two nodes, that means the user is trying to delete the space
|
|
75
|
-
// If they deleted to the left, we should move the cursor to the end of the entity
|
|
76
|
-
// If they delete to the right, we should move the cursor to the end of the newly added space
|
|
77
|
-
// This mimics changing the delete into a cursor move action
|
|
78
|
-
const shouldMoveSelection = selection && $isRangeSelection(selection) && selection.isCollapsed() && selection.anchor.offset === node.getIndexWithinParent() + 1;
|
|
79
|
-
const text = $createTextNode(' ');
|
|
80
|
-
node.insertAfter(text);
|
|
81
|
-
if (shouldMoveSelection) {
|
|
82
|
-
if (this.__deleteDirection === 'forward') {
|
|
83
|
-
text.selectEnd();
|
|
84
|
-
} else {
|
|
85
|
-
node.selectEnd();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// In the case the entity is the first node, we need a space before it.
|
|
90
|
-
if (!node.getPreviousSibling()) {
|
|
91
|
-
const text = $createTextNode(' ');
|
|
92
|
-
node.insertBefore(text);
|
|
93
|
-
}
|
|
94
|
-
}), onChatInputEntityAdded || onChatInputEntityDeleted ? editor.registerMutationListener(this.__nodeClass, (nodes, payload)=>{
|
|
95
|
-
for (const [nodeKey, mutation] of nodes){
|
|
96
|
-
if (onChatInputEntityDeleted && mutation === 'destroyed') {
|
|
97
|
-
payload.prevEditorState.read(()=>{
|
|
98
|
-
const node = $getNodeByKey(nodeKey);
|
|
99
|
-
if ($isChatInputEntityNode(node) && node.__pluginId === id) {
|
|
100
|
-
onChatInputEntityDeleted(node.getEntityData(), nodeKey);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
} else if (onChatInputEntityAdded && mutation === 'created') {
|
|
104
|
-
editor.getEditorState().read(()=>{
|
|
105
|
-
const node = $getNodeByKey(nodeKey);
|
|
106
|
-
if ($isChatInputEntityNode(node) && node.__pluginId === id) {
|
|
107
|
-
onChatInputEntityAdded(node.getEntityData(), nodeKey);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}) : noop);
|
|
113
|
-
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}) : noop);
|
|
117
|
+
}
|
|
114
118
|
}
|
|
115
119
|
function noop() {
|
|
116
|
-
|
|
120
|
+
return;
|
|
117
121
|
}
|
|
122
|
+
//# sourceMappingURL=ChatInputEntityPlugin.base.js.map
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=ChatInputEntityPlugin.types.js.map
|
|
@@ -2,157 +2,160 @@ import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
|
2
2
|
import { $createTextNode, $getNodeByKey, $getSelection, $isRangeSelection, $isTextNode, $setSelection, COMMAND_PRIORITY_LOW, KEY_TAB_COMMAND, mergeRegister } from '@fluentui-copilot/text-editor';
|
|
3
3
|
import { $isSentinelNode } from '../BasicFunctionality';
|
|
4
4
|
export class GhostTextPluginBase {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
cleanup() {
|
|
6
|
+
var _this___cleanup, _this;
|
|
7
|
+
(_this___cleanup = (_this = this).__cleanup) === null || _this___cleanup === void 0 ? void 0 : _this___cleanup.call(_this);
|
|
8
|
+
}
|
|
9
|
+
setExposeText(exposeText) {
|
|
10
|
+
this.__exposeText = exposeText;
|
|
11
|
+
}
|
|
12
|
+
setComponentProps(componentProps) {
|
|
13
|
+
this.__componentProps = componentProps;
|
|
14
|
+
}
|
|
15
|
+
setGetGhostText($getGhostText) {
|
|
16
|
+
this.__$getGhostText = $getGhostText;
|
|
17
|
+
}
|
|
18
|
+
setAllowCompletion(allowCompletion) {
|
|
19
|
+
this.__allowCompletion = allowCompletion;
|
|
20
|
+
}
|
|
21
|
+
constructor(editor, id, $getGhostText, nodeClass, createNode, componentProps,
|
|
22
|
+
// Whether or not the ghost text should count as text inside the input for submitting and character count
|
|
23
|
+
exposeText, allowCompletion) {
|
|
24
|
+
_define_property(this, "__id", void 0);
|
|
25
|
+
_define_property(this, "__$getGhostText", void 0);
|
|
26
|
+
_define_property(this, "__componentProps", void 0);
|
|
27
|
+
_define_property(this, "__exposeText", void 0);
|
|
28
|
+
_define_property(this, "__allowCompletion", void 0);
|
|
29
|
+
_define_property(this, "__cleanup", void 0);
|
|
30
|
+
this.__id = id;
|
|
31
|
+
this.__$getGhostText = $getGhostText;
|
|
32
|
+
this.__componentProps = componentProps;
|
|
33
|
+
this.__exposeText = exposeText;
|
|
34
|
+
this.__allowCompletion = allowCompletion;
|
|
35
|
+
let ghostTextNodeKey = null;
|
|
36
|
+
let lastText = undefined;
|
|
37
|
+
let justRemovedGhostText = false;
|
|
38
|
+
let justAddedGhostText = false;
|
|
39
|
+
function $clearGhostText() {
|
|
40
|
+
const ghostTextNode = ghostTextNodeKey !== null ? $getNodeByKey(ghostTextNodeKey) : null;
|
|
41
|
+
ghostTextNodeKey = null;
|
|
42
|
+
lastText = undefined;
|
|
43
|
+
if (ghostTextNode && ghostTextNode.isAttached()) {
|
|
44
|
+
ghostTextNode.remove();
|
|
45
|
+
justRemovedGhostText = true;
|
|
46
|
+
}
|
|
8
47
|
}
|
|
9
|
-
|
|
10
|
-
|
|
48
|
+
function handleGhostTextNodeTransform(node) {
|
|
49
|
+
const key = node.getKey();
|
|
50
|
+
if (node.__id === id && key !== ghostTextNodeKey) {
|
|
51
|
+
// Only one ghost text
|
|
52
|
+
node.remove();
|
|
53
|
+
$clearGhostText();
|
|
54
|
+
}
|
|
11
55
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
constructor(editor, id, $getGhostText, nodeClass, createNode, componentProps, // Whether or not the ghost text should count as text inside the input for submitting and character count
|
|
22
|
-
exposeText, allowCompletion){
|
|
23
|
-
_define_property(this, "__id", void 0);
|
|
24
|
-
_define_property(this, "__$getGhostText", void 0);
|
|
25
|
-
_define_property(this, "__componentProps", void 0);
|
|
26
|
-
_define_property(this, "__exposeText", void 0);
|
|
27
|
-
_define_property(this, "__allowCompletion", void 0);
|
|
28
|
-
_define_property(this, "__cleanup", void 0);
|
|
29
|
-
this.__id = id;
|
|
30
|
-
this.__$getGhostText = $getGhostText;
|
|
31
|
-
this.__componentProps = componentProps;
|
|
32
|
-
this.__exposeText = exposeText;
|
|
33
|
-
this.__allowCompletion = allowCompletion;
|
|
34
|
-
let ghostTextNodeKey = null;
|
|
35
|
-
let lastText = undefined;
|
|
36
|
-
let justRemovedGhostText = false;
|
|
37
|
-
let justAddedGhostText = false;
|
|
38
|
-
function $clearGhostText() {
|
|
39
|
-
const ghostTextNode = ghostTextNodeKey !== null ? $getNodeByKey(ghostTextNodeKey) : null;
|
|
40
|
-
ghostTextNodeKey = null;
|
|
41
|
-
lastText = undefined;
|
|
42
|
-
if (ghostTextNode && ghostTextNode.isAttached()) {
|
|
43
|
-
ghostTextNode.remove();
|
|
44
|
-
justRemovedGhostText = true;
|
|
45
|
-
}
|
|
56
|
+
const handleGhostTextResponse = text => {
|
|
57
|
+
if (text === lastText) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
editor.update(() => {
|
|
61
|
+
$clearGhostText();
|
|
62
|
+
const selection = $getSelection();
|
|
63
|
+
if (!text || !selection) {
|
|
64
|
+
return;
|
|
46
65
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
const selectionCopy = selection.clone();
|
|
67
|
+
const node = createNode(this.__id, text, this.__exposeText, this.__componentProps);
|
|
68
|
+
ghostTextNodeKey = node.getKey();
|
|
69
|
+
lastText = text;
|
|
70
|
+
selection.insertNodes([node]);
|
|
71
|
+
$setSelection(selectionCopy);
|
|
72
|
+
justAddedGhostText = true;
|
|
73
|
+
justRemovedGhostText = false;
|
|
74
|
+
}, {
|
|
75
|
+
tag: 'historic'
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
const handleUpdate = props => {
|
|
79
|
+
const {
|
|
80
|
+
editorState,
|
|
81
|
+
prevEditorState
|
|
82
|
+
} = props;
|
|
83
|
+
// If this update was caused by adding or deleting ghost text, don't recheck the ghost text function until a subsequent update
|
|
84
|
+
if (justRemovedGhostText || justAddedGhostText) {
|
|
85
|
+
justRemovedGhostText = false;
|
|
86
|
+
justAddedGhostText = false;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
editorState.read(() => {
|
|
90
|
+
// We only update the ghost text if the user selection is inside the input
|
|
91
|
+
const selection = $getSelection();
|
|
92
|
+
if (!$getSelection()) {
|
|
93
|
+
return;
|
|
54
94
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
node
|
|
71
|
-
]);
|
|
72
|
-
$setSelection(selectionCopy);
|
|
73
|
-
justAddedGhostText = true;
|
|
74
|
-
justRemovedGhostText = false;
|
|
95
|
+
if ($isRangeSelection(selection) && selection.isCollapsed()) {
|
|
96
|
+
var _selectedNode_getPreviousSibling;
|
|
97
|
+
var _selection_getNodes_at;
|
|
98
|
+
// All the `$isXNode` functions prefer `null` over `undefined`
|
|
99
|
+
const selectedNode = (_selection_getNodes_at = selection.getNodes().at(0)) !== null && _selection_getNodes_at !== void 0 ? _selection_getNodes_at : null;
|
|
100
|
+
const previousNodeKey = selectedNode === null || selectedNode === void 0 ? void 0 : (_selectedNode_getPreviousSibling = selectedNode.getPreviousSibling()) === null || _selectedNode_getPreviousSibling === void 0 ? void 0 : _selectedNode_getPreviousSibling.getKey();
|
|
101
|
+
const previousNodeIsGhostText = previousNodeKey === ghostTextNodeKey;
|
|
102
|
+
// If the ghost text is active and we're navigating past it, act as if the ghost text is not there and move 1 extra character
|
|
103
|
+
if (previousNodeIsGhostText && !$isSentinelNode(selectedNode) && $isTextNode(selectedNode) && selection.anchor.offset === 0) {
|
|
104
|
+
editor.update(() => {
|
|
105
|
+
const selection = $getSelection();
|
|
106
|
+
if ($isRangeSelection(selection)) {
|
|
107
|
+
selection.modify('move', false, 'character');
|
|
108
|
+
}
|
|
109
|
+
$clearGhostText();
|
|
75
110
|
}, {
|
|
76
|
-
|
|
111
|
+
tag: 'historic'
|
|
77
112
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// We only update the ghost text if the user selection is inside the input
|
|
89
|
-
const selection = $getSelection();
|
|
90
|
-
if (!$getSelection()) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if ($isRangeSelection(selection) && selection.isCollapsed()) {
|
|
94
|
-
var _selectedNode_getPreviousSibling;
|
|
95
|
-
var _selection_getNodes_at;
|
|
96
|
-
// All the `$isXNode` functions prefer `null` over `undefined`
|
|
97
|
-
const selectedNode = (_selection_getNodes_at = selection.getNodes().at(0)) !== null && _selection_getNodes_at !== void 0 ? _selection_getNodes_at : null;
|
|
98
|
-
const previousNodeKey = selectedNode === null || selectedNode === void 0 ? void 0 : (_selectedNode_getPreviousSibling = selectedNode.getPreviousSibling()) === null || _selectedNode_getPreviousSibling === void 0 ? void 0 : _selectedNode_getPreviousSibling.getKey();
|
|
99
|
-
const previousNodeIsGhostText = previousNodeKey === ghostTextNodeKey;
|
|
100
|
-
// If the ghost text is active and we're navigating past it, act as if the ghost text is not there and move 1 extra character
|
|
101
|
-
if (previousNodeIsGhostText && !$isSentinelNode(selectedNode) && $isTextNode(selectedNode) && selection.anchor.offset === 0) {
|
|
102
|
-
editor.update(()=>{
|
|
103
|
-
const selection = $getSelection();
|
|
104
|
-
if ($isRangeSelection(selection)) {
|
|
105
|
-
selection.modify('move', false, 'character');
|
|
106
|
-
}
|
|
107
|
-
$clearGhostText();
|
|
108
|
-
}, {
|
|
109
|
-
tag: 'historic'
|
|
110
|
-
});
|
|
111
|
-
// Defer checking the ghost text until after this update has finished
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
// If the ghost text is the last node before the sentinel, we shouldn't let selection get past it
|
|
115
|
-
if (previousNodeIsGhostText && $isSentinelNode(selectedNode)) {
|
|
116
|
-
editor.update(()=>{
|
|
117
|
-
var _$getNodeByKey_getPreviousSibling, _$getNodeByKey;
|
|
118
|
-
(_$getNodeByKey = $getNodeByKey(previousNodeKey)) === null || _$getNodeByKey === void 0 ? void 0 : (_$getNodeByKey_getPreviousSibling = _$getNodeByKey.getPreviousSibling()) === null || _$getNodeByKey_getPreviousSibling === void 0 ? void 0 : _$getNodeByKey_getPreviousSibling.selectEnd();
|
|
119
|
-
}, {
|
|
120
|
-
tag: 'historic'
|
|
121
|
-
});
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
const promise = this.__$getGhostText(editor, editorState, prevEditorState);
|
|
126
|
-
promise.then(handleGhostTextResponse).catch((e)=>console.error(e));
|
|
113
|
+
// Defer checking the ghost text until after this update has finished
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// If the ghost text is the last node before the sentinel, we shouldn't let selection get past it
|
|
117
|
+
if (previousNodeIsGhostText && $isSentinelNode(selectedNode)) {
|
|
118
|
+
editor.update(() => {
|
|
119
|
+
var _$getNodeByKey_getPreviousSibling, _$getNodeByKey;
|
|
120
|
+
(_$getNodeByKey = $getNodeByKey(previousNodeKey)) === null || _$getNodeByKey === void 0 ? void 0 : (_$getNodeByKey_getPreviousSibling = _$getNodeByKey.getPreviousSibling()) === null || _$getNodeByKey_getPreviousSibling === void 0 ? void 0 : _$getNodeByKey_getPreviousSibling.selectEnd();
|
|
121
|
+
}, {
|
|
122
|
+
tag: 'historic'
|
|
127
123
|
});
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (ghostTextNodeKey) {
|
|
131
|
-
editor.update(()=>{
|
|
132
|
-
$clearGhostText();
|
|
133
|
-
}, {
|
|
134
|
-
tag: 'historic'
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function $handleTabCommand(e) {
|
|
139
|
-
if (ghostTextNodeKey === null || lastText === null) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
const ghostTextNode = $getNodeByKey(ghostTextNodeKey);
|
|
143
|
-
if (!ghostTextNode) {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
e.preventDefault();
|
|
147
|
-
const textNode = $createTextNode(lastText);
|
|
148
|
-
ghostTextNode.replace(textNode);
|
|
149
|
-
textNode.selectEnd();
|
|
150
|
-
$clearGhostText();
|
|
151
|
-
return true;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
152
126
|
}
|
|
153
|
-
|
|
127
|
+
const promise = this.__$getGhostText(editor, editorState, prevEditorState);
|
|
128
|
+
promise.then(handleGhostTextResponse).catch(e => console.error(e));
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
function unmountGhostText() {
|
|
132
|
+
if (ghostTextNodeKey) {
|
|
133
|
+
editor.update(() => {
|
|
134
|
+
$clearGhostText();
|
|
135
|
+
}, {
|
|
136
|
+
tag: 'historic'
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function $handleTabCommand(e) {
|
|
141
|
+
if (ghostTextNodeKey === null || lastText === null) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const ghostTextNode = $getNodeByKey(ghostTextNodeKey);
|
|
145
|
+
if (!ghostTextNode) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
const textNode = $createTextNode(lastText);
|
|
150
|
+
ghostTextNode.replace(textNode);
|
|
151
|
+
textNode.selectEnd();
|
|
152
|
+
$clearGhostText();
|
|
153
|
+
return true;
|
|
154
154
|
}
|
|
155
|
+
this.__cleanup = mergeRegister(editor.registerNodeTransform(nodeClass, handleGhostTextNodeTransform), editor.registerUpdateListener(handleUpdate), this.__allowCompletion ? editor.registerCommand(KEY_TAB_COMMAND, $handleTabCommand, COMMAND_PRIORITY_LOW) : noop, unmountGhostText);
|
|
156
|
+
}
|
|
155
157
|
}
|
|
156
158
|
function noop() {
|
|
157
|
-
|
|
159
|
+
return;
|
|
158
160
|
}
|
|
161
|
+
//# sourceMappingURL=GhostText.base.js.map
|
package/lib/GhostText/index.js
CHANGED