@fluentui-copilot/chat-input-plugins 0.0.8 → 0.1.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.
package/CHANGELOG.json CHANGED
@@ -2,7 +2,37 @@
2
2
  "name": "@fluentui-copilot/chat-input-plugins",
3
3
  "entries": [
4
4
  {
5
- "date": "Thu, 13 Jun 2024 21:00:13 GMT",
5
+ "date": "Tue, 23 Jul 2024 00:55:17 GMT",
6
+ "tag": "@fluentui-copilot/chat-input-plugins_v0.1.1",
7
+ "version": "0.1.1",
8
+ "comments": {
9
+ "patch": [
10
+ {
11
+ "author": "tristan.watanabe@gmail.com",
12
+ "package": "@fluentui-copilot/chat-input-plugins",
13
+ "commit": "888dd544512957e439443a9ff8b1e1ceebeb8aa1",
14
+ "comment": "fix: can now undo input until it is completely clear."
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Thu, 20 Jun 2024 23:05:53 GMT",
21
+ "tag": "@fluentui-copilot/chat-input-plugins_v0.1.0",
22
+ "version": "0.1.0",
23
+ "comments": {
24
+ "minor": [
25
+ {
26
+ "author": "owcampbe@microsoft.com",
27
+ "package": "@fluentui-copilot/chat-input-plugins",
28
+ "commit": "2f9626d2dca003ec62e70564b68b17917075296e",
29
+ "comment": "chore: Add parameter to callback and rename types."
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "date": "Thu, 13 Jun 2024 21:00:45 GMT",
6
36
  "tag": "@fluentui-copilot/chat-input-plugins_v0.0.8",
7
37
  "version": "0.0.8",
8
38
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,30 @@
1
1
  # Change Log - @fluentui-copilot/chat-input-plugins
2
2
 
3
- This log was last generated on Thu, 13 Jun 2024 21:00:13 GMT and should not be manually modified.
3
+ This log was last generated on Tue, 23 Jul 2024 00:55:17 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [0.1.1](https://github.com/microsoft/fluentai/tree/@fluentui-copilot/chat-input-plugins_v0.1.1)
8
+
9
+ Tue, 23 Jul 2024 00:55:17 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentai/compare/@fluentui-copilot/chat-input-plugins_v0.1.0..@fluentui-copilot/chat-input-plugins_v0.1.1)
11
+
12
+ ### Patches
13
+
14
+ - fix: can now undo input until it is completely clear. ([PR #1832](https://github.com/microsoft/fluentai/pull/1832) by tristan.watanabe@gmail.com)
15
+
16
+ ## [0.1.0](https://github.com/microsoft/fluentai/tree/@fluentui-copilot/chat-input-plugins_v0.1.0)
17
+
18
+ Thu, 20 Jun 2024 23:05:53 GMT
19
+ [Compare changes](https://github.com/microsoft/fluentai/compare/@fluentui-copilot/chat-input-plugins_v0.0.8..@fluentui-copilot/chat-input-plugins_v0.1.0)
20
+
21
+ ### Minor changes
22
+
23
+ - chore: Add parameter to callback and rename types. ([PR #1735](https://github.com/microsoft/fluentai/pull/1735) by owcampbe@microsoft.com)
24
+
7
25
  ## [0.0.8](https://github.com/microsoft/fluentai/tree/@fluentui-copilot/chat-input-plugins_v0.0.8)
8
26
 
9
- Thu, 13 Jun 2024 21:00:13 GMT
27
+ Thu, 13 Jun 2024 21:00:45 GMT
10
28
  [Compare changes](https://github.com/microsoft/fluentai/compare/@fluentui-copilot/chat-input-plugins_v0.0.7..@fluentui-copilot/chat-input-plugins_v0.0.8)
11
29
 
12
30
  ### Patches
package/dist/index.d.ts CHANGED
@@ -43,7 +43,7 @@ export declare class ChatInputEntityPluginBase<ExtraDataType, NodePropsType, Nod
43
43
  private __$createNode;
44
44
  private _cleanup;
45
45
  cleanup(): void;
46
- constructor(editor: LexicalEditor, id: string, nodeClass: Klass<NodeType>, $createNode: (pluginId: string, text: string, data?: ExtraDataType, entityProps?: NodePropsType, key?: NodeKey) => NodeType, $isChatInputEntityNode: (node: LexicalNode | null) => node is NodeType, onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void, onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void);
46
+ constructor(editor: LexicalEditor, id: string, nodeClass: Klass<NodeType>, $createNode: (pluginId: string, text: string, data?: ExtraDataType, entityProps?: NodePropsType, key?: NodeKey) => NodeType, $isChatInputEntityNode: (node: LexicalNode | null) => node is NodeType, onChatInputEntityAdded?: ChatInputEntityPluginProps<ExtraDataType, NodePropsType>['onChatInputEntityAdded'], onChatInputEntityDeleted?: ChatInputEntityPluginProps<ExtraDataType, NodePropsType>['onChatInputEntityDeleted']);
47
47
  insertChatInputEntity(props: ChatInputEntityData<ExtraDataType, NodePropsType>): string | undefined;
48
48
  removeChatInputEntity(keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean)): void;
49
49
  updateChatInputEntityProps(keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean), props: ChatInputEntityData<ExtraDataType, NodePropsType> | ((oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>) => ChatInputEntityData<ExtraDataType, NodePropsType>)): void;
@@ -52,8 +52,8 @@ export declare class ChatInputEntityPluginBase<ExtraDataType, NodePropsType, Nod
52
52
 
53
53
  export declare type ChatInputEntityPluginProps<ExtraDataType, NodePropsType> = {
54
54
  id: string;
55
- onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;
56
- onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;
55
+ onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>, nodeKey: NodeKey) => void;
56
+ onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>, nodeKey: NodeKey) => void;
57
57
  };
58
58
 
59
59
  export declare type GetGhostTextFunction = (editor: LexicalEditor, editorState: EditorState, prevEditorState: EditorState) => Promise<string | undefined>;
@@ -154,25 +154,13 @@ export declare class ManualGhostTextBase<ComponentPropsType> {
154
154
  cancelGhostText(): void;
155
155
  }
156
156
 
157
- export declare type PasteUnfurlingPluginProps<ExtraDataType, NodePropsType> = {
157
+ export declare type PasteUnfurlingPluginBaseProps<ExtraDataType, NodePropsType> = {
158
158
  entityPluginId: string;
159
- transforms: TransformFunction<ExtraDataType, NodePropsType>[];
159
+ transforms: PasteUnfurlingTransformFunction<ExtraDataType, NodePropsType>[];
160
160
  $createEntityNode: (pluginId: string, text: string, data?: ExtraDataType, entityProps?: NodePropsType, key?: NodeKey) => LexicalNode;
161
161
  };
162
162
 
163
- export declare function registerPasteUnfurlingPlugin<ExtraDataType, NodePropsType>(editor: LexicalEditor, props: PasteUnfurlingPluginProps<ExtraDataType, NodePropsType>): () => void;
164
-
165
- export declare const SENTINEL_VALUE = "\u200B\u200C";
166
-
167
- export declare class SentinelNode extends TextNode {
168
- constructor(key?: NodeKey);
169
- static getType(): string;
170
- static clone(node: SentinelNode): SentinelNode;
171
- createDOM(config: EditorConfig): HTMLElement;
172
- isToken(): boolean;
173
- }
174
-
175
- export declare type TransformedPart<ExtraDataType, NodePropsType> = {
163
+ export declare type PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType> = {
176
164
  type: 'text';
177
165
  value: string;
178
166
  } | {
@@ -180,11 +168,23 @@ export declare type TransformedPart<ExtraDataType, NodePropsType> = {
180
168
  value: ChatInputEntityData<ExtraDataType, NodePropsType>;
181
169
  };
182
170
 
183
- export declare type TransformFunction<ExtraDataType, NodePropsType> = (event: ClipboardEvent, editor: LexicalEditor) => TransformResult<ExtraDataType, NodePropsType>;
171
+ export declare type PasteUnfurlingTransformFunction<ExtraDataType, NodePropsType> = (event: ClipboardEvent, editor: LexicalEditor) => PasteUnfurlingTransformResult<ExtraDataType, NodePropsType>;
184
172
 
185
- export declare type TransformResult<ExtraDataType, NodePropsType> = {
173
+ export declare type PasteUnfurlingTransformResult<ExtraDataType, NodePropsType> = {
186
174
  handled: boolean;
187
- transformedParts?: TransformedPart<ExtraDataType, NodePropsType>[];
175
+ transformedParts?: PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType>[];
188
176
  };
189
177
 
178
+ export declare function registerPasteUnfurlingPlugin<ExtraDataType, NodePropsType>(editor: LexicalEditor, props: PasteUnfurlingPluginBaseProps<ExtraDataType, NodePropsType>): () => void;
179
+
180
+ export declare const SENTINEL_VALUE = "\u200B\u200C";
181
+
182
+ export declare class SentinelNode extends TextNode {
183
+ constructor(key?: NodeKey);
184
+ static getType(): string;
185
+ static clone(node: SentinelNode): SentinelNode;
186
+ createDOM(config: EditorConfig): HTMLElement;
187
+ isToken(): boolean;
188
+ }
189
+
190
190
  export { }
@@ -116,8 +116,11 @@ export class BasicFunctionalityBase {
116
116
  // We find the node by its key again in case the node was removed before this update runs
117
117
  _$getNodeByKey;
118
118
  (_$getNodeByKey = $getNodeByKey(lastNodeKey)) === null || _$getNodeByKey === void 0 ? void 0 : _$getNodeByKey.insertAfter($createSentinelNode());
119
- }, {
120
- discrete: true
119
+ },
120
+ // historic tag prevents every sentinel node addition from being added to LexicalHistoryPlugin undo stack
121
+ {
122
+ discrete: true,
123
+ tag: 'historic'
121
124
  });
122
125
  return;
123
126
  }
@@ -137,8 +140,6 @@ export class BasicFunctionalityBase {
137
140
  this.__editor.update(() => {
138
141
  var _$getNodeByKey;
139
142
  (_$getNodeByKey = $getNodeByKey(lastNodeKey)) === null || _$getNodeByKey === void 0 ? void 0 : _$getNodeByKey.selectStart();
140
- }, {
141
- discrete: true
142
143
  });
143
144
  return;
144
145
  }
@@ -159,8 +160,6 @@ export class BasicFunctionalityBase {
159
160
  if ($getNodeByKey(lastNodeKey) !== null) {
160
161
  $setSelection($normalizeSelection__EXPERIMENTAL(newSelection));
161
162
  }
162
- }, {
163
- discrete: true
164
163
  });
165
164
  }
166
165
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["BasicFunctionality.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport {\n $createTextNode,\n $getLeafNodes,\n $getNodeByKey,\n $getRoot,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n $normalizeSelection__EXPERIMENTAL,\n $setSelection,\n COMMAND_PRIORITY_CRITICAL,\n INSERT_PARAGRAPH_COMMAND,\n KEY_ENTER_COMMAND,\n PASTE_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport { $createSentinelNode, $isSentinelNode, SENTINEL_VALUE, SentinelNode } from './SentinelNode';\n\nexport interface IBasicFunctionalityBase {\n insertDefaultValue: (defaultValue: string) => void;\n setIsDisabled: (isDisabled: boolean) => void;\n activateContentCallbacks(onContentChange?: (value: string) => void, onCountChanged?: (count: number) => void): void;\n deactivateContentCallbacks(): void;\n activateTrimWhitespace(): void;\n deactivateTrimWhitespace(): void;\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void): void;\n deactivatePasteCallback(): void;\n cleanup(): void;\n}\n\nexport class BasicFunctionalityBase implements IBasicFunctionalityBase {\n private __editor: LexicalEditor;\n private __contentChangeCleanup?: () => void;\n private __trimWhitespaceCleanup?: () => void;\n private __baseHandlersCleanup?: () => void;\n private __pasteHandlerCleanup?: () => void;\n\n private __enterHandler(event: KeyboardEvent) {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n\n if (event === null) {\n return false;\n }\n\n event.preventDefault();\n\n if (event.shiftKey) {\n return this.__editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);\n }\n\n // Mark event handled to override default behavior\n return true;\n }\n\n constructor(editor: LexicalEditor) {\n this.__editor = editor;\n\n this.__baseHandlersCleanup = mergeRegister(\n this.__editor.registerCommand(KEY_ENTER_COMMAND, this.__enterHandler.bind(this), COMMAND_PRIORITY_CRITICAL),\n\n // Add a sentinel node at the end of the input when there is content.\n // This sentinel node fixes a number of issues.\n // In Safari, Lexical's behaviour of adding <br /> tags to the end of the input when it ends\n // in a decorator node causes cursor location issues: https://github.com/facebook/lexical/issues/4487\n // Otherwise, when a decorator node is the last node in the input, the cursor can't move past it.\n // Adding an invisible text node that doesn't contribute to the content and can't be selected to the end of the input\n // mitigates these issues.\n this.__editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const leaves = $getLeafNodes($getRoot());\n if (leaves.length === 0) {\n return;\n }\n\n const lastNode = leaves[leaves.length - 1];\n const lastNodeKey = lastNode.getKey();\n\n // If the last node isn't a sentinel, add one\n if (!$isSentinelNode(lastNode)) {\n this.__editor.update(\n () => {\n // We find the node by its key again in case the node was removed before this update runs\n $getNodeByKey(lastNodeKey)?.insertAfter($createSentinelNode());\n },\n { discrete: true },\n );\n return;\n }\n\n // If the sentinel node is not selected, we're done\n const previous = lastNode.getPreviousSibling();\n if (!previous || !lastNode.isSelected()) {\n return;\n }\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return;\n }\n\n // If the cursor is inside the sentinel node, move it out (next to the beginning)\n // We allow selection on the boundary of the sentinel in case the adjacent node is a decorator node\n // where selection is ill-defined.\n if (selection.isCollapsed() && selection.anchor.offset > 0) {\n this.__editor.update(\n () => {\n $getNodeByKey(lastNodeKey)?.selectStart();\n },\n { discrete: true },\n );\n return;\n }\n\n // If the selection is a range which includes the sentinel, modify the range to exclude it\n if (!selection.isCollapsed()) {\n let selectionChanged = false;\n const newSelection = selection.clone();\n\n if (newSelection.anchor.getNode() === lastNode && newSelection.anchor.offset > 0) {\n newSelection.anchor.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n if (newSelection.focus.getNode() === lastNode && newSelection.focus.offset > 0) {\n newSelection.focus.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n\n if (selectionChanged) {\n this.__editor.update(\n () => {\n if ($getNodeByKey(lastNodeKey) !== null) {\n $setSelection($normalizeSelection__EXPERIMENTAL(newSelection));\n }\n },\n { discrete: true },\n );\n }\n }\n });\n }),\n this.__editor.registerNodeTransform(SentinelNode, node => {\n if (!node.getPreviousSibling() || node.getNextSibling()) {\n node.remove();\n return;\n }\n }),\n );\n }\n\n insertDefaultValue(defaultValue: string) {\n if (defaultValue) {\n this.__editor.update(() => {\n $insertNodes([$createTextNode(defaultValue)]);\n });\n }\n }\n\n activateContentCallbacks(\n onContentChange?: ((value: string) => void) | undefined,\n onCountChanged?: ((count: number) => void) | undefined,\n ) {\n this.deactivateContentCallbacks();\n this.__contentChangeCleanup = this.__editor.registerTextContentListener(text => {\n // Remove the sentinel node\n const processed = text.replace(SENTINEL_VALUE, '');\n onContentChange?.(processed);\n onCountChanged?.(processed.length);\n });\n }\n\n deactivateContentCallbacks() {\n this.__contentChangeCleanup?.();\n this.__contentChangeCleanup = undefined;\n }\n\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void) {\n this.__pasteHandlerCleanup = this.__editor.registerCommand(\n PASTE_COMMAND,\n (event: ClipboardEvent) => {\n onPaste(event);\n\n if (event.defaultPrevented) {\n return true;\n }\n\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n }\n\n deactivatePasteCallback() {\n this.__pasteHandlerCleanup?.();\n this.__pasteHandlerCleanup = undefined;\n }\n\n activateTrimWhitespace() {\n this.deactivateTrimWhitespace();\n this.__trimWhitespaceCleanup = this.__editor.registerTextContentListener(text => {\n if (text.trim() === '') {\n this.__editor.update(\n () => {\n $getRoot()\n .getAllTextNodes()\n .forEach(node => {\n node.remove();\n });\n },\n // Don't allow undoing this action\n { tag: 'historic' },\n );\n }\n });\n }\n\n deactivateTrimWhitespace() {\n this.__trimWhitespaceCleanup?.();\n this.__trimWhitespaceCleanup = undefined;\n }\n\n setIsDisabled(isDisabled: boolean) {\n this.__editor.setEditable(!isDisabled);\n }\n\n cleanup() {\n this.deactivateContentCallbacks();\n this.deactivateTrimWhitespace();\n this.deactivatePasteCallback();\n this.__baseHandlersCleanup?.();\n this.__baseHandlersCleanup = undefined;\n }\n}\n"],"names":["$createTextNode","$getLeafNodes","$getNodeByKey","$getRoot","$getSelection","$insertNodes","$isRangeSelection","$normalizeSelection__EXPERIMENTAL","$setSelection","COMMAND_PRIORITY_CRITICAL","INSERT_PARAGRAPH_COMMAND","KEY_ENTER_COMMAND","PASTE_COMMAND","mergeRegister","$createSentinelNode","$isSentinelNode","SENTINEL_VALUE","SentinelNode","BasicFunctionalityBase","__enterHandler","event","selection","preventDefault","shiftKey","__editor","dispatchCommand","undefined","insertDefaultValue","defaultValue","update","activateContentCallbacks","onContentChange","onCountChanged","deactivateContentCallbacks","__contentChangeCleanup","registerTextContentListener","text","processed","replace","length","activatePasteCallback","onPaste","__pasteHandlerCleanup","registerCommand","defaultPrevented","deactivatePasteCallback","activateTrimWhitespace","deactivateTrimWhitespace","__trimWhitespaceCleanup","trim","getAllTextNodes","forEach","node","remove","tag","setIsDisabled","isDisabled","setEditable","cleanup","__baseHandlersCleanup","constructor","editor","bind","registerUpdateListener","editorState","read","leaves","lastNode","lastNodeKey","getKey","insertAfter","discrete","previous","getPreviousSibling","isSelected","isCollapsed","anchor","offset","selectStart","selectionChanged","newSelection","clone","getNode","set","focus","registerNodeTransform","getNextSibling"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["BasicFunctionality.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport {\n $createTextNode,\n $getLeafNodes,\n $getNodeByKey,\n $getRoot,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n $normalizeSelection__EXPERIMENTAL,\n $setSelection,\n COMMAND_PRIORITY_CRITICAL,\n INSERT_PARAGRAPH_COMMAND,\n KEY_ENTER_COMMAND,\n PASTE_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport { $createSentinelNode, $isSentinelNode, SENTINEL_VALUE, SentinelNode } from './SentinelNode';\n\nexport interface IBasicFunctionalityBase {\n insertDefaultValue: (defaultValue: string) => void;\n setIsDisabled: (isDisabled: boolean) => void;\n activateContentCallbacks(onContentChange?: (value: string) => void, onCountChanged?: (count: number) => void): void;\n deactivateContentCallbacks(): void;\n activateTrimWhitespace(): void;\n deactivateTrimWhitespace(): void;\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void): void;\n deactivatePasteCallback(): void;\n cleanup(): void;\n}\n\nexport class BasicFunctionalityBase implements IBasicFunctionalityBase {\n private __editor: LexicalEditor;\n private __contentChangeCleanup?: () => void;\n private __trimWhitespaceCleanup?: () => void;\n private __baseHandlersCleanup?: () => void;\n private __pasteHandlerCleanup?: () => void;\n\n private __enterHandler(event: KeyboardEvent) {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n\n if (event === null) {\n return false;\n }\n\n event.preventDefault();\n\n if (event.shiftKey) {\n return this.__editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);\n }\n\n // Mark event handled to override default behavior\n return true;\n }\n\n constructor(editor: LexicalEditor) {\n this.__editor = editor;\n\n this.__baseHandlersCleanup = mergeRegister(\n this.__editor.registerCommand(KEY_ENTER_COMMAND, this.__enterHandler.bind(this), COMMAND_PRIORITY_CRITICAL),\n\n // Add a sentinel node at the end of the input when there is content.\n // This sentinel node fixes a number of issues.\n // In Safari, Lexical's behaviour of adding <br /> tags to the end of the input when it ends\n // in a decorator node causes cursor location issues: https://github.com/facebook/lexical/issues/4487\n // Otherwise, when a decorator node is the last node in the input, the cursor can't move past it.\n // Adding an invisible text node that doesn't contribute to the content and can't be selected to the end of the input\n // mitigates these issues.\n this.__editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const leaves = $getLeafNodes($getRoot());\n if (leaves.length === 0) {\n return;\n }\n\n const lastNode = leaves[leaves.length - 1];\n const lastNodeKey = lastNode.getKey();\n\n // If the last node isn't a sentinel, add one\n if (!$isSentinelNode(lastNode)) {\n this.__editor.update(\n () => {\n // We find the node by its key again in case the node was removed before this update runs\n $getNodeByKey(lastNodeKey)?.insertAfter($createSentinelNode());\n },\n // historic tag prevents every sentinel node addition from being added to LexicalHistoryPlugin undo stack\n { discrete: true, tag: 'historic' },\n );\n return;\n }\n\n // If the sentinel node is not selected, we're done\n const previous = lastNode.getPreviousSibling();\n if (!previous || !lastNode.isSelected()) {\n return;\n }\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return;\n }\n\n // If the cursor is inside the sentinel node, move it out (next to the beginning)\n // We allow selection on the boundary of the sentinel in case the adjacent node is a decorator node\n // where selection is ill-defined.\n if (selection.isCollapsed() && selection.anchor.offset > 0) {\n this.__editor.update(() => {\n $getNodeByKey(lastNodeKey)?.selectStart();\n });\n return;\n }\n\n // If the selection is a range which includes the sentinel, modify the range to exclude it\n if (!selection.isCollapsed()) {\n let selectionChanged = false;\n const newSelection = selection.clone();\n\n if (newSelection.anchor.getNode() === lastNode && newSelection.anchor.offset > 0) {\n newSelection.anchor.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n if (newSelection.focus.getNode() === lastNode && newSelection.focus.offset > 0) {\n newSelection.focus.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n\n if (selectionChanged) {\n this.__editor.update(() => {\n if ($getNodeByKey(lastNodeKey) !== null) {\n $setSelection($normalizeSelection__EXPERIMENTAL(newSelection));\n }\n });\n }\n }\n });\n }),\n this.__editor.registerNodeTransform(SentinelNode, node => {\n if (!node.getPreviousSibling() || node.getNextSibling()) {\n node.remove();\n return;\n }\n }),\n );\n }\n\n insertDefaultValue(defaultValue: string) {\n if (defaultValue) {\n this.__editor.update(() => {\n $insertNodes([$createTextNode(defaultValue)]);\n });\n }\n }\n\n activateContentCallbacks(\n onContentChange?: ((value: string) => void) | undefined,\n onCountChanged?: ((count: number) => void) | undefined,\n ) {\n this.deactivateContentCallbacks();\n this.__contentChangeCleanup = this.__editor.registerTextContentListener(text => {\n // Remove the sentinel node\n const processed = text.replace(SENTINEL_VALUE, '');\n onContentChange?.(processed);\n onCountChanged?.(processed.length);\n });\n }\n\n deactivateContentCallbacks() {\n this.__contentChangeCleanup?.();\n this.__contentChangeCleanup = undefined;\n }\n\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void) {\n this.__pasteHandlerCleanup = this.__editor.registerCommand(\n PASTE_COMMAND,\n (event: ClipboardEvent) => {\n onPaste(event);\n\n if (event.defaultPrevented) {\n return true;\n }\n\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n }\n\n deactivatePasteCallback() {\n this.__pasteHandlerCleanup?.();\n this.__pasteHandlerCleanup = undefined;\n }\n\n activateTrimWhitespace() {\n this.deactivateTrimWhitespace();\n this.__trimWhitespaceCleanup = this.__editor.registerTextContentListener(text => {\n if (text.trim() === '') {\n this.__editor.update(\n () => {\n $getRoot()\n .getAllTextNodes()\n .forEach(node => {\n node.remove();\n });\n },\n // Don't allow undoing this action\n { tag: 'historic' },\n );\n }\n });\n }\n\n deactivateTrimWhitespace() {\n this.__trimWhitespaceCleanup?.();\n this.__trimWhitespaceCleanup = undefined;\n }\n\n setIsDisabled(isDisabled: boolean) {\n this.__editor.setEditable(!isDisabled);\n }\n\n cleanup() {\n this.deactivateContentCallbacks();\n this.deactivateTrimWhitespace();\n this.deactivatePasteCallback();\n this.__baseHandlersCleanup?.();\n this.__baseHandlersCleanup = undefined;\n }\n}\n"],"names":["$createTextNode","$getLeafNodes","$getNodeByKey","$getRoot","$getSelection","$insertNodes","$isRangeSelection","$normalizeSelection__EXPERIMENTAL","$setSelection","COMMAND_PRIORITY_CRITICAL","INSERT_PARAGRAPH_COMMAND","KEY_ENTER_COMMAND","PASTE_COMMAND","mergeRegister","$createSentinelNode","$isSentinelNode","SENTINEL_VALUE","SentinelNode","BasicFunctionalityBase","__enterHandler","event","selection","preventDefault","shiftKey","__editor","dispatchCommand","undefined","insertDefaultValue","defaultValue","update","activateContentCallbacks","onContentChange","onCountChanged","deactivateContentCallbacks","__contentChangeCleanup","registerTextContentListener","text","processed","replace","length","activatePasteCallback","onPaste","__pasteHandlerCleanup","registerCommand","defaultPrevented","deactivatePasteCallback","activateTrimWhitespace","deactivateTrimWhitespace","__trimWhitespaceCleanup","trim","getAllTextNodes","forEach","node","remove","tag","setIsDisabled","isDisabled","setEditable","cleanup","__baseHandlersCleanup","constructor","editor","bind","registerUpdateListener","editorState","read","leaves","lastNode","lastNodeKey","getKey","insertAfter","discrete","previous","getPreviousSibling","isSelected","isCollapsed","anchor","offset","selectStart","selectionChanged","newSelection","clone","getNode","set","focus","registerNodeTransform","getNextSibling"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -101,14 +101,14 @@ export class ChatInputEntityPluginBase {
101
101
  payload.prevEditorState.read(() => {
102
102
  const node = $getNodeByKey(nodeKey);
103
103
  if ($isChatInputEntityNode(node) && node.__pluginId === id) {
104
- onChatInputEntityDeleted(node.getEntityData());
104
+ onChatInputEntityDeleted(node.getEntityData(), nodeKey);
105
105
  }
106
106
  });
107
107
  } else if (onChatInputEntityAdded && mutation === 'created') {
108
108
  editor.getEditorState().read(() => {
109
109
  const node = $getNodeByKey(nodeKey);
110
110
  if ($isChatInputEntityNode(node) && node.__pluginId === id) {
111
- onChatInputEntityAdded(node.getEntityData());
111
+ onChatInputEntityAdded(node.getEntityData(), nodeKey);
112
112
  }
113
113
  });
114
114
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["ChatInputEntityPlugin.base.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey, Klass } from '@fluentui-copilot/text-editor';\nimport {\n $createParagraphNode,\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $insertNodes,\n $isDecoratorNode,\n $isRangeSelection,\n $isRootOrShadowRoot,\n $nodesOfType,\n $wrapNodeInElement,\n COMMAND_PRIORITY_CRITICAL,\n DELETE_CHARACTER_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport type { ChatInputEntityData, IChatInputEntityPluginBase, IEntityNode } from './ChatInputEntityPlugin.types';\n\nexport class ChatInputEntityPluginBase<\n ExtraDataType,\n NodePropsType,\n NodeType extends IEntityNode<ExtraDataType, NodePropsType>,\n> implements IChatInputEntityPluginBase<ExtraDataType, NodePropsType>\n{\n private __nodeClass: Klass<NodeType>;\n private __editor: LexicalEditor;\n private __id: string;\n\n private __deleteDirection: 'forward' | 'backward' | null = null;\n private __$createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType;\n\n private _cleanup: () => void;\n\n cleanup() {\n this._cleanup();\n }\n\n constructor(\n editor: LexicalEditor,\n id: string,\n nodeClass: Klass<NodeType>,\n $createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType,\n $isChatInputEntityNode: (node: LexicalNode | null) => node is NodeType,\n onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void,\n onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void,\n ) {\n this.__$createNode = $createNode;\n this.__editor = editor;\n this.__id = id;\n this.__nodeClass = nodeClass;\n\n this._cleanup = mergeRegister(\n // Keep track of delete direction so we know where to put the selection after adding back a space\n editor.registerCommand(\n DELETE_CHARACTER_COMMAND,\n isBackward => {\n this.__deleteDirection = isBackward ? 'backward' : 'forward';\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n ),\n // Always maintain a space before, after, and between entities in order for selection to work properly\n editor.registerNodeTransform(this.__nodeClass, node => {\n const nextSibling = node.getNextSibling();\n if (!nextSibling || $isDecoratorNode(nextSibling)) {\n const selection = $getSelection();\n\n // If selection is between the two nodes, that means the user is trying to delete the space\n // If they deleted to the left, we should move the cursor to the end of the entity\n // If they delete to the right, we should move the cursor to the end of the newly added space\n // This mimics changing the delete into a cursor move action\n const shouldMoveSelection =\n selection &&\n $isRangeSelection(selection) &&\n selection.isCollapsed() &&\n selection.anchor.offset === node.getIndexWithinParent() + 1;\n const text = $createTextNode(' ');\n node.insertAfter(text);\n if (shouldMoveSelection) {\n if (this.__deleteDirection === 'forward') {\n text.selectEnd();\n } else {\n node.selectEnd();\n }\n }\n }\n\n // In the case the entity is the first node, we need a space before it.\n if (!node.getPreviousSibling()) {\n const text = $createTextNode(' ');\n node.insertBefore(text);\n }\n }),\n onChatInputEntityAdded || onChatInputEntityDeleted\n ? editor.registerMutationListener(this.__nodeClass, (nodes, payload) => {\n for (const [nodeKey, mutation] of nodes) {\n if (onChatInputEntityDeleted && mutation === 'destroyed') {\n payload.prevEditorState.read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityDeleted(node.getEntityData());\n }\n });\n } else if (onChatInputEntityAdded && mutation === 'created') {\n editor.getEditorState().read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityAdded(node.getEntityData());\n }\n });\n }\n }\n })\n : noop,\n );\n }\n insertChatInputEntity(props: ChatInputEntityData<ExtraDataType, NodePropsType>): string | undefined {\n let key: string | undefined = undefined;\n this.__editor.update(() => {\n const { text, data, entityProps } = props;\n\n const entityNode = this.__$createNode(this.__id, text, data, entityProps);\n\n $insertNodes([entityNode]);\n entityNode.selectEnd();\n if ($isRootOrShadowRoot(entityNode.getParentOrThrow())) {\n $wrapNodeInElement(entityNode, $createParagraphNode).selectEnd();\n }\n\n key = entityNode.getKey();\n });\n\n return key;\n }\n removeChatInputEntity(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) {\n this.__editor.update(() => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(node => node.remove());\n } else {\n $getNodeByKey(keyOrPredicate)?.remove();\n }\n });\n }\n updateChatInputEntityProps(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) {\n const updateNode = (node: NodeType) => {\n const newProps = typeof props === 'function' ? props(node.getEntityData()) : props;\n node.updateEntityData(newProps);\n };\n\n this.__editor.update(\n () => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(updateNode);\n } else {\n const node = $getNodeByKey<NodeType>(keyOrPredicate);\n if (node) {\n updateNode(node);\n }\n }\n },\n { tag: 'historic' },\n );\n }\n\n getActiveEntities(): ChatInputEntityData<ExtraDataType, NodePropsType>[] {\n return this.__editor.getEditorState().read(() =>\n $nodesOfType(this.__nodeClass)\n .filter(node => node.__pluginId === this.__id)\n .map(node => node.getEntityData()),\n );\n }\n}\n\nfunction noop() {\n return;\n}\n"],"names":["$createParagraphNode","$createTextNode","$getNodeByKey","$getSelection","$insertNodes","$isDecoratorNode","$isRangeSelection","$isRootOrShadowRoot","$nodesOfType","$wrapNodeInElement","COMMAND_PRIORITY_CRITICAL","DELETE_CHARACTER_COMMAND","mergeRegister","ChatInputEntityPluginBase","cleanup","_cleanup","insertChatInputEntity","props","key","undefined","__editor","update","text","data","entityProps","entityNode","__$createNode","__id","selectEnd","getParentOrThrow","getKey","removeChatInputEntity","keyOrPredicate","__nodeClass","filter","node","i","__pluginId","getEntityData","forEach","remove","updateChatInputEntityProps","updateNode","newProps","updateEntityData","tag","getActiveEntities","getEditorState","read","map","constructor","editor","id","nodeClass","$createNode","$isChatInputEntityNode","onChatInputEntityAdded","onChatInputEntityDeleted","__deleteDirection","registerCommand","isBackward","registerNodeTransform","nextSibling","getNextSibling","selection","shouldMoveSelection","isCollapsed","anchor","offset","getIndexWithinParent","insertAfter","getPreviousSibling","insertBefore","registerMutationListener","nodes","payload","nodeKey","mutation","prevEditorState","noop"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";AACA,SACEA,oBAAoB,EACpBC,eAAe,EACfC,aAAa,EACbC,aAAa,EACbC,YAAY,EACZC,gBAAgB,EAChBC,iBAAiB,EACjBC,mBAAmB,EACnBC,YAAY,EACZC,kBAAkB,EAClBC,yBAAyB,EACzBC,wBAAwB,EACxBC,aAAa,QACR,gCAAgC;AAGvC,OAAO,MAAMC;IAqBXC,UAAU;QACR,IAAI,CAACC,QAAQ;IACf;IAuFAC,sBAAsBC,KAAwD,EAAsB;QAClG,IAAIC,MAA0BC;QAC9B,IAAI,CAACC,QAAQ,CAACC,MAAM,CAAC;YACnB,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAEC,WAAW,EAAE,GAAGP;YAEpC,MAAMQ,aAAa,IAAI,CAACC,aAAa,CAAC,IAAI,CAACC,IAAI,EAAEL,MAAMC,MAAMC;YAE7DpB,aAAa;gBAACqB;aAAW;YACzBA,WAAWG,SAAS;YACpB,IAAIrB,oBAAoBkB,WAAWI,gBAAgB,KAAK;gBACtDpB,mBAAmBgB,YAAYzB,sBAAsB4B,SAAS;YAChE;YAEAV,MAAMO,WAAWK,MAAM;QACzB;QAEA,OAAOZ;IACT;IACAa,sBACEC,cAA4G,EAC5G;QACA,IAAI,CAACZ,QAAQ,CAACC,MAAM,CAAC;YACnB,IAAI,OAAOW,mBAAmB,YAAY;gBACxCxB,aAAa,IAAI,CAACyB,WAAW,EAC1BC,MAAM,CAAC,CAACC,MAAMC,IAAMD,KAAKE,UAAU,KAAK,IAAI,CAACV,IAAI,IAAIK,eAAeG,KAAKG,aAAa,IAAIF,IAC1FG,OAAO,CAACJ,CAAAA,OAAQA,KAAKK,MAAM;YAChC,OAAO;oBACLtC;iBAAAA,iBAAAA,cAAc8B,6BAAd9B,qCAAAA,eAA+BsC,MAAM;YACvC;QACF;IACF;IACAC,2BACET,cAA4G,EAC5Gf,KAI2D,EAC3D;QACA,MAAMyB,aAAa,CAACP;YAClB,MAAMQ,WAAW,OAAO1B,UAAU,aAAaA,MAAMkB,KAAKG,aAAa,MAAMrB;YAC7EkB,KAAKS,gBAAgB,CAACD;QACxB;QAEA,IAAI,CAACvB,QAAQ,CAACC,MAAM,CAClB;YACE,IAAI,OAAOW,mBAAmB,YAAY;gBACxCxB,aAAa,IAAI,CAACyB,WAAW,EAC1BC,MAAM,CAAC,CAACC,MAAMC,IAAMD,KAAKE,UAAU,KAAK,IAAI,CAACV,IAAI,IAAIK,eAAeG,KAAKG,aAAa,IAAIF,IAC1FG,OAAO,CAACG;YACb,OAAO;gBACL,MAAMP,OAAOjC,cAAwB8B;gBACrC,IAAIG,MAAM;oBACRO,WAAWP;gBACb;YACF;QACF,GACA;YAAEU,KAAK;QAAW;IAEtB;IAEAC,oBAAyE;QACvE,OAAO,IAAI,CAAC1B,QAAQ,CAAC2B,cAAc,GAAGC,IAAI,CAAC,IACzCxC,aAAa,IAAI,CAACyB,WAAW,EAC1BC,MAAM,CAACC,CAAAA,OAAQA,KAAKE,UAAU,KAAK,IAAI,CAACV,IAAI,EAC5CsB,GAAG,CAACd,CAAAA,OAAQA,KAAKG,aAAa;IAErC;IAxJAY,YACEC,MAAqB,EACrBC,EAAU,EACVC,SAA0B,EAC1BC,WAMa,EACbC,sBAAsE,EACtEC,sBAA4F,EAC5FC,wBAA8F,CAC9F;QAjCF,uBAAQxB,eAAR,KAAA;QACA,uBAAQb,YAAR,KAAA;QACA,uBAAQO,QAAR,KAAA;QAEA,uBAAQ+B,qBAAmD;QAC3D,uBAAQhC,iBAAR,KAAA;QAQA,uBAAQX,YAAR,KAAA;QAqBE,IAAI,CAACW,aAAa,GAAG4B;QACrB,IAAI,CAAClC,QAAQ,GAAG+B;QAChB,IAAI,CAACxB,IAAI,GAAGyB;QACZ,IAAI,CAACnB,WAAW,GAAGoB;QAEnB,IAAI,CAACtC,QAAQ,GAAGH,cACd,iGAAiG;QACjGuC,OAAOQ,eAAe,CACpBhD,0BACAiD,CAAAA;YACE,IAAI,CAACF,iBAAiB,GAAGE,aAAa,aAAa;YACnD,OAAO;QACT,GACAlD,4BAEF,sGAAsG;QACtGyC,OAAOU,qBAAqB,CAAC,IAAI,CAAC5B,WAAW,EAAEE,CAAAA;YAC7C,MAAM2B,cAAc3B,KAAK4B,cAAc;YACvC,IAAI,CAACD,eAAezD,iBAAiByD,cAAc;gBACjD,MAAME,YAAY7D;gBAElB,2FAA2F;gBAC3F,kFAAkF;gBAClF,6FAA6F;gBAC7F,4DAA4D;gBAC5D,MAAM8D,sBACJD,aACA1D,kBAAkB0D,cAClBA,UAAUE,WAAW,MACrBF,UAAUG,MAAM,CAACC,MAAM,KAAKjC,KAAKkC,oBAAoB,KAAK;gBAC5D,MAAM/C,OAAOrB,gBAAgB;gBAC7BkC,KAAKmC,WAAW,CAAChD;gBACjB,IAAI2C,qBAAqB;oBACvB,IAAI,IAAI,CAACP,iBAAiB,KAAK,WAAW;wBACxCpC,KAAKM,SAAS;oBAChB,OAAO;wBACLO,KAAKP,SAAS;oBAChB;gBACF;YACF;YAEA,uEAAuE;YACvE,IAAI,CAACO,KAAKoC,kBAAkB,IAAI;gBAC9B,MAAMjD,OAAOrB,gBAAgB;gBAC7BkC,KAAKqC,YAAY,CAAClD;YACpB;QACF,IACAkC,0BAA0BC,2BACtBN,OAAOsB,wBAAwB,CAAC,IAAI,CAACxC,WAAW,EAAE,CAACyC,OAAOC;YACxD,KAAK,MAAM,CAACC,SAASC,SAAS,IAAIH,MAAO;gBACvC,IAAIjB,4BAA4BoB,aAAa,aAAa;oBACxDF,QAAQG,eAAe,CAAC9B,IAAI,CAAC;wBAC3B,MAAMb,OAAOjC,cAAc0E;wBAC3B,IAAIrB,uBAAuBpB,SAASA,KAAKE,UAAU,KAAKe,IAAI;4BAC1DK,yBAAyBtB,KAAKG,aAAa;wBAC7C;oBACF;gBACF,OAAO,IAAIkB,0BAA0BqB,aAAa,WAAW;oBAC3D1B,OAAOJ,cAAc,GAAGC,IAAI,CAAC;wBAC3B,MAAMb,OAAOjC,cAAc0E;wBAC3B,IAAIrB,uBAAuBpB,SAASA,KAAKE,UAAU,KAAKe,IAAI;4BAC1DI,uBAAuBrB,KAAKG,aAAa;wBAC3C;oBACF;gBACF;YACF;QACF,KACAyC;IAER;AAqEF;AAEA,SAASA;IACP;AACF"}
1
+ {"version":3,"sources":["ChatInputEntityPlugin.base.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey, Klass } from '@fluentui-copilot/text-editor';\nimport {\n $createParagraphNode,\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $insertNodes,\n $isDecoratorNode,\n $isRangeSelection,\n $isRootOrShadowRoot,\n $nodesOfType,\n $wrapNodeInElement,\n COMMAND_PRIORITY_CRITICAL,\n DELETE_CHARACTER_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport type {\n ChatInputEntityData,\n ChatInputEntityPluginProps,\n IChatInputEntityPluginBase,\n IEntityNode,\n} from './ChatInputEntityPlugin.types';\n\nexport class ChatInputEntityPluginBase<\n ExtraDataType,\n NodePropsType,\n NodeType extends IEntityNode<ExtraDataType, NodePropsType>,\n> implements IChatInputEntityPluginBase<ExtraDataType, NodePropsType>\n{\n private __nodeClass: Klass<NodeType>;\n private __editor: LexicalEditor;\n private __id: string;\n\n private __deleteDirection: 'forward' | 'backward' | null = null;\n private __$createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType;\n\n private _cleanup: () => void;\n\n cleanup() {\n this._cleanup();\n }\n\n constructor(\n editor: LexicalEditor,\n id: string,\n nodeClass: Klass<NodeType>,\n $createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType,\n $isChatInputEntityNode: (node: LexicalNode | null) => node is NodeType,\n onChatInputEntityAdded?: ChatInputEntityPluginProps<ExtraDataType, NodePropsType>['onChatInputEntityAdded'],\n onChatInputEntityDeleted?: ChatInputEntityPluginProps<ExtraDataType, NodePropsType>['onChatInputEntityDeleted'],\n ) {\n this.__$createNode = $createNode;\n this.__editor = editor;\n this.__id = id;\n this.__nodeClass = nodeClass;\n\n this._cleanup = mergeRegister(\n // Keep track of delete direction so we know where to put the selection after adding back a space\n editor.registerCommand(\n DELETE_CHARACTER_COMMAND,\n isBackward => {\n this.__deleteDirection = isBackward ? 'backward' : 'forward';\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n ),\n // Always maintain a space before, after, and between entities in order for selection to work properly\n editor.registerNodeTransform(this.__nodeClass, node => {\n const nextSibling = node.getNextSibling();\n if (!nextSibling || $isDecoratorNode(nextSibling)) {\n const selection = $getSelection();\n\n // If selection is between the two nodes, that means the user is trying to delete the space\n // If they deleted to the left, we should move the cursor to the end of the entity\n // If they delete to the right, we should move the cursor to the end of the newly added space\n // This mimics changing the delete into a cursor move action\n const shouldMoveSelection =\n selection &&\n $isRangeSelection(selection) &&\n selection.isCollapsed() &&\n selection.anchor.offset === node.getIndexWithinParent() + 1;\n const text = $createTextNode(' ');\n node.insertAfter(text);\n if (shouldMoveSelection) {\n if (this.__deleteDirection === 'forward') {\n text.selectEnd();\n } else {\n node.selectEnd();\n }\n }\n }\n\n // In the case the entity is the first node, we need a space before it.\n if (!node.getPreviousSibling()) {\n const text = $createTextNode(' ');\n node.insertBefore(text);\n }\n }),\n onChatInputEntityAdded || onChatInputEntityDeleted\n ? editor.registerMutationListener(this.__nodeClass, (nodes, payload) => {\n for (const [nodeKey, mutation] of nodes) {\n if (onChatInputEntityDeleted && mutation === 'destroyed') {\n payload.prevEditorState.read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityDeleted(node.getEntityData(), nodeKey);\n }\n });\n } else if (onChatInputEntityAdded && mutation === 'created') {\n editor.getEditorState().read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityAdded(node.getEntityData(), nodeKey);\n }\n });\n }\n }\n })\n : noop,\n );\n }\n insertChatInputEntity(props: ChatInputEntityData<ExtraDataType, NodePropsType>): string | undefined {\n let key: string | undefined = undefined;\n this.__editor.update(() => {\n const { text, data, entityProps } = props;\n\n const entityNode = this.__$createNode(this.__id, text, data, entityProps);\n\n $insertNodes([entityNode]);\n entityNode.selectEnd();\n if ($isRootOrShadowRoot(entityNode.getParentOrThrow())) {\n $wrapNodeInElement(entityNode, $createParagraphNode).selectEnd();\n }\n\n key = entityNode.getKey();\n });\n\n return key;\n }\n removeChatInputEntity(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) {\n this.__editor.update(() => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(node => node.remove());\n } else {\n $getNodeByKey(keyOrPredicate)?.remove();\n }\n });\n }\n updateChatInputEntityProps(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) {\n const updateNode = (node: NodeType) => {\n const newProps = typeof props === 'function' ? props(node.getEntityData()) : props;\n node.updateEntityData(newProps);\n };\n\n this.__editor.update(\n () => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(updateNode);\n } else {\n const node = $getNodeByKey<NodeType>(keyOrPredicate);\n if (node) {\n updateNode(node);\n }\n }\n },\n { tag: 'historic' },\n );\n }\n\n getActiveEntities(): ChatInputEntityData<ExtraDataType, NodePropsType>[] {\n return this.__editor.getEditorState().read(() =>\n $nodesOfType(this.__nodeClass)\n .filter(node => node.__pluginId === this.__id)\n .map(node => node.getEntityData()),\n );\n }\n}\n\nfunction noop() {\n return;\n}\n"],"names":["$createParagraphNode","$createTextNode","$getNodeByKey","$getSelection","$insertNodes","$isDecoratorNode","$isRangeSelection","$isRootOrShadowRoot","$nodesOfType","$wrapNodeInElement","COMMAND_PRIORITY_CRITICAL","DELETE_CHARACTER_COMMAND","mergeRegister","ChatInputEntityPluginBase","cleanup","_cleanup","insertChatInputEntity","props","key","undefined","__editor","update","text","data","entityProps","entityNode","__$createNode","__id","selectEnd","getParentOrThrow","getKey","removeChatInputEntity","keyOrPredicate","__nodeClass","filter","node","i","__pluginId","getEntityData","forEach","remove","updateChatInputEntityProps","updateNode","newProps","updateEntityData","tag","getActiveEntities","getEditorState","read","map","constructor","editor","id","nodeClass","$createNode","$isChatInputEntityNode","onChatInputEntityAdded","onChatInputEntityDeleted","__deleteDirection","registerCommand","isBackward","registerNodeTransform","nextSibling","getNextSibling","selection","shouldMoveSelection","isCollapsed","anchor","offset","getIndexWithinParent","insertAfter","getPreviousSibling","insertBefore","registerMutationListener","nodes","payload","nodeKey","mutation","prevEditorState","noop"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["ChatInputEntityPlugin.types.ts"],"sourcesContent":["import type { LexicalNode } from '@fluentui-copilot/text-editor';\n\nexport type ChatInputEntityData<ExtraDataType, NodePropsType> = {\n // Represents the string content of the entity that will returned inside the ChatInput's text content\n text: string;\n // Props to pass to the component rendered by the node\n // By default, `text` will be used as the entity's text content.\n // If entityProps contains information for rendering children, that will take priority\n entityProps?: NodePropsType;\n // Optional extra data that can be associated with the entity\n data?: ExtraDataType;\n};\n\nexport type ChatInputEntityPluginProps<ExtraDataType, NodePropsType> = {\n // An identifier for an instance of the ChatInputEntityPlugin\n // Only entities created by this instance of the plugin will be handled by it\n id: string;\n onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n};\n\n/**\n * A lexical node representing an entity should conform to this interface\n */\nexport interface IEntityNode<ExtraDataType, NodePropsType> extends LexicalNode {\n getEntityData: () => ChatInputEntityData<ExtraDataType, NodePropsType>;\n updateEntityData: (data: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n __pluginId: string;\n}\n\nexport interface IChatInputEntityPluginBase<ExtraDataType, NodePropsType> {\n // Inserts a new entity and returns its key, to be used by removeChatInputEntity or updateChatInputEntityProps\n insertChatInputEntity: (props: ChatInputEntityData<ExtraDataType, NodePropsType>) => string | undefined;\n // Removes an entity by its key, or removes all entities that match a predicate function\n removeChatInputEntity: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) => void;\n // Updates an entity by its key, or removes all entities that match a predicate function\n updateChatInputEntityProps: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) => void;\n getActiveEntities: () => ChatInputEntityData<ExtraDataType, NodePropsType>[];\n}\n"],"names":[],"rangeMappings":"","mappings":"AA8BA,WAiBC"}
1
+ {"version":3,"sources":["ChatInputEntityPlugin.types.ts"],"sourcesContent":["import type { LexicalNode, NodeKey } from '@fluentui-copilot/text-editor';\n\nexport type ChatInputEntityData<ExtraDataType, NodePropsType> = {\n // Represents the string content of the entity that will returned inside the ChatInput's text content\n text: string;\n // Props to pass to the component rendered by the node\n // By default, `text` will be used as the entity's text content.\n // If entityProps contains information for rendering children, that will take priority\n entityProps?: NodePropsType;\n // Optional extra data that can be associated with the entity\n data?: ExtraDataType;\n};\n\nexport type ChatInputEntityPluginProps<ExtraDataType, NodePropsType> = {\n // An identifier for an instance of the ChatInputEntityPlugin\n // Only entities created by this instance of the plugin will be handled by it\n id: string;\n onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>, nodeKey: NodeKey) => void;\n onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>, nodeKey: NodeKey) => void;\n};\n\n/**\n * A lexical node representing an entity should conform to this interface\n */\nexport interface IEntityNode<ExtraDataType, NodePropsType> extends LexicalNode {\n getEntityData: () => ChatInputEntityData<ExtraDataType, NodePropsType>;\n updateEntityData: (data: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n __pluginId: string;\n}\n\nexport interface IChatInputEntityPluginBase<ExtraDataType, NodePropsType> {\n // Inserts a new entity and returns its key, to be used by removeChatInputEntity or updateChatInputEntityProps\n insertChatInputEntity: (props: ChatInputEntityData<ExtraDataType, NodePropsType>) => string | undefined;\n // Removes an entity by its key, or removes all entities that match a predicate function\n removeChatInputEntity: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) => void;\n // Updates an entity by its key, or removes all entities that match a predicate function\n updateChatInputEntityProps: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) => void;\n getActiveEntities: () => ChatInputEntityData<ExtraDataType, NodePropsType>[];\n}\n"],"names":[],"rangeMappings":"","mappings":"AA8BA,WAiBC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["PasteUnfurling.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport { PASTE_COMMAND, COMMAND_PRIORITY_HIGH, $insertNodes, $createTextNode } from '@fluentui-copilot/text-editor';\nimport type { PasteUnfurlingPluginProps, TransformedPart } from './PasteUnfurling.types';\n\nfunction unhandledPart(part: never): never {\n throw new Error(`Unhandled part: ${part}`);\n}\n\nexport function registerPasteUnfurlingPlugin<ExtraDataType, NodePropsType>(\n editor: LexicalEditor,\n props: PasteUnfurlingPluginProps<ExtraDataType, NodePropsType>,\n): () => void {\n const { entityPluginId, transforms, $createEntityNode } = props;\n\n function insertParts(parts: TransformedPart<ExtraDataType, NodePropsType>[]) {\n editor.update(() => {\n const nodes = parts.map(part => {\n switch (part.type) {\n case 'entity':\n return $createEntityNode(entityPluginId, part.value.text, part.value.data, part.value.entityProps);\n case 'text':\n return $createTextNode(part.value);\n }\n return unhandledPart(part);\n });\n $insertNodes(nodes);\n });\n }\n\n function handlePaste(event: ClipboardEvent): boolean {\n for (const transform of transforms) {\n const result = transform(event, editor);\n\n if (result.transformedParts) {\n insertParts(result.transformedParts);\n }\n\n if (result.handled) {\n return true;\n }\n }\n\n return false;\n }\n\n return editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_HIGH);\n}\n"],"names":["PASTE_COMMAND","COMMAND_PRIORITY_HIGH","$insertNodes","$createTextNode","unhandledPart","part","Error","registerPasteUnfurlingPlugin","editor","props","entityPluginId","transforms","$createEntityNode","insertParts","parts","update","nodes","map","type","value","text","data","entityProps","handlePaste","event","transform","result","transformedParts","handled","registerCommand"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,aAAa,EAAEC,qBAAqB,EAAEC,YAAY,EAAEC,eAAe,QAAQ,gCAAgC;AAGpH,SAASC,cAAcC,IAAW;IAChC,MAAM,IAAIC,MAAM,CAAC,gBAAgB,EAAED,KAAK,CAAC;AAC3C;AAEA,OAAO,SAASE,6BACdC,MAAqB,EACrBC,KAA8D;IAE9D,MAAM,EAAEC,cAAc,EAAEC,UAAU,EAAEC,iBAAiB,EAAE,GAAGH;IAE1D,SAASI,YAAYC,KAAsD;QACzEN,OAAOO,MAAM,CAAC;YACZ,MAAMC,QAAQF,MAAMG,GAAG,CAACZ,CAAAA;gBACtB,OAAQA,KAAKa,IAAI;oBACf,KAAK;wBACH,OAAON,kBAAkBF,gBAAgBL,KAAKc,KAAK,CAACC,IAAI,EAAEf,KAAKc,KAAK,CAACE,IAAI,EAAEhB,KAAKc,KAAK,CAACG,WAAW;oBACnG,KAAK;wBACH,OAAOnB,gBAAgBE,KAAKc,KAAK;gBACrC;gBACA,OAAOf,cAAcC;YACvB;YACAH,aAAac;QACf;IACF;IAEA,SAASO,YAAYC,KAAqB;QACxC,KAAK,MAAMC,aAAad,WAAY;YAClC,MAAMe,SAASD,UAAUD,OAAOhB;YAEhC,IAAIkB,OAAOC,gBAAgB,EAAE;gBAC3Bd,YAAYa,OAAOC,gBAAgB;YACrC;YAEA,IAAID,OAAOE,OAAO,EAAE;gBAClB,OAAO;YACT;QACF;QAEA,OAAO;IACT;IAEA,OAAOpB,OAAOqB,eAAe,CAAC7B,eAAeuB,aAAatB;AAC5D"}
1
+ {"version":3,"sources":["PasteUnfurling.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport { PASTE_COMMAND, COMMAND_PRIORITY_HIGH, $insertNodes, $createTextNode } from '@fluentui-copilot/text-editor';\nimport type { PasteUnfurlingPluginBaseProps, PasteUnfurlingTransformedPart } from './PasteUnfurling.types';\n\nfunction unhandledPart(part: never): never {\n throw new Error(`Unhandled part: ${part}`);\n}\n\nexport function registerPasteUnfurlingPlugin<ExtraDataType, NodePropsType>(\n editor: LexicalEditor,\n props: PasteUnfurlingPluginBaseProps<ExtraDataType, NodePropsType>,\n): () => void {\n const { entityPluginId, transforms, $createEntityNode } = props;\n\n function insertParts(parts: PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType>[]) {\n editor.update(() => {\n const nodes = parts.map(part => {\n switch (part.type) {\n case 'entity':\n return $createEntityNode(entityPluginId, part.value.text, part.value.data, part.value.entityProps);\n case 'text':\n return $createTextNode(part.value);\n }\n return unhandledPart(part);\n });\n $insertNodes(nodes);\n });\n }\n\n function handlePaste(event: ClipboardEvent): boolean {\n for (const transform of transforms) {\n const result = transform(event, editor);\n\n if (result.transformedParts) {\n insertParts(result.transformedParts);\n }\n\n if (result.handled) {\n return true;\n }\n }\n\n return false;\n }\n\n return editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_HIGH);\n}\n"],"names":["PASTE_COMMAND","COMMAND_PRIORITY_HIGH","$insertNodes","$createTextNode","unhandledPart","part","Error","registerPasteUnfurlingPlugin","editor","props","entityPluginId","transforms","$createEntityNode","insertParts","parts","update","nodes","map","type","value","text","data","entityProps","handlePaste","event","transform","result","transformedParts","handled","registerCommand"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,aAAa,EAAEC,qBAAqB,EAAEC,YAAY,EAAEC,eAAe,QAAQ,gCAAgC;AAGpH,SAASC,cAAcC,IAAW;IAChC,MAAM,IAAIC,MAAM,CAAC,gBAAgB,EAAED,KAAK,CAAC;AAC3C;AAEA,OAAO,SAASE,6BACdC,MAAqB,EACrBC,KAAkE;IAElE,MAAM,EAAEC,cAAc,EAAEC,UAAU,EAAEC,iBAAiB,EAAE,GAAGH;IAE1D,SAASI,YAAYC,KAAoE;QACvFN,OAAOO,MAAM,CAAC;YACZ,MAAMC,QAAQF,MAAMG,GAAG,CAACZ,CAAAA;gBACtB,OAAQA,KAAKa,IAAI;oBACf,KAAK;wBACH,OAAON,kBAAkBF,gBAAgBL,KAAKc,KAAK,CAACC,IAAI,EAAEf,KAAKc,KAAK,CAACE,IAAI,EAAEhB,KAAKc,KAAK,CAACG,WAAW;oBACnG,KAAK;wBACH,OAAOnB,gBAAgBE,KAAKc,KAAK;gBACrC;gBACA,OAAOf,cAAcC;YACvB;YACAH,aAAac;QACf;IACF;IAEA,SAASO,YAAYC,KAAqB;QACxC,KAAK,MAAMC,aAAad,WAAY;YAClC,MAAMe,SAASD,UAAUD,OAAOhB;YAEhC,IAAIkB,OAAOC,gBAAgB,EAAE;gBAC3Bd,YAAYa,OAAOC,gBAAgB;YACrC;YAEA,IAAID,OAAOE,OAAO,EAAE;gBAClB,OAAO;YACT;QACF;QAEA,OAAO;IACT;IAEA,OAAOpB,OAAOqB,eAAe,CAAC7B,eAAeuB,aAAatB;AAC5D"}
@@ -1 +1 @@
1
- {"version":3,"sources":["PasteUnfurling.types.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey } from '@fluentui-copilot/text-editor';\nimport type { ChatInputEntityData } from '../ChatInputEntity';\n\nexport type TransformedPart<ExtraDataType, NodePropsType> =\n | { type: 'text'; value: string }\n | { type: 'entity'; value: ChatInputEntityData<ExtraDataType, NodePropsType> };\n\nexport type TransformResult<ExtraDataType, NodePropsType> = {\n handled: boolean;\n transformedParts?: TransformedPart<ExtraDataType, NodePropsType>[];\n};\n\nexport type TransformFunction<ExtraDataType, NodePropsType> = (\n event: ClipboardEvent,\n editor: LexicalEditor,\n) => TransformResult<ExtraDataType, NodePropsType>;\n\nexport type PasteUnfurlingPluginProps<ExtraDataType, NodePropsType> = {\n entityPluginId: string;\n transforms: TransformFunction<ExtraDataType, NodePropsType>[];\n $createEntityNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => LexicalNode;\n};\n"],"names":[],"rangeMappings":"","mappings":"AAiBA,WAUE"}
1
+ {"version":3,"sources":["PasteUnfurling.types.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey } from '@fluentui-copilot/text-editor';\nimport type { ChatInputEntityData } from '../ChatInputEntity';\n\nexport type PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType> =\n | { type: 'text'; value: string }\n | { type: 'entity'; value: ChatInputEntityData<ExtraDataType, NodePropsType> };\n\nexport type PasteUnfurlingTransformResult<ExtraDataType, NodePropsType> = {\n handled: boolean;\n transformedParts?: PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType>[];\n};\n\nexport type PasteUnfurlingTransformFunction<ExtraDataType, NodePropsType> = (\n event: ClipboardEvent,\n editor: LexicalEditor,\n) => PasteUnfurlingTransformResult<ExtraDataType, NodePropsType>;\n\nexport type PasteUnfurlingPluginBaseProps<ExtraDataType, NodePropsType> = {\n entityPluginId: string;\n transforms: PasteUnfurlingTransformFunction<ExtraDataType, NodePropsType>[];\n $createEntityNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => LexicalNode;\n};\n"],"names":[],"rangeMappings":"","mappings":"AAiBA,WAUE"}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":["export {\n BasicFunctionalityBase,\n SentinelNode,\n $createSentinelNode,\n $isSentinelNode,\n SENTINEL_VALUE,\n} from './BasicFunctionality';\nexport type { IBasicFunctionalityBase } from './BasicFunctionality';\n\nexport { ChatInputEntityPluginBase } from './ChatInputEntity';\nexport type {\n ChatInputEntityData,\n ChatInputEntityPluginProps,\n IChatInputEntityPluginBase,\n IEntityNode,\n} from './ChatInputEntity';\n\nexport { GhostTextPluginBase } from './GhostText';\nexport type { GetGhostTextFunction, IGhostTextNode } from './GhostText';\n\nexport { ImperativeControlBase } from './ImperativeControl';\nexport type { IImperativeControlBase } from './ImperativeControl';\n\nexport { ManualGhostTextBase } from './ManualGhostText';\nexport type { IManualGhostTextBase } from './ManualGhostText';\n\nexport { registerPasteUnfurlingPlugin } from './PasteUnfurling';\nexport type { PasteUnfurlingPluginProps, TransformFunction, TransformedPart, TransformResult } from './PasteUnfurling';\n"],"names":["BasicFunctionalityBase","SentinelNode","$createSentinelNode","$isSentinelNode","SENTINEL_VALUE","ChatInputEntityPluginBase","GhostTextPluginBase","ImperativeControlBase","ManualGhostTextBase","registerPasteUnfurlingPlugin"],"rangeMappings":";;;;;","mappings":"AAAA,SACEA,sBAAsB,EACtBC,YAAY,EACZC,mBAAmB,EACnBC,eAAe,EACfC,cAAc,QACT,uBAAuB;AAG9B,SAASC,yBAAyB,QAAQ,oBAAoB;AAQ9D,SAASC,mBAAmB,QAAQ,cAAc;AAGlD,SAASC,qBAAqB,QAAQ,sBAAsB;AAG5D,SAASC,mBAAmB,QAAQ,oBAAoB;AAGxD,SAASC,4BAA4B,QAAQ,mBAAmB"}
1
+ {"version":3,"sources":["index.ts"],"sourcesContent":["export {\n BasicFunctionalityBase,\n SentinelNode,\n $createSentinelNode,\n $isSentinelNode,\n SENTINEL_VALUE,\n} from './BasicFunctionality';\nexport type { IBasicFunctionalityBase } from './BasicFunctionality';\n\nexport { ChatInputEntityPluginBase } from './ChatInputEntity';\nexport type {\n ChatInputEntityData,\n ChatInputEntityPluginProps,\n IChatInputEntityPluginBase,\n IEntityNode,\n} from './ChatInputEntity';\n\nexport { GhostTextPluginBase } from './GhostText';\nexport type { GetGhostTextFunction, IGhostTextNode } from './GhostText';\n\nexport { ImperativeControlBase } from './ImperativeControl';\nexport type { IImperativeControlBase } from './ImperativeControl';\n\nexport { ManualGhostTextBase } from './ManualGhostText';\nexport type { IManualGhostTextBase } from './ManualGhostText';\n\nexport { registerPasteUnfurlingPlugin } from './PasteUnfurling';\nexport type {\n PasteUnfurlingPluginBaseProps,\n PasteUnfurlingTransformFunction,\n PasteUnfurlingTransformedPart,\n PasteUnfurlingTransformResult,\n} from './PasteUnfurling';\n"],"names":["BasicFunctionalityBase","SentinelNode","$createSentinelNode","$isSentinelNode","SENTINEL_VALUE","ChatInputEntityPluginBase","GhostTextPluginBase","ImperativeControlBase","ManualGhostTextBase","registerPasteUnfurlingPlugin"],"rangeMappings":";;;;;","mappings":"AAAA,SACEA,sBAAsB,EACtBC,YAAY,EACZC,mBAAmB,EACnBC,eAAe,EACfC,cAAc,QACT,uBAAuB;AAG9B,SAASC,yBAAyB,QAAQ,oBAAoB;AAQ9D,SAASC,mBAAmB,QAAQ,cAAc;AAGlD,SAASC,qBAAqB,QAAQ,sBAAsB;AAG5D,SAASC,mBAAmB,QAAQ,oBAAoB;AAGxD,SAASC,4BAA4B,QAAQ,mBAAmB"}
@@ -123,8 +123,10 @@ class BasicFunctionalityBase {
123
123
  var // We find the node by its key again in case the node was removed before this update runs
124
124
  _$getNodeByKey;
125
125
  (_$getNodeByKey = (0, _texteditor.$getNodeByKey)(lastNodeKey)) === null || _$getNodeByKey === void 0 ? void 0 : _$getNodeByKey.insertAfter((0, _SentinelNode.$createSentinelNode)());
126
- }, {
127
- discrete: true
126
+ }, // historic tag prevents every sentinel node addition from being added to LexicalHistoryPlugin undo stack
127
+ {
128
+ discrete: true,
129
+ tag: 'historic'
128
130
  });
129
131
  return;
130
132
  }
@@ -144,8 +146,6 @@ class BasicFunctionalityBase {
144
146
  this.__editor.update(()=>{
145
147
  var _$getNodeByKey;
146
148
  (_$getNodeByKey = (0, _texteditor.$getNodeByKey)(lastNodeKey)) === null || _$getNodeByKey === void 0 ? void 0 : _$getNodeByKey.selectStart();
147
- }, {
148
- discrete: true
149
149
  });
150
150
  return;
151
151
  }
@@ -166,8 +166,6 @@ class BasicFunctionalityBase {
166
166
  if ((0, _texteditor.$getNodeByKey)(lastNodeKey) !== null) {
167
167
  (0, _texteditor.$setSelection)((0, _texteditor.$normalizeSelection__EXPERIMENTAL)(newSelection));
168
168
  }
169
- }, {
170
- discrete: true
171
169
  });
172
170
  }
173
171
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["BasicFunctionality.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport {\n $createTextNode,\n $getLeafNodes,\n $getNodeByKey,\n $getRoot,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n $normalizeSelection__EXPERIMENTAL,\n $setSelection,\n COMMAND_PRIORITY_CRITICAL,\n INSERT_PARAGRAPH_COMMAND,\n KEY_ENTER_COMMAND,\n PASTE_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport { $createSentinelNode, $isSentinelNode, SENTINEL_VALUE, SentinelNode } from './SentinelNode';\n\nexport interface IBasicFunctionalityBase {\n insertDefaultValue: (defaultValue: string) => void;\n setIsDisabled: (isDisabled: boolean) => void;\n activateContentCallbacks(onContentChange?: (value: string) => void, onCountChanged?: (count: number) => void): void;\n deactivateContentCallbacks(): void;\n activateTrimWhitespace(): void;\n deactivateTrimWhitespace(): void;\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void): void;\n deactivatePasteCallback(): void;\n cleanup(): void;\n}\n\nexport class BasicFunctionalityBase implements IBasicFunctionalityBase {\n private __editor: LexicalEditor;\n private __contentChangeCleanup?: () => void;\n private __trimWhitespaceCleanup?: () => void;\n private __baseHandlersCleanup?: () => void;\n private __pasteHandlerCleanup?: () => void;\n\n private __enterHandler(event: KeyboardEvent) {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n\n if (event === null) {\n return false;\n }\n\n event.preventDefault();\n\n if (event.shiftKey) {\n return this.__editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);\n }\n\n // Mark event handled to override default behavior\n return true;\n }\n\n constructor(editor: LexicalEditor) {\n this.__editor = editor;\n\n this.__baseHandlersCleanup = mergeRegister(\n this.__editor.registerCommand(KEY_ENTER_COMMAND, this.__enterHandler.bind(this), COMMAND_PRIORITY_CRITICAL),\n\n // Add a sentinel node at the end of the input when there is content.\n // This sentinel node fixes a number of issues.\n // In Safari, Lexical's behaviour of adding <br /> tags to the end of the input when it ends\n // in a decorator node causes cursor location issues: https://github.com/facebook/lexical/issues/4487\n // Otherwise, when a decorator node is the last node in the input, the cursor can't move past it.\n // Adding an invisible text node that doesn't contribute to the content and can't be selected to the end of the input\n // mitigates these issues.\n this.__editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const leaves = $getLeafNodes($getRoot());\n if (leaves.length === 0) {\n return;\n }\n\n const lastNode = leaves[leaves.length - 1];\n const lastNodeKey = lastNode.getKey();\n\n // If the last node isn't a sentinel, add one\n if (!$isSentinelNode(lastNode)) {\n this.__editor.update(\n () => {\n // We find the node by its key again in case the node was removed before this update runs\n $getNodeByKey(lastNodeKey)?.insertAfter($createSentinelNode());\n },\n { discrete: true },\n );\n return;\n }\n\n // If the sentinel node is not selected, we're done\n const previous = lastNode.getPreviousSibling();\n if (!previous || !lastNode.isSelected()) {\n return;\n }\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return;\n }\n\n // If the cursor is inside the sentinel node, move it out (next to the beginning)\n // We allow selection on the boundary of the sentinel in case the adjacent node is a decorator node\n // where selection is ill-defined.\n if (selection.isCollapsed() && selection.anchor.offset > 0) {\n this.__editor.update(\n () => {\n $getNodeByKey(lastNodeKey)?.selectStart();\n },\n { discrete: true },\n );\n return;\n }\n\n // If the selection is a range which includes the sentinel, modify the range to exclude it\n if (!selection.isCollapsed()) {\n let selectionChanged = false;\n const newSelection = selection.clone();\n\n if (newSelection.anchor.getNode() === lastNode && newSelection.anchor.offset > 0) {\n newSelection.anchor.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n if (newSelection.focus.getNode() === lastNode && newSelection.focus.offset > 0) {\n newSelection.focus.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n\n if (selectionChanged) {\n this.__editor.update(\n () => {\n if ($getNodeByKey(lastNodeKey) !== null) {\n $setSelection($normalizeSelection__EXPERIMENTAL(newSelection));\n }\n },\n { discrete: true },\n );\n }\n }\n });\n }),\n this.__editor.registerNodeTransform(SentinelNode, node => {\n if (!node.getPreviousSibling() || node.getNextSibling()) {\n node.remove();\n return;\n }\n }),\n );\n }\n\n insertDefaultValue(defaultValue: string) {\n if (defaultValue) {\n this.__editor.update(() => {\n $insertNodes([$createTextNode(defaultValue)]);\n });\n }\n }\n\n activateContentCallbacks(\n onContentChange?: ((value: string) => void) | undefined,\n onCountChanged?: ((count: number) => void) | undefined,\n ) {\n this.deactivateContentCallbacks();\n this.__contentChangeCleanup = this.__editor.registerTextContentListener(text => {\n // Remove the sentinel node\n const processed = text.replace(SENTINEL_VALUE, '');\n onContentChange?.(processed);\n onCountChanged?.(processed.length);\n });\n }\n\n deactivateContentCallbacks() {\n this.__contentChangeCleanup?.();\n this.__contentChangeCleanup = undefined;\n }\n\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void) {\n this.__pasteHandlerCleanup = this.__editor.registerCommand(\n PASTE_COMMAND,\n (event: ClipboardEvent) => {\n onPaste(event);\n\n if (event.defaultPrevented) {\n return true;\n }\n\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n }\n\n deactivatePasteCallback() {\n this.__pasteHandlerCleanup?.();\n this.__pasteHandlerCleanup = undefined;\n }\n\n activateTrimWhitespace() {\n this.deactivateTrimWhitespace();\n this.__trimWhitespaceCleanup = this.__editor.registerTextContentListener(text => {\n if (text.trim() === '') {\n this.__editor.update(\n () => {\n $getRoot()\n .getAllTextNodes()\n .forEach(node => {\n node.remove();\n });\n },\n // Don't allow undoing this action\n { tag: 'historic' },\n );\n }\n });\n }\n\n deactivateTrimWhitespace() {\n this.__trimWhitespaceCleanup?.();\n this.__trimWhitespaceCleanup = undefined;\n }\n\n setIsDisabled(isDisabled: boolean) {\n this.__editor.setEditable(!isDisabled);\n }\n\n cleanup() {\n this.deactivateContentCallbacks();\n this.deactivateTrimWhitespace();\n this.deactivatePasteCallback();\n this.__baseHandlersCleanup?.();\n this.__baseHandlersCleanup = undefined;\n }\n}\n"],"names":["BasicFunctionalityBase","__enterHandler","event","selection","$getSelection","$isRangeSelection","preventDefault","shiftKey","__editor","dispatchCommand","INSERT_PARAGRAPH_COMMAND","insertDefaultValue","defaultValue","update","$insertNodes","onContentChange","onCountChanged","deactivateContentCallbacks","activateContentCallbacks","text","processed","__contentChangeCleanup","SENTINEL_VALUE","registerTextContentListener","length","_this___contentChangeCleanup","_this","call","undefined","__pasteHandlerCleanup","registerCommand","PASTE_COMMAND","activatePasteCallback","onPaste","COMMAND_PRIORITY_CRITICAL","_this___pasteHandlerCleanup","deactivatePasteCallback","deactivateTrimWhitespace","activateTrimWhitespace","__trimWhitespaceCleanup","trim","forEach","node","remove","_this___trimWhitespaceCleanup","isDisabled","setIsDisabled","cleanup","__baseHandlersCleanup","_this___baseHandlersCleanup","editor","constructor","registerUpdateListener","editorState","read","leaves","$getLeafNodes","$getRoot","$isSentinelNode","lastNode","$getNodeByKey","lastNodeKey","_$getNodeByKey","insertAfter","$createSentinelNode","getPreviousSibling","selectStart","isCollapsed","newSelection","anchor","selectionChanged","getNode","offset","focus","$setSelection","discrete","registerNodeTransform","SentinelNode","getNextSibling"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["BasicFunctionality.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport {\n $createTextNode,\n $getLeafNodes,\n $getNodeByKey,\n $getRoot,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n $normalizeSelection__EXPERIMENTAL,\n $setSelection,\n COMMAND_PRIORITY_CRITICAL,\n INSERT_PARAGRAPH_COMMAND,\n KEY_ENTER_COMMAND,\n PASTE_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport { $createSentinelNode, $isSentinelNode, SENTINEL_VALUE, SentinelNode } from './SentinelNode';\n\nexport interface IBasicFunctionalityBase {\n insertDefaultValue: (defaultValue: string) => void;\n setIsDisabled: (isDisabled: boolean) => void;\n activateContentCallbacks(onContentChange?: (value: string) => void, onCountChanged?: (count: number) => void): void;\n deactivateContentCallbacks(): void;\n activateTrimWhitespace(): void;\n deactivateTrimWhitespace(): void;\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void): void;\n deactivatePasteCallback(): void;\n cleanup(): void;\n}\n\nexport class BasicFunctionalityBase implements IBasicFunctionalityBase {\n private __editor: LexicalEditor;\n private __contentChangeCleanup?: () => void;\n private __trimWhitespaceCleanup?: () => void;\n private __baseHandlersCleanup?: () => void;\n private __pasteHandlerCleanup?: () => void;\n\n private __enterHandler(event: KeyboardEvent) {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return false;\n }\n\n if (event === null) {\n return false;\n }\n\n event.preventDefault();\n\n if (event.shiftKey) {\n return this.__editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);\n }\n\n // Mark event handled to override default behavior\n return true;\n }\n\n constructor(editor: LexicalEditor) {\n this.__editor = editor;\n\n this.__baseHandlersCleanup = mergeRegister(\n this.__editor.registerCommand(KEY_ENTER_COMMAND, this.__enterHandler.bind(this), COMMAND_PRIORITY_CRITICAL),\n\n // Add a sentinel node at the end of the input when there is content.\n // This sentinel node fixes a number of issues.\n // In Safari, Lexical's behaviour of adding <br /> tags to the end of the input when it ends\n // in a decorator node causes cursor location issues: https://github.com/facebook/lexical/issues/4487\n // Otherwise, when a decorator node is the last node in the input, the cursor can't move past it.\n // Adding an invisible text node that doesn't contribute to the content and can't be selected to the end of the input\n // mitigates these issues.\n this.__editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const leaves = $getLeafNodes($getRoot());\n if (leaves.length === 0) {\n return;\n }\n\n const lastNode = leaves[leaves.length - 1];\n const lastNodeKey = lastNode.getKey();\n\n // If the last node isn't a sentinel, add one\n if (!$isSentinelNode(lastNode)) {\n this.__editor.update(\n () => {\n // We find the node by its key again in case the node was removed before this update runs\n $getNodeByKey(lastNodeKey)?.insertAfter($createSentinelNode());\n },\n // historic tag prevents every sentinel node addition from being added to LexicalHistoryPlugin undo stack\n { discrete: true, tag: 'historic' },\n );\n return;\n }\n\n // If the sentinel node is not selected, we're done\n const previous = lastNode.getPreviousSibling();\n if (!previous || !lastNode.isSelected()) {\n return;\n }\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return;\n }\n\n // If the cursor is inside the sentinel node, move it out (next to the beginning)\n // We allow selection on the boundary of the sentinel in case the adjacent node is a decorator node\n // where selection is ill-defined.\n if (selection.isCollapsed() && selection.anchor.offset > 0) {\n this.__editor.update(() => {\n $getNodeByKey(lastNodeKey)?.selectStart();\n });\n return;\n }\n\n // If the selection is a range which includes the sentinel, modify the range to exclude it\n if (!selection.isCollapsed()) {\n let selectionChanged = false;\n const newSelection = selection.clone();\n\n if (newSelection.anchor.getNode() === lastNode && newSelection.anchor.offset > 0) {\n newSelection.anchor.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n if (newSelection.focus.getNode() === lastNode && newSelection.focus.offset > 0) {\n newSelection.focus.set(lastNodeKey, 0, 'text');\n selectionChanged = true;\n }\n\n if (selectionChanged) {\n this.__editor.update(() => {\n if ($getNodeByKey(lastNodeKey) !== null) {\n $setSelection($normalizeSelection__EXPERIMENTAL(newSelection));\n }\n });\n }\n }\n });\n }),\n this.__editor.registerNodeTransform(SentinelNode, node => {\n if (!node.getPreviousSibling() || node.getNextSibling()) {\n node.remove();\n return;\n }\n }),\n );\n }\n\n insertDefaultValue(defaultValue: string) {\n if (defaultValue) {\n this.__editor.update(() => {\n $insertNodes([$createTextNode(defaultValue)]);\n });\n }\n }\n\n activateContentCallbacks(\n onContentChange?: ((value: string) => void) | undefined,\n onCountChanged?: ((count: number) => void) | undefined,\n ) {\n this.deactivateContentCallbacks();\n this.__contentChangeCleanup = this.__editor.registerTextContentListener(text => {\n // Remove the sentinel node\n const processed = text.replace(SENTINEL_VALUE, '');\n onContentChange?.(processed);\n onCountChanged?.(processed.length);\n });\n }\n\n deactivateContentCallbacks() {\n this.__contentChangeCleanup?.();\n this.__contentChangeCleanup = undefined;\n }\n\n activatePasteCallback(onPaste: (event: ClipboardEvent) => void) {\n this.__pasteHandlerCleanup = this.__editor.registerCommand(\n PASTE_COMMAND,\n (event: ClipboardEvent) => {\n onPaste(event);\n\n if (event.defaultPrevented) {\n return true;\n }\n\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n }\n\n deactivatePasteCallback() {\n this.__pasteHandlerCleanup?.();\n this.__pasteHandlerCleanup = undefined;\n }\n\n activateTrimWhitespace() {\n this.deactivateTrimWhitespace();\n this.__trimWhitespaceCleanup = this.__editor.registerTextContentListener(text => {\n if (text.trim() === '') {\n this.__editor.update(\n () => {\n $getRoot()\n .getAllTextNodes()\n .forEach(node => {\n node.remove();\n });\n },\n // Don't allow undoing this action\n { tag: 'historic' },\n );\n }\n });\n }\n\n deactivateTrimWhitespace() {\n this.__trimWhitespaceCleanup?.();\n this.__trimWhitespaceCleanup = undefined;\n }\n\n setIsDisabled(isDisabled: boolean) {\n this.__editor.setEditable(!isDisabled);\n }\n\n cleanup() {\n this.deactivateContentCallbacks();\n this.deactivateTrimWhitespace();\n this.deactivatePasteCallback();\n this.__baseHandlersCleanup?.();\n this.__baseHandlersCleanup = undefined;\n }\n}\n"],"names":["BasicFunctionalityBase","__enterHandler","event","selection","$getSelection","$isRangeSelection","preventDefault","shiftKey","__editor","dispatchCommand","INSERT_PARAGRAPH_COMMAND","insertDefaultValue","defaultValue","update","$insertNodes","onContentChange","onCountChanged","deactivateContentCallbacks","activateContentCallbacks","text","processed","__contentChangeCleanup","SENTINEL_VALUE","registerTextContentListener","length","_this___contentChangeCleanup","_this","call","undefined","__pasteHandlerCleanup","registerCommand","PASTE_COMMAND","activatePasteCallback","onPaste","COMMAND_PRIORITY_CRITICAL","_this___pasteHandlerCleanup","deactivatePasteCallback","deactivateTrimWhitespace","activateTrimWhitespace","__trimWhitespaceCleanup","trim","forEach","node","remove","_this___trimWhitespaceCleanup","isDisabled","setIsDisabled","cleanup","__baseHandlersCleanup","_this___baseHandlersCleanup","editor","constructor","registerUpdateListener","editorState","read","leaves","$getLeafNodes","$getRoot","$isSentinelNode","lastNode","$getNodeByKey","discrete","lastNodeKey","_$getNodeByKey","insertAfter","$createSentinelNode","isCollapsed","anchor","offset","selectStart","newSelection","selectionChanged","clone","focus","getNode","$setSelection","$normalizeSelection__EXPERIMENTAL","registerNodeTransform","SentinelNode","getPreviousSibling","getNextSibling"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -107,14 +107,14 @@ class ChatInputEntityPluginBase {
107
107
  payload.prevEditorState.read(()=>{
108
108
  const node = (0, _texteditor.$getNodeByKey)(nodeKey);
109
109
  if ($isChatInputEntityNode(node) && node.__pluginId === id) {
110
- onChatInputEntityDeleted(node.getEntityData());
110
+ onChatInputEntityDeleted(node.getEntityData(), nodeKey);
111
111
  }
112
112
  });
113
113
  } else if (onChatInputEntityAdded && mutation === 'created') {
114
114
  editor.getEditorState().read(()=>{
115
115
  const node = (0, _texteditor.$getNodeByKey)(nodeKey);
116
116
  if ($isChatInputEntityNode(node) && node.__pluginId === id) {
117
- onChatInputEntityAdded(node.getEntityData());
117
+ onChatInputEntityAdded(node.getEntityData(), nodeKey);
118
118
  }
119
119
  });
120
120
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["ChatInputEntityPlugin.base.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey, Klass } from '@fluentui-copilot/text-editor';\nimport {\n $createParagraphNode,\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $insertNodes,\n $isDecoratorNode,\n $isRangeSelection,\n $isRootOrShadowRoot,\n $nodesOfType,\n $wrapNodeInElement,\n COMMAND_PRIORITY_CRITICAL,\n DELETE_CHARACTER_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport type { ChatInputEntityData, IChatInputEntityPluginBase, IEntityNode } from './ChatInputEntityPlugin.types';\n\nexport class ChatInputEntityPluginBase<\n ExtraDataType,\n NodePropsType,\n NodeType extends IEntityNode<ExtraDataType, NodePropsType>,\n> implements IChatInputEntityPluginBase<ExtraDataType, NodePropsType>\n{\n private __nodeClass: Klass<NodeType>;\n private __editor: LexicalEditor;\n private __id: string;\n\n private __deleteDirection: 'forward' | 'backward' | null = null;\n private __$createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType;\n\n private _cleanup: () => void;\n\n cleanup() {\n this._cleanup();\n }\n\n constructor(\n editor: LexicalEditor,\n id: string,\n nodeClass: Klass<NodeType>,\n $createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType,\n $isChatInputEntityNode: (node: LexicalNode | null) => node is NodeType,\n onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void,\n onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void,\n ) {\n this.__$createNode = $createNode;\n this.__editor = editor;\n this.__id = id;\n this.__nodeClass = nodeClass;\n\n this._cleanup = mergeRegister(\n // Keep track of delete direction so we know where to put the selection after adding back a space\n editor.registerCommand(\n DELETE_CHARACTER_COMMAND,\n isBackward => {\n this.__deleteDirection = isBackward ? 'backward' : 'forward';\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n ),\n // Always maintain a space before, after, and between entities in order for selection to work properly\n editor.registerNodeTransform(this.__nodeClass, node => {\n const nextSibling = node.getNextSibling();\n if (!nextSibling || $isDecoratorNode(nextSibling)) {\n const selection = $getSelection();\n\n // If selection is between the two nodes, that means the user is trying to delete the space\n // If they deleted to the left, we should move the cursor to the end of the entity\n // If they delete to the right, we should move the cursor to the end of the newly added space\n // This mimics changing the delete into a cursor move action\n const shouldMoveSelection =\n selection &&\n $isRangeSelection(selection) &&\n selection.isCollapsed() &&\n selection.anchor.offset === node.getIndexWithinParent() + 1;\n const text = $createTextNode(' ');\n node.insertAfter(text);\n if (shouldMoveSelection) {\n if (this.__deleteDirection === 'forward') {\n text.selectEnd();\n } else {\n node.selectEnd();\n }\n }\n }\n\n // In the case the entity is the first node, we need a space before it.\n if (!node.getPreviousSibling()) {\n const text = $createTextNode(' ');\n node.insertBefore(text);\n }\n }),\n onChatInputEntityAdded || onChatInputEntityDeleted\n ? editor.registerMutationListener(this.__nodeClass, (nodes, payload) => {\n for (const [nodeKey, mutation] of nodes) {\n if (onChatInputEntityDeleted && mutation === 'destroyed') {\n payload.prevEditorState.read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityDeleted(node.getEntityData());\n }\n });\n } else if (onChatInputEntityAdded && mutation === 'created') {\n editor.getEditorState().read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityAdded(node.getEntityData());\n }\n });\n }\n }\n })\n : noop,\n );\n }\n insertChatInputEntity(props: ChatInputEntityData<ExtraDataType, NodePropsType>): string | undefined {\n let key: string | undefined = undefined;\n this.__editor.update(() => {\n const { text, data, entityProps } = props;\n\n const entityNode = this.__$createNode(this.__id, text, data, entityProps);\n\n $insertNodes([entityNode]);\n entityNode.selectEnd();\n if ($isRootOrShadowRoot(entityNode.getParentOrThrow())) {\n $wrapNodeInElement(entityNode, $createParagraphNode).selectEnd();\n }\n\n key = entityNode.getKey();\n });\n\n return key;\n }\n removeChatInputEntity(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) {\n this.__editor.update(() => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(node => node.remove());\n } else {\n $getNodeByKey(keyOrPredicate)?.remove();\n }\n });\n }\n updateChatInputEntityProps(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) {\n const updateNode = (node: NodeType) => {\n const newProps = typeof props === 'function' ? props(node.getEntityData()) : props;\n node.updateEntityData(newProps);\n };\n\n this.__editor.update(\n () => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(updateNode);\n } else {\n const node = $getNodeByKey<NodeType>(keyOrPredicate);\n if (node) {\n updateNode(node);\n }\n }\n },\n { tag: 'historic' },\n );\n }\n\n getActiveEntities(): ChatInputEntityData<ExtraDataType, NodePropsType>[] {\n return this.__editor.getEditorState().read(() =>\n $nodesOfType(this.__nodeClass)\n .filter(node => node.__pluginId === this.__id)\n .map(node => node.getEntityData()),\n );\n }\n}\n\nfunction noop() {\n return;\n}\n"],"names":["ChatInputEntityPluginBase","cleanup","_cleanup","insertChatInputEntity","props","key","__editor","update","$insertNodes","entityNode","selectEnd","__id","text","data","entityProps","$isRootOrShadowRoot","$wrapNodeInElement","getParentOrThrow","$createParagraphNode","removeChatInputEntity","keyOrPredicate","$nodesOfType","$getNodeByKey","_$getNodeByKey","remove","updateChatInputEntityProps","updateEntityData","newProps","node","getEntityData","updateNode","tag","getActiveEntities","constructor","editor","id","$createNode","$isChatInputEntityNode","onChatInputEntityAdded","onChatInputEntityDeleted","map","nodeClass","__deleteDirection","__$createNode","__nodeClass","registerCommand","COMMAND_PRIORITY_CRITICAL","isBackward","registerNodeTransform","$isDecoratorNode","$getSelection","getNextSibling","nextSibling","isCollapsed","$isRangeSelection","selection","anchor","offset","getIndexWithinParent","$createTextNode","mutation","nodeKey","read","getEditorState","__pluginId","noop"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["ChatInputEntityPlugin.base.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey, Klass } from '@fluentui-copilot/text-editor';\nimport {\n $createParagraphNode,\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $insertNodes,\n $isDecoratorNode,\n $isRangeSelection,\n $isRootOrShadowRoot,\n $nodesOfType,\n $wrapNodeInElement,\n COMMAND_PRIORITY_CRITICAL,\n DELETE_CHARACTER_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport type {\n ChatInputEntityData,\n ChatInputEntityPluginProps,\n IChatInputEntityPluginBase,\n IEntityNode,\n} from './ChatInputEntityPlugin.types';\n\nexport class ChatInputEntityPluginBase<\n ExtraDataType,\n NodePropsType,\n NodeType extends IEntityNode<ExtraDataType, NodePropsType>,\n> implements IChatInputEntityPluginBase<ExtraDataType, NodePropsType>\n{\n private __nodeClass: Klass<NodeType>;\n private __editor: LexicalEditor;\n private __id: string;\n\n private __deleteDirection: 'forward' | 'backward' | null = null;\n private __$createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType;\n\n private _cleanup: () => void;\n\n cleanup() {\n this._cleanup();\n }\n\n constructor(\n editor: LexicalEditor,\n id: string,\n nodeClass: Klass<NodeType>,\n $createNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => NodeType,\n $isChatInputEntityNode: (node: LexicalNode | null) => node is NodeType,\n onChatInputEntityAdded?: ChatInputEntityPluginProps<ExtraDataType, NodePropsType>['onChatInputEntityAdded'],\n onChatInputEntityDeleted?: ChatInputEntityPluginProps<ExtraDataType, NodePropsType>['onChatInputEntityDeleted'],\n ) {\n this.__$createNode = $createNode;\n this.__editor = editor;\n this.__id = id;\n this.__nodeClass = nodeClass;\n\n this._cleanup = mergeRegister(\n // Keep track of delete direction so we know where to put the selection after adding back a space\n editor.registerCommand(\n DELETE_CHARACTER_COMMAND,\n isBackward => {\n this.__deleteDirection = isBackward ? 'backward' : 'forward';\n return false;\n },\n COMMAND_PRIORITY_CRITICAL,\n ),\n // Always maintain a space before, after, and between entities in order for selection to work properly\n editor.registerNodeTransform(this.__nodeClass, node => {\n const nextSibling = node.getNextSibling();\n if (!nextSibling || $isDecoratorNode(nextSibling)) {\n const selection = $getSelection();\n\n // If selection is between the two nodes, that means the user is trying to delete the space\n // If they deleted to the left, we should move the cursor to the end of the entity\n // If they delete to the right, we should move the cursor to the end of the newly added space\n // This mimics changing the delete into a cursor move action\n const shouldMoveSelection =\n selection &&\n $isRangeSelection(selection) &&\n selection.isCollapsed() &&\n selection.anchor.offset === node.getIndexWithinParent() + 1;\n const text = $createTextNode(' ');\n node.insertAfter(text);\n if (shouldMoveSelection) {\n if (this.__deleteDirection === 'forward') {\n text.selectEnd();\n } else {\n node.selectEnd();\n }\n }\n }\n\n // In the case the entity is the first node, we need a space before it.\n if (!node.getPreviousSibling()) {\n const text = $createTextNode(' ');\n node.insertBefore(text);\n }\n }),\n onChatInputEntityAdded || onChatInputEntityDeleted\n ? editor.registerMutationListener(this.__nodeClass, (nodes, payload) => {\n for (const [nodeKey, mutation] of nodes) {\n if (onChatInputEntityDeleted && mutation === 'destroyed') {\n payload.prevEditorState.read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityDeleted(node.getEntityData(), nodeKey);\n }\n });\n } else if (onChatInputEntityAdded && mutation === 'created') {\n editor.getEditorState().read(() => {\n const node = $getNodeByKey(nodeKey);\n if ($isChatInputEntityNode(node) && node.__pluginId === id) {\n onChatInputEntityAdded(node.getEntityData(), nodeKey);\n }\n });\n }\n }\n })\n : noop,\n );\n }\n insertChatInputEntity(props: ChatInputEntityData<ExtraDataType, NodePropsType>): string | undefined {\n let key: string | undefined = undefined;\n this.__editor.update(() => {\n const { text, data, entityProps } = props;\n\n const entityNode = this.__$createNode(this.__id, text, data, entityProps);\n\n $insertNodes([entityNode]);\n entityNode.selectEnd();\n if ($isRootOrShadowRoot(entityNode.getParentOrThrow())) {\n $wrapNodeInElement(entityNode, $createParagraphNode).selectEnd();\n }\n\n key = entityNode.getKey();\n });\n\n return key;\n }\n removeChatInputEntity(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) {\n this.__editor.update(() => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(node => node.remove());\n } else {\n $getNodeByKey(keyOrPredicate)?.remove();\n }\n });\n }\n updateChatInputEntityProps(\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) {\n const updateNode = (node: NodeType) => {\n const newProps = typeof props === 'function' ? props(node.getEntityData()) : props;\n node.updateEntityData(newProps);\n };\n\n this.__editor.update(\n () => {\n if (typeof keyOrPredicate === 'function') {\n $nodesOfType(this.__nodeClass)\n .filter((node, i) => node.__pluginId === this.__id && keyOrPredicate(node.getEntityData(), i))\n .forEach(updateNode);\n } else {\n const node = $getNodeByKey<NodeType>(keyOrPredicate);\n if (node) {\n updateNode(node);\n }\n }\n },\n { tag: 'historic' },\n );\n }\n\n getActiveEntities(): ChatInputEntityData<ExtraDataType, NodePropsType>[] {\n return this.__editor.getEditorState().read(() =>\n $nodesOfType(this.__nodeClass)\n .filter(node => node.__pluginId === this.__id)\n .map(node => node.getEntityData()),\n );\n }\n}\n\nfunction noop() {\n return;\n}\n"],"names":["ChatInputEntityPluginBase","cleanup","_cleanup","insertChatInputEntity","props","key","__editor","update","$insertNodes","entityNode","selectEnd","__id","text","data","entityProps","$isRootOrShadowRoot","$wrapNodeInElement","getParentOrThrow","$createParagraphNode","removeChatInputEntity","keyOrPredicate","$nodesOfType","$getNodeByKey","_$getNodeByKey","remove","updateChatInputEntityProps","updateEntityData","newProps","node","getEntityData","updateNode","tag","getActiveEntities","constructor","editor","id","$createNode","$isChatInputEntityNode","onChatInputEntityAdded","onChatInputEntityDeleted","map","nodeClass","__deleteDirection","__$createNode","__nodeClass","registerCommand","COMMAND_PRIORITY_CRITICAL","isBackward","registerNodeTransform","$isDecoratorNode","$getSelection","getNextSibling","nextSibling","isCollapsed","$isRangeSelection","selection","anchor","offset","getIndexWithinParent","$createTextNode","mutation","nodeKey","read","getEditorState","__pluginId","noop"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["ChatInputEntityPlugin.types.ts"],"sourcesContent":["import type { LexicalNode } from '@fluentui-copilot/text-editor';\n\nexport type ChatInputEntityData<ExtraDataType, NodePropsType> = {\n // Represents the string content of the entity that will returned inside the ChatInput's text content\n text: string;\n // Props to pass to the component rendered by the node\n // By default, `text` will be used as the entity's text content.\n // If entityProps contains information for rendering children, that will take priority\n entityProps?: NodePropsType;\n // Optional extra data that can be associated with the entity\n data?: ExtraDataType;\n};\n\nexport type ChatInputEntityPluginProps<ExtraDataType, NodePropsType> = {\n // An identifier for an instance of the ChatInputEntityPlugin\n // Only entities created by this instance of the plugin will be handled by it\n id: string;\n onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n};\n\n/**\n * A lexical node representing an entity should conform to this interface\n */\nexport interface IEntityNode<ExtraDataType, NodePropsType> extends LexicalNode {\n getEntityData: () => ChatInputEntityData<ExtraDataType, NodePropsType>;\n updateEntityData: (data: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n __pluginId: string;\n}\n\nexport interface IChatInputEntityPluginBase<ExtraDataType, NodePropsType> {\n // Inserts a new entity and returns its key, to be used by removeChatInputEntity or updateChatInputEntityProps\n insertChatInputEntity: (props: ChatInputEntityData<ExtraDataType, NodePropsType>) => string | undefined;\n // Removes an entity by its key, or removes all entities that match a predicate function\n removeChatInputEntity: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) => void;\n // Updates an entity by its key, or removes all entities that match a predicate function\n updateChatInputEntityProps: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) => void;\n getActiveEntities: () => ChatInputEntityData<ExtraDataType, NodePropsType>[];\n}\n"],"names":[],"rangeMappings":"","mappings":""}
1
+ {"version":3,"sources":["ChatInputEntityPlugin.types.ts"],"sourcesContent":["import type { LexicalNode, NodeKey } from '@fluentui-copilot/text-editor';\n\nexport type ChatInputEntityData<ExtraDataType, NodePropsType> = {\n // Represents the string content of the entity that will returned inside the ChatInput's text content\n text: string;\n // Props to pass to the component rendered by the node\n // By default, `text` will be used as the entity's text content.\n // If entityProps contains information for rendering children, that will take priority\n entityProps?: NodePropsType;\n // Optional extra data that can be associated with the entity\n data?: ExtraDataType;\n};\n\nexport type ChatInputEntityPluginProps<ExtraDataType, NodePropsType> = {\n // An identifier for an instance of the ChatInputEntityPlugin\n // Only entities created by this instance of the plugin will be handled by it\n id: string;\n onChatInputEntityAdded?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>, nodeKey: NodeKey) => void;\n onChatInputEntityDeleted?: (entity: ChatInputEntityData<ExtraDataType, NodePropsType>, nodeKey: NodeKey) => void;\n};\n\n/**\n * A lexical node representing an entity should conform to this interface\n */\nexport interface IEntityNode<ExtraDataType, NodePropsType> extends LexicalNode {\n getEntityData: () => ChatInputEntityData<ExtraDataType, NodePropsType>;\n updateEntityData: (data: ChatInputEntityData<ExtraDataType, NodePropsType>) => void;\n __pluginId: string;\n}\n\nexport interface IChatInputEntityPluginBase<ExtraDataType, NodePropsType> {\n // Inserts a new entity and returns its key, to be used by removeChatInputEntity or updateChatInputEntityProps\n insertChatInputEntity: (props: ChatInputEntityData<ExtraDataType, NodePropsType>) => string | undefined;\n // Removes an entity by its key, or removes all entities that match a predicate function\n removeChatInputEntity: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n ) => void;\n // Updates an entity by its key, or removes all entities that match a predicate function\n updateChatInputEntityProps: (\n keyOrPredicate: string | ((entity: ChatInputEntityData<ExtraDataType, NodePropsType>, i: number) => boolean),\n props:\n | ChatInputEntityData<ExtraDataType, NodePropsType>\n | ((\n oldProps: ChatInputEntityData<ExtraDataType, NodePropsType>,\n ) => ChatInputEntityData<ExtraDataType, NodePropsType>),\n ) => void;\n getActiveEntities: () => ChatInputEntityData<ExtraDataType, NodePropsType>[];\n}\n"],"names":[],"rangeMappings":"","mappings":""}
@@ -1 +1 @@
1
- {"version":3,"sources":["PasteUnfurling.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport { PASTE_COMMAND, COMMAND_PRIORITY_HIGH, $insertNodes, $createTextNode } from '@fluentui-copilot/text-editor';\nimport type { PasteUnfurlingPluginProps, TransformedPart } from './PasteUnfurling.types';\n\nfunction unhandledPart(part: never): never {\n throw new Error(`Unhandled part: ${part}`);\n}\n\nexport function registerPasteUnfurlingPlugin<ExtraDataType, NodePropsType>(\n editor: LexicalEditor,\n props: PasteUnfurlingPluginProps<ExtraDataType, NodePropsType>,\n): () => void {\n const { entityPluginId, transforms, $createEntityNode } = props;\n\n function insertParts(parts: TransformedPart<ExtraDataType, NodePropsType>[]) {\n editor.update(() => {\n const nodes = parts.map(part => {\n switch (part.type) {\n case 'entity':\n return $createEntityNode(entityPluginId, part.value.text, part.value.data, part.value.entityProps);\n case 'text':\n return $createTextNode(part.value);\n }\n return unhandledPart(part);\n });\n $insertNodes(nodes);\n });\n }\n\n function handlePaste(event: ClipboardEvent): boolean {\n for (const transform of transforms) {\n const result = transform(event, editor);\n\n if (result.transformedParts) {\n insertParts(result.transformedParts);\n }\n\n if (result.handled) {\n return true;\n }\n }\n\n return false;\n }\n\n return editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_HIGH);\n}\n"],"names":["registerPasteUnfurlingPlugin","unhandledPart","part","Error","editor","props","entityPluginId","insertParts","nodes","parts","map","$createEntityNode","$insertNodes","transform","result","transforms","event","transformedParts","handled"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAQgBA;;;eAAAA;;;4BAPoE;AAGpF,SAASC,cAAcC,IAAW;UAChC,IAAMC,MAAIA,CAAAA,gBAAO,EAAgBD,KAAEA,CAAAA;AACrC;AAEO,SAASF,6BACdI,MAAqB,EACrBC,KAA8D;UAE9D,EAEAC,cAASC,YACPH,mBACQI;yBAEFC,KAAK;;0BAELA,MAAKC,GAAA,CAAAR,CAAAA;gCACH;;+BAEJS,kBAAqBT,gBAAAA,KAAAA,KAAAA,CAAAA,IAAAA,EAAAA,KAAAA,KAAAA,CAAAA,IAAAA,EAAAA,KAAAA,KAAAA,CAAAA,WAAAA;yBACvB;wBACAU,OAAAA,IAAAA,2BAAaJ,EAAAA,KAAAA,KAAAA;gBACf;gBACF,OAAAP,cAAAC;YAEA;wCACO,EAAMW;;;yBAIPN,KAAYO;mBACdD,aAAAE,WAAA;kBAEAD,SAAIA,UAAcE,OAAEZ;uBAClBa,gBAAO,EAAA;4BACTH,OAAAG,gBAAA;;gBAGFH,OAAOI,OAAA,EAAA;gBACT,OAAA;YAEA;QACF"}
1
+ {"version":3,"sources":["PasteUnfurling.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport { PASTE_COMMAND, COMMAND_PRIORITY_HIGH, $insertNodes, $createTextNode } from '@fluentui-copilot/text-editor';\nimport type { PasteUnfurlingPluginBaseProps, PasteUnfurlingTransformedPart } from './PasteUnfurling.types';\n\nfunction unhandledPart(part: never): never {\n throw new Error(`Unhandled part: ${part}`);\n}\n\nexport function registerPasteUnfurlingPlugin<ExtraDataType, NodePropsType>(\n editor: LexicalEditor,\n props: PasteUnfurlingPluginBaseProps<ExtraDataType, NodePropsType>,\n): () => void {\n const { entityPluginId, transforms, $createEntityNode } = props;\n\n function insertParts(parts: PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType>[]) {\n editor.update(() => {\n const nodes = parts.map(part => {\n switch (part.type) {\n case 'entity':\n return $createEntityNode(entityPluginId, part.value.text, part.value.data, part.value.entityProps);\n case 'text':\n return $createTextNode(part.value);\n }\n return unhandledPart(part);\n });\n $insertNodes(nodes);\n });\n }\n\n function handlePaste(event: ClipboardEvent): boolean {\n for (const transform of transforms) {\n const result = transform(event, editor);\n\n if (result.transformedParts) {\n insertParts(result.transformedParts);\n }\n\n if (result.handled) {\n return true;\n }\n }\n\n return false;\n }\n\n return editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_HIGH);\n}\n"],"names":["registerPasteUnfurlingPlugin","unhandledPart","part","Error","editor","props","entityPluginId","insertParts","nodes","parts","map","$createEntityNode","$insertNodes","transform","result","transforms","event","transformedParts","handled"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAQgBA;;;eAAAA;;;4BAPoE;AAGpF,SAASC,cAAcC,IAAW;UAChC,IAAMC,MAAIA,CAAAA,gBAAO,EAAgBD,KAAEA,CAAAA;AACrC;AAEO,SAASF,6BACdI,MAAqB,EACrBC,KAAkE;UAElE,EAEAC,cAASC,YACPH,mBACQI;yBAEFC,KAAK;;0BAELA,MAAKC,GAAA,CAAAR,CAAAA;gCACH;;+BAEJS,kBAAqBT,gBAAAA,KAAAA,KAAAA,CAAAA,IAAAA,EAAAA,KAAAA,KAAAA,CAAAA,IAAAA,EAAAA,KAAAA,KAAAA,CAAAA,WAAAA;yBACvB;wBACAU,OAAAA,IAAAA,2BAAaJ,EAAAA,KAAAA,KAAAA;gBACf;gBACF,OAAAP,cAAAC;YAEA;wCACO,EAAMW;;;yBAIPN,KAAYO;mBACdD,aAAAE,WAAA;kBAEAD,SAAIA,UAAcE,OAAEZ;uBAClBa,gBAAO,EAAA;4BACTH,OAAAG,gBAAA;;gBAGFH,OAAOI,OAAA,EAAA;gBACT,OAAA;YAEA;QACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["PasteUnfurling.types.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey } from '@fluentui-copilot/text-editor';\nimport type { ChatInputEntityData } from '../ChatInputEntity';\n\nexport type TransformedPart<ExtraDataType, NodePropsType> =\n | { type: 'text'; value: string }\n | { type: 'entity'; value: ChatInputEntityData<ExtraDataType, NodePropsType> };\n\nexport type TransformResult<ExtraDataType, NodePropsType> = {\n handled: boolean;\n transformedParts?: TransformedPart<ExtraDataType, NodePropsType>[];\n};\n\nexport type TransformFunction<ExtraDataType, NodePropsType> = (\n event: ClipboardEvent,\n editor: LexicalEditor,\n) => TransformResult<ExtraDataType, NodePropsType>;\n\nexport type PasteUnfurlingPluginProps<ExtraDataType, NodePropsType> = {\n entityPluginId: string;\n transforms: TransformFunction<ExtraDataType, NodePropsType>[];\n $createEntityNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => LexicalNode;\n};\n"],"names":[],"rangeMappings":"","mappings":""}
1
+ {"version":3,"sources":["PasteUnfurling.types.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode, NodeKey } from '@fluentui-copilot/text-editor';\nimport type { ChatInputEntityData } from '../ChatInputEntity';\n\nexport type PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType> =\n | { type: 'text'; value: string }\n | { type: 'entity'; value: ChatInputEntityData<ExtraDataType, NodePropsType> };\n\nexport type PasteUnfurlingTransformResult<ExtraDataType, NodePropsType> = {\n handled: boolean;\n transformedParts?: PasteUnfurlingTransformedPart<ExtraDataType, NodePropsType>[];\n};\n\nexport type PasteUnfurlingTransformFunction<ExtraDataType, NodePropsType> = (\n event: ClipboardEvent,\n editor: LexicalEditor,\n) => PasteUnfurlingTransformResult<ExtraDataType, NodePropsType>;\n\nexport type PasteUnfurlingPluginBaseProps<ExtraDataType, NodePropsType> = {\n entityPluginId: string;\n transforms: PasteUnfurlingTransformFunction<ExtraDataType, NodePropsType>[];\n $createEntityNode: (\n pluginId: string,\n text: string,\n data?: ExtraDataType,\n entityProps?: NodePropsType,\n key?: NodeKey,\n ) => LexicalNode;\n};\n"],"names":[],"rangeMappings":"","mappings":""}
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":["export {\n BasicFunctionalityBase,\n SentinelNode,\n $createSentinelNode,\n $isSentinelNode,\n SENTINEL_VALUE,\n} from './BasicFunctionality';\nexport type { IBasicFunctionalityBase } from './BasicFunctionality';\n\nexport { ChatInputEntityPluginBase } from './ChatInputEntity';\nexport type {\n ChatInputEntityData,\n ChatInputEntityPluginProps,\n IChatInputEntityPluginBase,\n IEntityNode,\n} from './ChatInputEntity';\n\nexport { GhostTextPluginBase } from './GhostText';\nexport type { GetGhostTextFunction, IGhostTextNode } from './GhostText';\n\nexport { ImperativeControlBase } from './ImperativeControl';\nexport type { IImperativeControlBase } from './ImperativeControl';\n\nexport { ManualGhostTextBase } from './ManualGhostText';\nexport type { IManualGhostTextBase } from './ManualGhostText';\n\nexport { registerPasteUnfurlingPlugin } from './PasteUnfurling';\nexport type { PasteUnfurlingPluginProps, TransformFunction, TransformedPart, TransformResult } from './PasteUnfurling';\n"],"names":["$createSentinelNode","$isSentinelNode","BasicFunctionalityBase","ChatInputEntityPluginBase","GhostTextPluginBase","ImperativeControlBase","ManualGhostTextBase","SENTINEL_VALUE","SentinelNode","registerPasteUnfurlingPlugin"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;;;;;;;;IAGEA,mBAAmB;eAAnBA,uCAAmB;;IACnBC,eAAe;eAAfA,mCAAe;;IAHfC,sBAAsB;eAAtBA,0CAAsB;;IAQfC,yBAAyB;eAAzBA,0CAAyB;;IAQzBC,mBAAmB;eAAnBA,8BAAmB;;IAGnBC,qBAAqB;eAArBA,wCAAqB;;IAGrBC,mBAAmB;eAAnBA,oCAAmB;;IAlB1BC,cAAc;eAAdA,kCAAc;;IAHdC,YAAY;eAAZA,gCAAY;;IAwBLC,4BAA4B;eAA5BA,4CAA4B;;;oCApB9B;iCAGmC;2BAQN;mCAGE;iCAGF;gCAGS"}
1
+ {"version":3,"sources":["index.ts"],"sourcesContent":["export {\n BasicFunctionalityBase,\n SentinelNode,\n $createSentinelNode,\n $isSentinelNode,\n SENTINEL_VALUE,\n} from './BasicFunctionality';\nexport type { IBasicFunctionalityBase } from './BasicFunctionality';\n\nexport { ChatInputEntityPluginBase } from './ChatInputEntity';\nexport type {\n ChatInputEntityData,\n ChatInputEntityPluginProps,\n IChatInputEntityPluginBase,\n IEntityNode,\n} from './ChatInputEntity';\n\nexport { GhostTextPluginBase } from './GhostText';\nexport type { GetGhostTextFunction, IGhostTextNode } from './GhostText';\n\nexport { ImperativeControlBase } from './ImperativeControl';\nexport type { IImperativeControlBase } from './ImperativeControl';\n\nexport { ManualGhostTextBase } from './ManualGhostText';\nexport type { IManualGhostTextBase } from './ManualGhostText';\n\nexport { registerPasteUnfurlingPlugin } from './PasteUnfurling';\nexport type {\n PasteUnfurlingPluginBaseProps,\n PasteUnfurlingTransformFunction,\n PasteUnfurlingTransformedPart,\n PasteUnfurlingTransformResult,\n} from './PasteUnfurling';\n"],"names":["$createSentinelNode","$isSentinelNode","BasicFunctionalityBase","ChatInputEntityPluginBase","GhostTextPluginBase","ImperativeControlBase","ManualGhostTextBase","SENTINEL_VALUE","SentinelNode","registerPasteUnfurlingPlugin"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;;;;;;;;IAGEA,mBAAmB;eAAnBA,uCAAmB;;IACnBC,eAAe;eAAfA,mCAAe;;IAHfC,sBAAsB;eAAtBA,0CAAsB;;IAQfC,yBAAyB;eAAzBA,0CAAyB;;IAQzBC,mBAAmB;eAAnBA,8BAAmB;;IAGnBC,qBAAqB;eAArBA,wCAAqB;;IAGrBC,mBAAmB;eAAnBA,oCAAmB;;IAlB1BC,cAAc;eAAdA,kCAAc;;IAHdC,YAAY;eAAZA,gCAAY;;IAwBLC,4BAA4B;eAA5BA,4CAA4B;;;oCApB9B;iCAGmC;2BAQN;mCAGE;iCAGF;gCAGS"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui-copilot/chat-input-plugins",
3
- "version": "0.0.8",
3
+ "version": "0.1.1",
4
4
  "description": "A Fluent AI package for non-react specific chat input plugins.",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
- "@fluentui-copilot/text-editor": "^0.0.4",
15
+ "@fluentui-copilot/text-editor": "^0.0.5",
16
16
  "@swc/helpers": "^0.5.1"
17
17
  },
18
18
  "beachball": {