@fluentui-copilot/chat-input-plugins 0.4.2 → 0.5.1

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.
Files changed (50) hide show
  1. package/CHANGELOG.json +61 -1
  2. package/CHANGELOG.md +20 -2
  3. package/dist/index.d.ts +0 -2
  4. package/lib/BasicFunctionality/BasicFunctionality.base.js +92 -93
  5. package/lib/BasicFunctionality/BasicFunctionality.base.js.map +1 -1
  6. package/lib/BasicFunctionality/SentinelNode.js +29 -30
  7. package/lib/BasicFunctionality/SentinelNodeHandlers.js +73 -78
  8. package/lib/BasicFunctionality/index.js +0 -1
  9. package/lib/ChatInputEntity/ChatInputEntityPlugin.base.js +109 -114
  10. package/lib/ChatInputEntity/ChatInputEntityPlugin.types.js +1 -2
  11. package/lib/ChatInputEntity/index.js +0 -1
  12. package/lib/GhostText/GhostText.base.js +142 -145
  13. package/lib/GhostText/index.js +0 -1
  14. package/lib/ImperativeControl/ImperativeControl.base.js +82 -83
  15. package/lib/ImperativeControl/index.js +0 -1
  16. package/lib/ManualGhostText/ManualGhostText.base.js +68 -67
  17. package/lib/ManualGhostText/index.js +0 -1
  18. package/lib/PasteUnfurling/PasteUnfurling.base.js +52 -57
  19. package/lib/PasteUnfurling/PasteUnfurling.types.js +1 -2
  20. package/lib/PasteUnfurling/PasteUnfurlingTestUtils.js +138 -139
  21. package/lib/PasteUnfurling/index.js +0 -1
  22. package/lib/index.js +0 -1
  23. package/lib-commonjs/BasicFunctionality/BasicFunctionality.base.js +15 -17
  24. package/lib-commonjs/BasicFunctionality/BasicFunctionality.base.js.map +1 -1
  25. package/lib-commonjs/BasicFunctionality/SentinelNode.js +1 -1
  26. package/lib-commonjs/BasicFunctionality/SentinelNode.js.map +1 -1
  27. package/lib-commonjs/BasicFunctionality/SentinelNodeHandlers.js +3 -5
  28. package/lib-commonjs/BasicFunctionality/SentinelNodeHandlers.js.map +1 -1
  29. package/lib-commonjs/BasicFunctionality/index.js +0 -1
  30. package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.base.js +3 -5
  31. package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.base.js.map +1 -1
  32. package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.types.js +0 -1
  33. package/lib-commonjs/ChatInputEntity/index.js +0 -1
  34. package/lib-commonjs/GhostText/GhostText.base.js +2 -3
  35. package/lib-commonjs/GhostText/GhostText.base.js.map +1 -1
  36. package/lib-commonjs/GhostText/index.js +0 -1
  37. package/lib-commonjs/ImperativeControl/ImperativeControl.base.js +1 -1
  38. package/lib-commonjs/ImperativeControl/ImperativeControl.base.js.map +1 -1
  39. package/lib-commonjs/ImperativeControl/index.js +0 -1
  40. package/lib-commonjs/ManualGhostText/ManualGhostText.base.js +1 -1
  41. package/lib-commonjs/ManualGhostText/ManualGhostText.base.js.map +1 -1
  42. package/lib-commonjs/ManualGhostText/index.js +0 -1
  43. package/lib-commonjs/PasteUnfurling/PasteUnfurling.base.js +1 -1
  44. package/lib-commonjs/PasteUnfurling/PasteUnfurling.base.js.map +1 -1
  45. package/lib-commonjs/PasteUnfurling/PasteUnfurling.types.js +0 -1
  46. package/lib-commonjs/PasteUnfurling/PasteUnfurlingTestUtils.js +1 -1
  47. package/lib-commonjs/PasteUnfurling/PasteUnfurlingTestUtils.js.map +1 -1
  48. package/lib-commonjs/PasteUnfurling/index.js +0 -1
  49. package/lib-commonjs/index.js +0 -1
  50. package/package.json +2 -2
@@ -1,122 +1,117 @@
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
- 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);
4
+ cleanup() {
5
+ this._cleanup();
6
+ }
7
+ insertChatInputEntity(props) {
8
+ let key = undefined;
9
+ this.__editor.update(()=>{
10
+ const { text, data, entityProps } = props;
11
+ const entityNode = this.__$createNode(this.__id, text, data, entityProps);
12
+ $insertNodes([
13
+ entityNode
14
+ ]);
15
+ entityNode.selectEnd();
16
+ if ($isRootOrShadowRoot(entityNode.getParentOrThrow())) {
17
+ $wrapNodeInElement(entityNode, $createParagraphNode).selectEnd();
105
18
  }
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);
19
+ key = entityNode.getKey();
20
+ });
21
+ return key;
22
+ }
23
+ removeChatInputEntity(keyOrPredicate) {
24
+ this.__editor.update(()=>{
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();
112
30
  }
113
- });
114
- }
115
- }
116
- }) : noop);
117
- }
31
+ });
32
+ }
33
+ updateChatInputEntityProps(keyOrPredicate, props) {
34
+ const updateNode = (node)=>{
35
+ const newProps = typeof props === 'function' ? props(node.getEntityData()) : props;
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
+ }
118
114
  }
119
115
  function noop() {
120
- return;
116
+ return;
121
117
  }
122
- //# sourceMappingURL=ChatInputEntityPlugin.base.js.map
@@ -1,2 +1 @@
1
- export {};
2
- //# sourceMappingURL=ChatInputEntityPlugin.types.js.map
1
+ export { };
@@ -1,2 +1 @@
1
1
  export { ChatInputEntityPluginBase } from './ChatInputEntityPlugin.base';
2
- //# sourceMappingURL=index.js.map
@@ -2,160 +2,157 @@ 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
- 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
- }
5
+ cleanup() {
6
+ var _this___cleanup, _this;
7
+ (_this___cleanup = (_this = this).__cleanup) === null || _this___cleanup === void 0 ? void 0 : _this___cleanup.call(_this);
47
8
  }
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
- }
9
+ setExposeText(exposeText) {
10
+ this.__exposeText = exposeText;
55
11
  }
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;
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, // 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
+ }
65
46
  }
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;
47
+ function handleGhostTextNodeTransform(node) {
48
+ const key = node.getKey();
49
+ if (node.__id === id && key !== ghostTextNodeKey) {
50
+ // Only one ghost text
51
+ node.remove();
52
+ $clearGhostText();
53
+ }
94
54
  }
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();
55
+ const handleGhostTextResponse = (text)=>{
56
+ if (text === lastText) {
57
+ return;
58
+ }
59
+ editor.update(()=>{
60
+ $clearGhostText();
61
+ const selection = $getSelection();
62
+ if (!text || !selection) {
63
+ return;
64
+ }
65
+ const selectionCopy = selection.clone();
66
+ const node = createNode(this.__id, text, this.__exposeText, this.__componentProps);
67
+ ghostTextNodeKey = node.getKey();
68
+ lastText = text;
69
+ selection.insertNodes([
70
+ node
71
+ ]);
72
+ $setSelection(selectionCopy);
73
+ justAddedGhostText = true;
74
+ justRemovedGhostText = false;
110
75
  }, {
111
- tag: 'historic'
76
+ tag: 'historic'
112
77
  });
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'
78
+ };
79
+ const handleUpdate = (props)=>{
80
+ const { editorState, prevEditorState } = props;
81
+ // If this update was caused by adding or deleting ghost text, don't recheck the ghost text function until a subsequent update
82
+ if (justRemovedGhostText || justAddedGhostText) {
83
+ justRemovedGhostText = false;
84
+ justAddedGhostText = false;
85
+ return;
86
+ }
87
+ editorState.read(()=>{
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));
123
127
  });
124
- return;
125
- }
128
+ };
129
+ function unmountGhostText() {
130
+ if (ghostTextNodeKey) {
131
+ editor.update(()=>{
132
+ $clearGhostText();
133
+ }, {
134
+ tag: 'historic'
135
+ });
136
+ }
126
137
  }
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;
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;
152
+ }
153
+ this.__cleanup = mergeRegister(editor.registerNodeTransform(nodeClass, handleGhostTextNodeTransform), editor.registerUpdateListener(handleUpdate), this.__allowCompletion ? editor.registerCommand(KEY_TAB_COMMAND, $handleTabCommand, COMMAND_PRIORITY_LOW) : noop, unmountGhostText);
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
- }
157
155
  }
158
156
  function noop() {
159
- return;
157
+ return;
160
158
  }
161
- //# sourceMappingURL=GhostText.base.js.map
@@ -1,2 +1 @@
1
1
  export { GhostTextPluginBase } from './GhostText.base';
2
- //# sourceMappingURL=index.js.map