@fluentui-copilot/chat-input-plugins 0.4.2-hotfix.1 → 0.4.2-hotfix.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +20 -5
- package/CHANGELOG.md +5 -5
- package/lib/BasicFunctionality/BasicFunctionality.base.js +92 -92
- package/lib/BasicFunctionality/SentinelNode.js +30 -29
- package/lib/BasicFunctionality/SentinelNodeHandlers.js +78 -73
- package/lib/BasicFunctionality/index.js +1 -0
- package/lib/ChatInputEntity/ChatInputEntityPlugin.base.js +114 -109
- package/lib/ChatInputEntity/ChatInputEntityPlugin.types.js +2 -1
- package/lib/ChatInputEntity/index.js +1 -0
- package/lib/GhostText/GhostText.base.js +145 -142
- package/lib/GhostText/index.js +1 -0
- package/lib/ImperativeControl/ImperativeControl.base.js +83 -82
- package/lib/ImperativeControl/index.js +1 -0
- package/lib/ManualGhostText/ManualGhostText.base.js +67 -68
- package/lib/ManualGhostText/index.js +1 -0
- package/lib/PasteUnfurling/PasteUnfurling.base.js +57 -52
- package/lib/PasteUnfurling/PasteUnfurling.types.js +2 -1
- package/lib/PasteUnfurling/PasteUnfurlingTestUtils.js +139 -138
- package/lib/PasteUnfurling/index.js +1 -0
- package/lib/index.js +1 -0
- package/lib-commonjs/BasicFunctionality/BasicFunctionality.base.js +3 -2
- package/lib-commonjs/BasicFunctionality/BasicFunctionality.base.js.map +1 -1
- package/lib-commonjs/BasicFunctionality/SentinelNode.js +1 -1
- package/lib-commonjs/BasicFunctionality/SentinelNode.js.map +1 -1
- package/lib-commonjs/BasicFunctionality/SentinelNodeHandlers.js +5 -3
- package/lib-commonjs/BasicFunctionality/SentinelNodeHandlers.js.map +1 -1
- package/lib-commonjs/BasicFunctionality/index.js +1 -0
- package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.base.js +5 -3
- package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.base.js.map +1 -1
- package/lib-commonjs/ChatInputEntity/ChatInputEntityPlugin.types.js +1 -0
- package/lib-commonjs/ChatInputEntity/index.js +1 -0
- package/lib-commonjs/GhostText/GhostText.base.js +3 -2
- package/lib-commonjs/GhostText/GhostText.base.js.map +1 -1
- package/lib-commonjs/GhostText/index.js +1 -0
- package/lib-commonjs/ImperativeControl/ImperativeControl.base.js +1 -1
- package/lib-commonjs/ImperativeControl/ImperativeControl.base.js.map +1 -1
- package/lib-commonjs/ImperativeControl/index.js +1 -0
- package/lib-commonjs/ManualGhostText/ManualGhostText.base.js +1 -1
- package/lib-commonjs/ManualGhostText/ManualGhostText.base.js.map +1 -1
- package/lib-commonjs/ManualGhostText/index.js +1 -0
- package/lib-commonjs/PasteUnfurling/PasteUnfurling.base.js +1 -1
- package/lib-commonjs/PasteUnfurling/PasteUnfurling.base.js.map +1 -1
- package/lib-commonjs/PasteUnfurling/PasteUnfurling.types.js +1 -0
- package/lib-commonjs/PasteUnfurling/PasteUnfurlingTestUtils.js +1 -1
- package/lib-commonjs/PasteUnfurling/PasteUnfurlingTestUtils.js.map +1 -1
- package/lib-commonjs/PasteUnfurling/index.js +1 -0
- package/lib-commonjs/index.js +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["GhostText.base.ts"],"sourcesContent":["import type { EditorState, Klass, LexicalEditor, LexicalNode, UpdateListener } from '@fluentui-copilot/text-editor';\nimport {\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n $setSelection,\n COMMAND_PRIORITY_LOW,\n KEY_TAB_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport { $isSentinelNode } from '../BasicFunctionality';\n\nexport type GetGhostTextFunction = (\n editor: LexicalEditor,\n editorState: EditorState,\n prevEditorState: EditorState,\n) => Promise<string | undefined>;\n\nexport interface IGhostTextNode<ComponentPropsType> extends LexicalNode {\n __content: string;\n __id: string;\n __allowCommitting?: boolean;\n __componentProps?: ComponentPropsType;\n __exposeText?: boolean;\n}\n\nexport class GhostTextPluginBase<ComponentPropsType> {\n private __id: string;\n private __$getGhostText: GetGhostTextFunction;\n private __componentProps?: ComponentPropsType;\n private __exposeText?: boolean;\n private __allowCompletion?: boolean;\n\n private __cleanup?: () => void;\n\n cleanup() {\n this.__cleanup?.();\n }\n\n constructor(\n editor: LexicalEditor,\n id: string,\n $getGhostText: GetGhostTextFunction,\n nodeClass: Klass<IGhostTextNode<ComponentPropsType>>,\n createNode: (\n id: string,\n content: string,\n exposeText?: boolean,\n componentProps?: ComponentPropsType,\n ) => IGhostTextNode<ComponentPropsType>,\n componentProps?: ComponentPropsType,\n // Whether or not the ghost text should count as text inside the input for submitting and character count\n exposeText?: boolean,\n allowCompletion?: boolean,\n ) {\n this.__id = id;\n this.__$getGhostText = $getGhostText;\n this.__componentProps = componentProps;\n this.__exposeText = exposeText;\n this.__allowCompletion = allowCompletion;\n\n let ghostTextNodeKey: string | null = null;\n let lastText: string | undefined = undefined;\n let justRemovedGhostText = false;\n let justAddedGhostText = false;\n\n function $clearGhostText() {\n const ghostTextNode = ghostTextNodeKey !== null ? $getNodeByKey(ghostTextNodeKey) : null;\n ghostTextNodeKey = null;\n lastText = undefined;\n if (ghostTextNode && ghostTextNode.isAttached()) {\n ghostTextNode.remove();\n justRemovedGhostText = true;\n }\n }\n function handleGhostTextNodeTransform(node: IGhostTextNode<ComponentPropsType>) {\n const key = node.getKey();\n\n if (node.__id === id && key !== ghostTextNodeKey) {\n // Only one ghost text\n node.remove();\n $clearGhostText();\n }\n }\n\n const handleGhostTextResponse = (text?: string) => {\n if (text === lastText) {\n return;\n }\n\n editor.update(\n () => {\n $clearGhostText();\n\n const selection = $getSelection();\n if (!text || !selection) {\n return;\n }\n\n const selectionCopy = selection.clone();\n\n const node = createNode(this.__id, text, this.__exposeText, this.__componentProps);\n ghostTextNodeKey = node.getKey();\n lastText = text;\n\n selection.insertNodes([node]);\n $setSelection(selectionCopy);\n justAddedGhostText = true;\n justRemovedGhostText = false;\n },\n { tag: 'historic' },\n );\n };\n\n const handleUpdate: UpdateListener = props => {\n const { editorState, prevEditorState } = props;\n\n // If this update was caused by adding or deleting ghost text, don't recheck the ghost text function until a subsequent update\n if (justRemovedGhostText || justAddedGhostText) {\n justRemovedGhostText = false;\n justAddedGhostText = false;\n return;\n }\n\n editorState.read(() => {\n // We only update the ghost text if the user selection is inside the input\n const selection = $getSelection();\n if (!$getSelection()) {\n return;\n }\n\n if ($isRangeSelection(selection) && selection.isCollapsed()) {\n // All the `$isXNode` functions prefer `null` over `undefined`\n const selectedNode = selection.getNodes().at(0) ?? null;\n const previousNodeKey = selectedNode?.getPreviousSibling()?.getKey();\n const previousNodeIsGhostText = previousNodeKey === ghostTextNodeKey;\n // If the ghost text is active and we're navigating past it, act as if the ghost text is not there and move 1 extra character\n if (\n previousNodeIsGhostText &&\n !$isSentinelNode(selectedNode) &&\n $isTextNode(selectedNode) &&\n selection.anchor.offset === 0\n ) {\n editor.update(\n () => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n selection.modify('move', false, 'character');\n }\n $clearGhostText();\n },\n { tag: 'historic' },\n );\n // Defer checking the ghost text until after this update has finished\n return;\n }\n\n // If the ghost text is the last node before the sentinel, we shouldn't let selection get past it\n if (previousNodeIsGhostText && $isSentinelNode(selectedNode)) {\n editor.update(\n () => {\n $getNodeByKey(previousNodeKey)?.getPreviousSibling()?.selectEnd();\n },\n { tag: 'historic' },\n );\n return;\n }\n }\n\n const promise = this.__$getGhostText(editor, editorState, prevEditorState);\n promise.then(handleGhostTextResponse).catch(e => console.error(e));\n });\n };\n\n function unmountGhostText() {\n if (ghostTextNodeKey) {\n editor.update(\n () => {\n $clearGhostText();\n },\n { tag: 'historic' },\n );\n }\n }\n\n function $handleTabCommand(e: KeyboardEvent) {\n if (ghostTextNodeKey === null || lastText === null) {\n return false;\n }\n\n const ghostTextNode = $getNodeByKey(ghostTextNodeKey);\n if (!ghostTextNode) {\n return false;\n }\n\n e.preventDefault();\n\n const textNode = $createTextNode(lastText);\n ghostTextNode.replace(textNode);\n textNode.selectEnd();\n $clearGhostText();\n return true;\n }\n\n this.__cleanup = mergeRegister(\n editor.registerNodeTransform(nodeClass, handleGhostTextNodeTransform),\n editor.registerUpdateListener(handleUpdate),\n this.__allowCompletion ? editor.registerCommand(KEY_TAB_COMMAND, $handleTabCommand, COMMAND_PRIORITY_LOW) : noop,\n unmountGhostText,\n );\n }\n\n setExposeText(exposeText?: boolean) {\n this.__exposeText = exposeText;\n }\n\n setComponentProps(componentProps?: ComponentPropsType) {\n this.__componentProps = componentProps;\n }\n\n setGetGhostText($getGhostText: GetGhostTextFunction) {\n this.__$getGhostText = $getGhostText;\n }\n\n setAllowCompletion(allowCompletion?: boolean) {\n this.__allowCompletion = allowCompletion;\n }\n}\nfunction noop(): void {\n return;\n}\n"],"names":["GhostTextPluginBase","cleanup","_this___cleanup","_this","__cleanup","call","setExposeText","exposeText","__exposeText","setComponentProps","componentProps","__componentProps","setGetGhostText","$getGhostText","__$getGhostText","setAllowCompletion","allowCompletion","__allowCompletion","constructor","editor","id","nodeClass","createNode","_define_property","__id","ghostTextNodeKey","lastText","undefined","justRemovedGhostText","justAddedGhostText","$clearGhostText","ghostTextNode","$getNodeByKey","isAttached","remove","handleGhostTextNodeTransform","node","key","getKey","handleGhostTextResponse","text","update","selection","$getSelection","selectionCopy","clone","insertNodes","$setSelection","tag","handleUpdate","props","editorState","prevEditorState","read","$isRangeSelection","isCollapsed","selectedNode","getNodes","at","previousNodeKey","getPreviousSibling","previousNodeIsGhostText","$isSentinelNode","$isTextNode","anchor","offset","modify","selectEnd","promise","then","catch","e","console","error","unmountGhostText","$handleTabCommand","preventDefault","textNode","$createTextNode","replace","mergeRegister","registerNodeTransform","registerUpdateListener","registerCommand","KEY_TAB_COMMAND","COMMAND_PRIORITY_LOW","noop"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BA4BaA;;;eAAAA;;;;4BAjBN;oCACyB;AAgBzB,MAAMA;IASXC,UAAU;YACRC,iBAAAC;QAAAD,CAAAA,kBAAA,AAAAC,CAAAA,QAAA,IAAI,AAAJ,EAAKC,SAAS,AAATA,MAAS,QAAdF,oBAAA,KAAA,IAAA,KAAA,IAAAA,gBAAAG,IAAA,CAAAF;IACF;IA+KAG,cAAcC,UAAoB,EAAE;QAClC,IAAI,CAACC,YAAY,GAAGD;IACtB;IAEAE,kBAAkBC,cAAmC,EAAE;QACrD,IAAI,CAACC,gBAAgB,GAAGD;IAC1B;IAEAE,gBAAgBC,aAAmC,EAAE;QACnD,IAAI,CAACC,eAAe,GAAGD;IACzB;IAEAE,mBAAmBC,eAAyB,EAAE;QAC5C,IAAI,CAACC,iBAAiB,GAAGD;IAC3B;IA3LAE,YACEC,MAAqB,EACrBC,EAAU,EACVP,aAAmC,EACnCQ,SAAoD,EACpDC,UAKuC,EACvCZ,cAAmC,EAEnCH,UAAoB,EACpBS,eAAyB,CACzB;QA3BFO,IAAAA,kBAAA,EAAA,IAAA,EAAQC,QAAR,KAAA;QACAD,IAAAA,kBAAA,EAAA,IAAA,EAAQT,mBAAR,KAAA;QACAS,IAAAA,kBAAA,EAAA,IAAA,EAAQZ,oBAAR,KAAA;QACAY,IAAAA,kBAAA,EAAA,IAAA,EAAQf,gBAAR,KAAA;QACAe,IAAAA,kBAAA,EAAA,IAAA,EAAQN,qBAAR,KAAA;QAEAM,IAAAA,kBAAA,EAAA,IAAA,EAAQnB,aAAR,KAAA;QAsBE,IAAI,CAACoB,IAAI,GAAGJ;QACZ,IAAI,CAACN,eAAe,GAAGD;QACvB,IAAI,CAACF,gBAAgB,GAAGD;QACxB,IAAI,CAACF,YAAY,GAAGD;QACpB,IAAI,CAACU,iBAAiB,GAAGD;QAEzB,IAAIS,mBAAkC;QACtC,IAAIC,WAA+BC;QACnC,IAAIC,uBAAuB;QAC3B,IAAIC,qBAAqB;QAEzB,SAASC;YACP,MAAMC,gBAAgBN,qBAAqB,OAAOO,IAAAA,yBAAAA,EAAcP,oBAAoB;YACpFA,mBAAmB;YACnBC,WAAWC;YACX,IAAII,iBAAiBA,cAAcE,UAAU,IAAI;gBAC/CF,cAAcG,MAAM;gBACpBN,uBAAuB;YACzB;QACF;QACA,SAASO,6BAA6BC,IAAwC;YAC5E,MAAMC,MAAMD,KAAKE,MAAM;YAEvB,IAAIF,KAAKZ,IAAI,KAAKJ,MAAMiB,QAAQZ,kBAAkB;gBAChD,sBAAsB;gBACtBW,KAAKF,MAAM;gBACXJ;YACF;QACF;QAEA,MAAMS,0BAA0B,CAACC;YAC/B,IAAIA,SAASd,UAAU;gBACrB;YACF;YAEAP,OAAOsB,MAAM,CACX;gBACEX;gBAEA,MAAMY,YAAYC,IAAAA,yBAAAA;gBAClB,IAAI,CAACH,QAAQ,CAACE,WAAW;oBACvB;gBACF;gBAEA,MAAME,gBAAgBF,UAAUG,KAAK;gBAErC,MAAMT,OAAOd,WAAW,IAAI,CAACE,IAAI,EAAEgB,MAAM,IAAI,CAAChC,YAAY,EAAE,IAAI,CAACG,gBAAgB;gBACjFc,mBAAmBW,KAAKE,MAAM;gBAC9BZ,WAAWc;gBAEXE,UAAUI,WAAW,CAAC;oBAACV;iBAAK;gBAC5BW,IAAAA,yBAAAA,EAAcH;gBACdf,qBAAqB;gBACrBD,uBAAuB;YACzB,GACA;gBAAEoB,KAAK;YAAW;QAEtB;QAEA,MAAMC,eAA+BC,CAAAA;YACnC,MAAM,EAAEC,WAAW,EAAEC,eAAe,EAAE,GAAGF;YAEzC,8HAA8H;YAC9H,IAAItB,wBAAwBC,oBAAoB;gBAC9CD,uBAAuB;gBACvBC,qBAAqB;gBACrB;YACF;YAEAsB,YAAYE,IAAI,CAAC;gBACf,0EAA0E;gBAC1E,MAAMX,YAAYC,IAAAA,yBAAAA;gBAClB,IAAI,CAACA,IAAAA,yBAAAA,KAAiB;oBACpB;gBACF;gBAEA,IAAIW,IAAAA,6BAAAA,EAAkBZ,cAAcA,UAAUa,WAAW,IAAI;wBAGnCC;wBADHd;oBADrB,8DAA8D;oBAC9D,MAAMc,eAAed,CAAAA,yBAAAA,UAAUe,QAAQ,GAAGC,EAAE,CAAC,EAAA,MAAA,QAAxBhB,2BAAAA,KAAAA,IAAAA,yBAA8B;oBACnD,MAAMiB,kBAAkBH,iBAAAA,QAAAA,iBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,CAAAA,mCAAAA,aAAcI,kBAAkB,EAAA,MAAA,QAAhCJ,qCAAAA,KAAAA,IAAAA,KAAAA,IAAAA,iCAAoClB,MAAM;oBAClE,MAAMuB,0BAA0BF,oBAAoBlC;oBACpD,6HAA6H;oBAC7H,IACEoC,2BACA,CAACC,IAAAA,mCAAAA,EAAgBN,iBACjBO,IAAAA,uBAAAA,EAAYP,iBACZd,UAAUsB,MAAM,CAACC,MAAM,KAAK,GAC5B;wBACA9C,OAAOsB,MAAM,CACX;4BACE,MAAMC,YAAYC,IAAAA,yBAAAA;4BAClB,IAAIW,IAAAA,6BAAAA,EAAkBZ,YAAY;gCAChCA,UAAUwB,MAAM,CAAC,QAAQ,OAAO;4BAClC;4BACApC;wBACF,GACA;4BAAEkB,KAAK;wBAAW;wBAEpB,qEAAqE;wBACrE;oBACF;oBAEA,iGAAiG;oBACjG,IAAIa,2BAA2BC,IAAAA,mCAAAA,EAAgBN,eAAe;wBAC5DrC,OAAOsB,MAAM,CACX;gCACET,mCAAAA;4BAAAA,CAAAA,iBAAAA,IAAAA,yBAAAA,EAAc2B,gBAAAA,MAAAA,QAAd3B,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,CAAAA,oCAAAA,eAAgC4B,kBAAkB,EAAA,MAAA,QAAlD5B,sCAAAA,KAAAA,IAAAA,KAAAA,IAAAA,kCAAsDmC,SAAS;wBACjE,GACA;4BAAEnB,KAAK;wBAAW;wBAEpB;oBACF;gBACF;gBAEA,MAAMoB,UAAU,IAAI,CAACtD,eAAe,CAACK,QAAQgC,aAAaC;gBAC1DgB,QAAQC,IAAI,CAAC9B,yBAAyB+B,KAAK,CAACC,CAAAA,IAAKC,QAAQC,KAAK,CAACF;YACjE;QACF;QAEA,SAASG;YACP,IAAIjD,kBAAkB;gBACpBN,OAAOsB,MAAM,CACX;oBACEX;gBACF,GACA;oBAAEkB,KAAK;gBAAW;YAEtB;QACF;QAEA,SAAS2B,kBAAkBJ,CAAgB;YACzC,IAAI9C,qBAAqB,QAAQC,aAAa,MAAM;gBAClD,OAAO;YACT;YAEA,MAAMK,gBAAgBC,IAAAA,yBAAAA,EAAcP;YACpC,IAAI,CAACM,eAAe;gBAClB,OAAO;YACT;YAEAwC,EAAEK,cAAc;YAEhB,MAAMC,WAAWC,IAAAA,2BAAAA,EAAgBpD;YACjCK,cAAcgD,OAAO,CAACF;YACtBA,SAASV,SAAS;YAClBrC;YACA,OAAO;QACT;QAEA,IAAI,CAAC1B,SAAS,GAAG4E,IAAAA,yBAAAA,EACf7D,OAAO8D,qBAAqB,CAAC5D,WAAWc,+BACxChB,OAAO+D,sBAAsB,CAACjC,eAC9B,IAAI,CAAChC,iBAAiB,GAAGE,OAAOgE,eAAe,CAACC,2BAAAA,EAAiBT,mBAAmBU,gCAAAA,IAAwBC,MAC5GZ;IAEJ;AAiBF;AACA,SAASY;IACP;AACF"}
|
|
1
|
+
{"version":3,"sources":["GhostText.base.ts"],"sourcesContent":["import type { EditorState, Klass, LexicalEditor, LexicalNode, UpdateListener } from '@fluentui-copilot/text-editor';\nimport {\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n $setSelection,\n COMMAND_PRIORITY_LOW,\n KEY_TAB_COMMAND,\n mergeRegister,\n} from '@fluentui-copilot/text-editor';\nimport { $isSentinelNode } from '../BasicFunctionality';\n\nexport type GetGhostTextFunction = (\n editor: LexicalEditor,\n editorState: EditorState,\n prevEditorState: EditorState,\n) => Promise<string | undefined>;\n\nexport interface IGhostTextNode<ComponentPropsType> extends LexicalNode {\n __content: string;\n __id: string;\n __allowCommitting?: boolean;\n __componentProps?: ComponentPropsType;\n __exposeText?: boolean;\n}\n\nexport class GhostTextPluginBase<ComponentPropsType> {\n private __id: string;\n private __$getGhostText: GetGhostTextFunction;\n private __componentProps?: ComponentPropsType;\n private __exposeText?: boolean;\n private __allowCompletion?: boolean;\n\n private __cleanup?: () => void;\n\n cleanup() {\n this.__cleanup?.();\n }\n\n constructor(\n editor: LexicalEditor,\n id: string,\n $getGhostText: GetGhostTextFunction,\n nodeClass: Klass<IGhostTextNode<ComponentPropsType>>,\n createNode: (\n id: string,\n content: string,\n exposeText?: boolean,\n componentProps?: ComponentPropsType,\n ) => IGhostTextNode<ComponentPropsType>,\n componentProps?: ComponentPropsType,\n // Whether or not the ghost text should count as text inside the input for submitting and character count\n exposeText?: boolean,\n allowCompletion?: boolean,\n ) {\n this.__id = id;\n this.__$getGhostText = $getGhostText;\n this.__componentProps = componentProps;\n this.__exposeText = exposeText;\n this.__allowCompletion = allowCompletion;\n\n let ghostTextNodeKey: string | null = null;\n let lastText: string | undefined = undefined;\n let justRemovedGhostText = false;\n let justAddedGhostText = false;\n\n function $clearGhostText() {\n const ghostTextNode = ghostTextNodeKey !== null ? $getNodeByKey(ghostTextNodeKey) : null;\n ghostTextNodeKey = null;\n lastText = undefined;\n if (ghostTextNode && ghostTextNode.isAttached()) {\n ghostTextNode.remove();\n justRemovedGhostText = true;\n }\n }\n function handleGhostTextNodeTransform(node: IGhostTextNode<ComponentPropsType>) {\n const key = node.getKey();\n\n if (node.__id === id && key !== ghostTextNodeKey) {\n // Only one ghost text\n node.remove();\n $clearGhostText();\n }\n }\n\n const handleGhostTextResponse = (text?: string) => {\n if (text === lastText) {\n return;\n }\n\n editor.update(\n () => {\n $clearGhostText();\n\n const selection = $getSelection();\n if (!text || !selection) {\n return;\n }\n\n const selectionCopy = selection.clone();\n\n const node = createNode(this.__id, text, this.__exposeText, this.__componentProps);\n ghostTextNodeKey = node.getKey();\n lastText = text;\n\n selection.insertNodes([node]);\n $setSelection(selectionCopy);\n justAddedGhostText = true;\n justRemovedGhostText = false;\n },\n { tag: 'historic' },\n );\n };\n\n const handleUpdate: UpdateListener = props => {\n const { editorState, prevEditorState } = props;\n\n // If this update was caused by adding or deleting ghost text, don't recheck the ghost text function until a subsequent update\n if (justRemovedGhostText || justAddedGhostText) {\n justRemovedGhostText = false;\n justAddedGhostText = false;\n return;\n }\n\n editorState.read(() => {\n // We only update the ghost text if the user selection is inside the input\n const selection = $getSelection();\n if (!$getSelection()) {\n return;\n }\n\n if ($isRangeSelection(selection) && selection.isCollapsed()) {\n // All the `$isXNode` functions prefer `null` over `undefined`\n const selectedNode = selection.getNodes().at(0) ?? null;\n const previousNodeKey = selectedNode?.getPreviousSibling()?.getKey();\n const previousNodeIsGhostText = previousNodeKey === ghostTextNodeKey;\n // If the ghost text is active and we're navigating past it, act as if the ghost text is not there and move 1 extra character\n if (\n previousNodeIsGhostText &&\n !$isSentinelNode(selectedNode) &&\n $isTextNode(selectedNode) &&\n selection.anchor.offset === 0\n ) {\n editor.update(\n () => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n selection.modify('move', false, 'character');\n }\n $clearGhostText();\n },\n { tag: 'historic' },\n );\n // Defer checking the ghost text until after this update has finished\n return;\n }\n\n // If the ghost text is the last node before the sentinel, we shouldn't let selection get past it\n if (previousNodeIsGhostText && $isSentinelNode(selectedNode)) {\n editor.update(\n () => {\n $getNodeByKey(previousNodeKey)?.getPreviousSibling()?.selectEnd();\n },\n { tag: 'historic' },\n );\n return;\n }\n }\n\n const promise = this.__$getGhostText(editor, editorState, prevEditorState);\n promise.then(handleGhostTextResponse).catch(e => console.error(e));\n });\n };\n\n function unmountGhostText() {\n if (ghostTextNodeKey) {\n editor.update(\n () => {\n $clearGhostText();\n },\n { tag: 'historic' },\n );\n }\n }\n\n function $handleTabCommand(e: KeyboardEvent) {\n if (ghostTextNodeKey === null || lastText === null) {\n return false;\n }\n\n const ghostTextNode = $getNodeByKey(ghostTextNodeKey);\n if (!ghostTextNode) {\n return false;\n }\n\n e.preventDefault();\n\n const textNode = $createTextNode(lastText);\n ghostTextNode.replace(textNode);\n textNode.selectEnd();\n $clearGhostText();\n return true;\n }\n\n this.__cleanup = mergeRegister(\n editor.registerNodeTransform(nodeClass, handleGhostTextNodeTransform),\n editor.registerUpdateListener(handleUpdate),\n this.__allowCompletion ? editor.registerCommand(KEY_TAB_COMMAND, $handleTabCommand, COMMAND_PRIORITY_LOW) : noop,\n unmountGhostText,\n );\n }\n\n setExposeText(exposeText?: boolean) {\n this.__exposeText = exposeText;\n }\n\n setComponentProps(componentProps?: ComponentPropsType) {\n this.__componentProps = componentProps;\n }\n\n setGetGhostText($getGhostText: GetGhostTextFunction) {\n this.__$getGhostText = $getGhostText;\n }\n\n setAllowCompletion(allowCompletion?: boolean) {\n this.__allowCompletion = allowCompletion;\n }\n}\nfunction noop(): void {\n return;\n}\n"],"names":["GhostTextPluginBase","cleanup","_this","__cleanup","_this___cleanup","call","setExposeText","exposeText","__exposeText","setComponentProps","componentProps","__componentProps","setGetGhostText","$getGhostText","__$getGhostText","setAllowCompletion","allowCompletion","__allowCompletion","constructor","editor","id","nodeClass","createNode","__id","ghostTextNodeKey","undefined","lastText","justRemovedGhostText","justAddedGhostText","$clearGhostText","$getNodeByKey","ghostTextNode","isAttached","handleGhostTextNodeTransform","node","key","text","selection","clone","getKey","selectionCopy","$setSelection","handleUpdate","props","read","$getSelection","selectedNode","previousNodeIsGhostText","previousNodeKey","_selectedNode_getPreviousSibling","getPreviousSibling","$isSentinelNode","modify","_$getNodeByKey","tag","_$getNodeByKey_getPreviousSibling","selectEnd","promise","editorState","prevEditorState","then","handleGhostTextResponse","catch","e","console","error","preventDefault","textNode","mergeRegister","registerNodeTransform","registerUpdateListener","registerCommand","KEY_TAB_COMMAND","$handleTabCommand","COMMAND_PRIORITY_LOW","noop","unmountGhostText"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["ImperativeControl.base.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode } from '@fluentui-copilot/text-editor';\nimport {\n $createParagraphNode,\n $createRangeSelection,\n $createTextNode,\n $getLeafNodes,\n $getRoot,\n $getSelection,\n $isTextNode,\n $normalizeSelection__EXPERIMENTAL,\n $setSelection,\n} from '@fluentui-copilot/text-editor';\nimport { SENTINEL_VALUE, $isSentinelNode } from '../BasicFunctionality';\n\nexport interface IImperativeControlBase {\n setInputText: (inputText: string) => void;\n appendText: (text: string) => void;\n prependText: (text: string) => void;\n insertTextAtCursor: (text: string) => void;\n /**\n * @param transform will be called for each Lexical node in the input. This enables custom string representation for each node.\n */\n getInputText: (transform?: (node: LexicalNode) => string) => string;\n scrollToBottom: () => void;\n moveCursor: (location: number) => void;\n}\n\nexport class ImperativeControlBase implements IImperativeControlBase {\n private __editor: LexicalEditor;\n\n constructor(editor: LexicalEditor) {\n this.__editor = editor;\n }\n\n moveCursor(location: number): void {\n this.__editor.update(() => {\n const children = $getLeafNodes($getRoot());\n\n let baseOffset = 0;\n let currentNode = children.shift();\n while (baseOffset < location && currentNode) {\n const nodeLength =\n $isTextNode(currentNode) && !currentNode.isToken()\n ? currentNode.getTextContent().length\n : // Token text nodes and non-text nodes are considered to be a single entry in the input\n 1;\n\n if (baseOffset + nodeLength >= location) {\n const elementType = $isTextNode(currentNode) ? 'text' : 'element';\n const localOffset = location - baseOffset;\n const nodeKey = currentNode.getKey();\n\n const selection = $createRangeSelection();\n selection.anchor.set(nodeKey, localOffset, elementType);\n selection.focus.set(nodeKey, localOffset, elementType);\n\n $setSelection($normalizeSelection__EXPERIMENTAL(selection));\n return;\n }\n\n baseOffset += nodeLength;\n currentNode = children.shift();\n }\n\n if (location > baseOffset) {\n $getRoot().selectEnd();\n }\n });\n }\n setInputText(inputText: string) {\n this.__editor.update(() => {\n const root = $getRoot();\n root.clear();\n if (inputText !== '') {\n const newParagraph = $createParagraphNode();\n const newText = $createTextNode(inputText);\n\n newParagraph.append(newText);\n root.append(newParagraph);\n root.selectEnd();\n }\n });\n }\n appendText(text: string) {\n this.__editor.update(() => {\n $getRoot().selectEnd().insertText(text);\n });\n }\n prependText(text: string) {\n this.__editor.update(() => {\n $getRoot().selectStart().insertText(text);\n });\n }\n insertTextAtCursor(text: string) {\n this.__editor.update(() => {\n const selection = $getSelection() ?? $getRoot().selectEnd();\n selection.insertText(text);\n });\n }\n getInputText(transform?: (node: LexicalNode) => string) {\n return this.__editor.getEditorState().read(() => {\n if (!transform) {\n return $getRoot().getTextContent().replace(SENTINEL_VALUE, '');\n }\n const children = $getLeafNodes($getRoot());\n const transformedNodeTexts: string[] = [];\n\n for (const currentNode of children) {\n if (!$isSentinelNode(currentNode)) {\n transformedNodeTexts.push(transform(currentNode));\n }\n }\n\n return transformedNodeTexts.join('');\n });\n }\n scrollToBottom() {\n this.__editor.getRootElement()?.scrollIntoView({ behavior: 'smooth', block: 'end' });\n return;\n }\n}\n"],"names":["ImperativeControlBase","moveCursor","location","__editor","update","children","$getLeafNodes","$getRoot","baseOffset","currentNode","
|
|
1
|
+
{"version":3,"sources":["ImperativeControl.base.ts"],"sourcesContent":["import type { LexicalEditor, LexicalNode } from '@fluentui-copilot/text-editor';\nimport {\n $createParagraphNode,\n $createRangeSelection,\n $createTextNode,\n $getLeafNodes,\n $getRoot,\n $getSelection,\n $isTextNode,\n $normalizeSelection__EXPERIMENTAL,\n $setSelection,\n} from '@fluentui-copilot/text-editor';\nimport { SENTINEL_VALUE, $isSentinelNode } from '../BasicFunctionality';\n\nexport interface IImperativeControlBase {\n setInputText: (inputText: string) => void;\n appendText: (text: string) => void;\n prependText: (text: string) => void;\n insertTextAtCursor: (text: string) => void;\n /**\n * @param transform will be called for each Lexical node in the input. This enables custom string representation for each node.\n */\n getInputText: (transform?: (node: LexicalNode) => string) => string;\n scrollToBottom: () => void;\n moveCursor: (location: number) => void;\n}\n\nexport class ImperativeControlBase implements IImperativeControlBase {\n private __editor: LexicalEditor;\n\n constructor(editor: LexicalEditor) {\n this.__editor = editor;\n }\n\n moveCursor(location: number): void {\n this.__editor.update(() => {\n const children = $getLeafNodes($getRoot());\n\n let baseOffset = 0;\n let currentNode = children.shift();\n while (baseOffset < location && currentNode) {\n const nodeLength =\n $isTextNode(currentNode) && !currentNode.isToken()\n ? currentNode.getTextContent().length\n : // Token text nodes and non-text nodes are considered to be a single entry in the input\n 1;\n\n if (baseOffset + nodeLength >= location) {\n const elementType = $isTextNode(currentNode) ? 'text' : 'element';\n const localOffset = location - baseOffset;\n const nodeKey = currentNode.getKey();\n\n const selection = $createRangeSelection();\n selection.anchor.set(nodeKey, localOffset, elementType);\n selection.focus.set(nodeKey, localOffset, elementType);\n\n $setSelection($normalizeSelection__EXPERIMENTAL(selection));\n return;\n }\n\n baseOffset += nodeLength;\n currentNode = children.shift();\n }\n\n if (location > baseOffset) {\n $getRoot().selectEnd();\n }\n });\n }\n setInputText(inputText: string) {\n this.__editor.update(() => {\n const root = $getRoot();\n root.clear();\n if (inputText !== '') {\n const newParagraph = $createParagraphNode();\n const newText = $createTextNode(inputText);\n\n newParagraph.append(newText);\n root.append(newParagraph);\n root.selectEnd();\n }\n });\n }\n appendText(text: string) {\n this.__editor.update(() => {\n $getRoot().selectEnd().insertText(text);\n });\n }\n prependText(text: string) {\n this.__editor.update(() => {\n $getRoot().selectStart().insertText(text);\n });\n }\n insertTextAtCursor(text: string) {\n this.__editor.update(() => {\n const selection = $getSelection() ?? $getRoot().selectEnd();\n selection.insertText(text);\n });\n }\n getInputText(transform?: (node: LexicalNode) => string) {\n return this.__editor.getEditorState().read(() => {\n if (!transform) {\n return $getRoot().getTextContent().replace(SENTINEL_VALUE, '');\n }\n const children = $getLeafNodes($getRoot());\n const transformedNodeTexts: string[] = [];\n\n for (const currentNode of children) {\n if (!$isSentinelNode(currentNode)) {\n transformedNodeTexts.push(transform(currentNode));\n }\n }\n\n return transformedNodeTexts.join('');\n });\n }\n scrollToBottom() {\n this.__editor.getRootElement()?.scrollIntoView({ behavior: 'smooth', block: 'end' });\n return;\n }\n}\n"],"names":["ImperativeControlBase","moveCursor","location","__editor","update","children","$getLeafNodes","$getRoot","baseOffset","currentNode","nodeLength","$isTextNode","isToken","getTextContent","length","elementType","localOffset","nodeKey","selection","$createRangeSelection","anchor","focus","$setSelection","$normalizeSelection__EXPERIMENTAL","selectEnd","setInputText","inputText","root","newParagraph","$createParagraphNode","newText","$createTextNode","appendText","text","insertText","prependText","selectStart","insertTextAtCursor","$getSelection","getInputText","transform","getEditorState","read","replace","SENTINEL_VALUE","transformedNodeTexts","$isSentinelNode","scrollToBottom","getRootElement","_this___editor_getRootElement","scrollIntoView","behavior","block","constructor","editor"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BA2BaA;;;eAAAA;;;;4BAhBN;oCACyC;AAezC,MAAMA;eAOXC,QAAWC,EAAgB;YACzB,CAAAC,QAAKA,CAAAA,MAASC,CAAAA;kBACZC,WAAMA,IAAAA,yBAAWC,EAAAA,IAAAA,oBAAcC;6BAE3BC;8BACAC,SAAcJ,KAAAA;kBAClBG,aAAOA,YAAaN,YAAYO;mCACxBC,IAAAA,uBACJC,EAAAA,gBAAYF,CAAAA,YAAiBA,OAAAA,KAAYG,YACrCH,cAAYI,GAAAA,MAAc,GAAGC;iCAI/BN,cAAaE,UAAcR;wCACvBa,IAAAA,uBAAcJ,EAAAA,eAAYF,SAAAA;wCAC1BO,WAAcd;oCACde,YAAUR,MAAAA;sCAEVS,IAAAA,iCAAYC;8BAClBD,MAAAA,CAAAA,GAAUE,CAAAA,SAAUJ,aAAUA;8BAC9BE,KAAAA,CAAAA,GAAAA,CAAUG,SAASL,aAAUA;iDAE7BM,EAAAA,IAAAA,6CAAcC,EAAAA;;;8BAIhBf;8BACAC,SAAcJ,KAAAA;;2BAGZH,YAAWM;wCACbD,IAAAA,SAAWiB;;;;iBAIjBC,SAAaC,EAAiB;YAC5B,CAAAvB,QAAKA,CAAAA,MAASC,CAAAA;kBACZuB,OAAMA,IAAAA,oBAAOpB;sBACboB;8BACID,IAAAA;qCACIE,IAAAA,gCAAeC;gCACfC,IAAAA,2BAAUC,EAAAA;6BAEhBH,MAAAA,CAAAA;2BACAD,CAAAA;8BACKH;;;;eAIXQ,IAAWC,EAAY;YACrB,CAAA9B,QAAKA,CAAAA,MAASC,CAAAA;oCACZG,IAAAA,SAAWiB,GAAAA,UAAYU,CAAAA;;;gBAG3BC,IAAYF,EAAY;YACtB,CAAA9B,QAAKA,CAAAA,MAASC,CAAAA;oCACZG,IAAAA,WAAW6B,GAAAA,UAAcF,CAAAA;;;uBAG7BG,IAAmBJ,EAAY;YAC7B,CAAA9B,QAAKA,CAAAA,MAASC,CAAAA;;kBACZc,YAAMA,CAAAA,iBAAYoB,IAAAA,yBAAAA,GAAAA,MAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,iBAAAA,IAAAA,oBAAmB/B,IAAAA,SAAWiB;sBAChDN,UAAUgB,CAAAA;;;iBAGdK,SAAaC,EAAyC;eACpD,IAAO,CAAArC,QAAKA,CAAAA,cAASsC,GAAAA,IAAiBC,CAAAA;4BAC/BF;+CACIjC,IAAAA,cAAWM,GAAAA,OAAc,CAAG8B,kCAAQC,EAAAA;;kBAE7CvC,WAAMA,IAAAA,yBAAWC,EAAAA,IAAAA,oBAAcC;kBAC/BsC,uBAAMA,EAAAA;uBAEDpC,eAAMA,SAAeJ;4DACnByC,EAAAA,cAAgBrC;yCACnBoC,IAAAA,CAAAA,UAA0BL;;;mBAI9BK,qBAAOA,IAAAA,CAAAA;;;qBAGXE;;yCACE,IAAA,CAAA5C,QAAKA,CAAAA,cAAS6C,EAAAA,MAAc,QAAAC,kCAA5B,KAAA,IAAA,KAAA,IAAAA,8BAAAC,cAAgCA,CAAAA;sBAAiBC;mBAAoBC;;;;gBAvFvEC,MAAYC,CAAqB;8BAFjC,EAAA,IAAA,EAAA,YAAQnD,KAAR;YAGE,CAAAA,QAAKA,GAAAA;;AAyFT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["ManualGhostText.base.ts"],"sourcesContent":["import {\n $createTextNode,\n $getNodeByKey,\n $insertNodes,\n type LexicalEditor,\n type LexicalNode,\n} from '@fluentui-copilot/text-editor';\nimport type { IGhostTextNode } from '../GhostText';\n\nexport interface IManualGhostTextBase<ComponentPropsType> {\n getGhostText: () => string | undefined;\n setGhostText: (text: string, exposeText?: boolean, componentProps?: ComponentPropsType, discrete?: boolean) => void;\n commitGhostText: (finalText: string, discrete?: boolean) => void;\n cancelGhostText: (discrete?: boolean) => void;\n}\n\nexport class ManualGhostTextBase<ComponentPropsType> implements IManualGhostTextBase<ComponentPropsType> {\n private __editor: LexicalEditor;\n private __nodeKey?: string;\n\n private __id: string;\n private __$isNodeType: (node: LexicalNode | null) => node is IGhostTextNode<ComponentPropsType>;\n private __$createNode: (\n id: string,\n content: string,\n exposeText?: boolean,\n componentProps?: ComponentPropsType,\n ) => IGhostTextNode<ComponentPropsType>;\n\n constructor(\n editor: LexicalEditor,\n id: string,\n $isNodeType: (node: LexicalNode | null) => node is IGhostTextNode<ComponentPropsType>,\n $createNode: (\n id: string,\n content: string,\n exposeText?: boolean,\n componentProps?: ComponentPropsType,\n ) => IGhostTextNode<ComponentPropsType>,\n ) {\n this.__editor = editor;\n this.__id = id;\n this.__$isNodeType = $isNodeType;\n this.__$createNode = $createNode;\n }\n\n getGhostText(): string | undefined {\n return this.__editor.getEditorState().read(() => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n return node.__content;\n }\n }\n });\n }\n\n setGhostText(text: string, exposeText?: boolean, componentProps?: ComponentPropsType, discrete?: boolean): void {\n this.__editor.update(\n () => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n node.getWritable().__content = text;\n return;\n }\n }\n\n const node = this.__$createNode(this.__id, text, exposeText, componentProps);\n this.__nodeKey = node.getKey();\n $insertNodes([node]);\n node.selectStart();\n },\n { tag: 'historic', discrete: discrete ? true : undefined },\n );\n }\n\n commitGhostText(finalText: string, discrete?: boolean): void {\n if (this.__nodeKey) {\n this.__editor.update(\n () => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n const textNode = $createTextNode(finalText);\n node.replace(textNode);\n textNode.selectEnd();\n }\n }\n },\n { discrete: discrete ? true : undefined },\n );\n this.__nodeKey = undefined;\n }\n }\n\n cancelGhostText(discrete?: boolean): void {\n if (this.__nodeKey) {\n this.__editor.update(\n () => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n node.remove();\n }\n }\n },\n { tag: 'historic', discrete: discrete ? true : undefined },\n );\n this.__nodeKey = undefined;\n }\n }\n}\n"],"names":["ManualGhostTextBase","getGhostText","__editor","getEditorState","read","__nodeKey","
|
|
1
|
+
{"version":3,"sources":["ManualGhostText.base.ts"],"sourcesContent":["import {\n $createTextNode,\n $getNodeByKey,\n $insertNodes,\n type LexicalEditor,\n type LexicalNode,\n} from '@fluentui-copilot/text-editor';\nimport type { IGhostTextNode } from '../GhostText';\n\nexport interface IManualGhostTextBase<ComponentPropsType> {\n getGhostText: () => string | undefined;\n setGhostText: (text: string, exposeText?: boolean, componentProps?: ComponentPropsType, discrete?: boolean) => void;\n commitGhostText: (finalText: string, discrete?: boolean) => void;\n cancelGhostText: (discrete?: boolean) => void;\n}\n\nexport class ManualGhostTextBase<ComponentPropsType> implements IManualGhostTextBase<ComponentPropsType> {\n private __editor: LexicalEditor;\n private __nodeKey?: string;\n\n private __id: string;\n private __$isNodeType: (node: LexicalNode | null) => node is IGhostTextNode<ComponentPropsType>;\n private __$createNode: (\n id: string,\n content: string,\n exposeText?: boolean,\n componentProps?: ComponentPropsType,\n ) => IGhostTextNode<ComponentPropsType>;\n\n constructor(\n editor: LexicalEditor,\n id: string,\n $isNodeType: (node: LexicalNode | null) => node is IGhostTextNode<ComponentPropsType>,\n $createNode: (\n id: string,\n content: string,\n exposeText?: boolean,\n componentProps?: ComponentPropsType,\n ) => IGhostTextNode<ComponentPropsType>,\n ) {\n this.__editor = editor;\n this.__id = id;\n this.__$isNodeType = $isNodeType;\n this.__$createNode = $createNode;\n }\n\n getGhostText(): string | undefined {\n return this.__editor.getEditorState().read(() => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n return node.__content;\n }\n }\n });\n }\n\n setGhostText(text: string, exposeText?: boolean, componentProps?: ComponentPropsType, discrete?: boolean): void {\n this.__editor.update(\n () => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n node.getWritable().__content = text;\n return;\n }\n }\n\n const node = this.__$createNode(this.__id, text, exposeText, componentProps);\n this.__nodeKey = node.getKey();\n $insertNodes([node]);\n node.selectStart();\n },\n { tag: 'historic', discrete: discrete ? true : undefined },\n );\n }\n\n commitGhostText(finalText: string, discrete?: boolean): void {\n if (this.__nodeKey) {\n this.__editor.update(\n () => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n const textNode = $createTextNode(finalText);\n node.replace(textNode);\n textNode.selectEnd();\n }\n }\n },\n { discrete: discrete ? true : undefined },\n );\n this.__nodeKey = undefined;\n }\n }\n\n cancelGhostText(discrete?: boolean): void {\n if (this.__nodeKey) {\n this.__editor.update(\n () => {\n if (this.__nodeKey) {\n const node = $getNodeByKey(this.__nodeKey);\n if (this.__$isNodeType(node)) {\n node.remove();\n }\n }\n },\n { tag: 'historic', discrete: discrete ? true : undefined },\n );\n this.__nodeKey = undefined;\n }\n }\n}\n"],"names":["ManualGhostTextBase","getGhostText","__editor","getEditorState","read","__nodeKey","$getNodeByKey","__$isNodeType","__content","node","setGhostText","text","exposeText","componentProps","discrete","update","getWritable","__$createNode","__id","getKey","$insertNodes","undefined","finalText","commitGhostText","textNode","cancelGhostText","editor","id","$isNodeType","$createNode","_define_property","constructor"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAgBaA;;;eAAAA;;;;4BAVN;AAUA,MAAMA;mBA8BXC;eACE,IAAO,CAAAC,QAAKA,CAAAA,cAASC,GAAAA,IAAiBC,CAAAA;oBACpC,CAAAC,SAASA,EAAAA;6BACPC,IAAAA,yBAAaA,EAAAA,IAAAA,CAAAA,SAAmBD;wBAChC,CAAAE,aAASA,CAAAA,OAAa;gCACpBC,SAAOC;;;;;iBAMfC,IAAaC,EAAYC,UAAEA,EAAoBC,cAAEA,EAAmCC,QAAEA,EAAkB;YACtG,CAAAZ,QAAKA,CAAAA,MAASa,CAAAA;oBAEV,CAAAV,SAASA,EAAAA;6BACPC,IAAAA,yBAAaA,EAAAA,IAAAA,CAAAA,SAAmBD;wBAChC,CAAAE,aAASA,CAAAA,OAAa;oCACfS,GAAAA,SAAW,GAAGR;;;;kBAKvBC,OAAMA,IAAAA,CAAAA,aAAYQ,CAAAA,IAAAA,CAAaC,IAAC,EAAKA,MAAMP,YAAMC;0BAC5CP,GAAAA,KAASc,MAAQA;wCACtBC,EAAAA;gBAAAA;aAAa;4BAACX;;;sBAGhBK,WAAA,OAAAO;;;oBAAyDC,SAAA,EAAAR,QAAA,EAAA;QAE7D,IAAA,IAAA,CAAAT,SAAA,EAAA;YAEAkB,IAAAA,CAAAA,QAAAA,CAAgBD,MAAAA,CAAAA;gBACd,IAAI,IAAI,CAACjB,SAAS,EAAE;0BACdI,OAACP,IAAAA,yBACH,EAAA,IAAA,CAAAG,SAAA;4BACE,CAAAE,aAASF,CAAAA,OAAW;yCACZI,IAAAA,2BAAOH,EAAAA;oCACT,CAAAkB;0CACIA;;;;0BAIVV,WAAA,OAAAO;;0BAEAP,GAAAA;;;oBAGNA,QAAA,EAAA;QACF,IAAA,IAAA,CAAAT,SAAA,EAAA;YAEAoB,IAAAA,CAAAA,QAAAA,CAAgBX,MAAAA,CAAAA;gBACd,IAAI,IAAI,CAACT,SAAS,EAAE;0BACdI,OAACP,IAAAA,yBACH,EAAA,IAAA,CAAAG,SAAA;4BACE,CAAAE,aAASF,CAAAA,OAAW;mCAClB;;;;;0BAMJS,WAAA,OAAAO;;0BAAmBP,GAAAA;;;gBAGvBY,MAAA,EAAAC,EAAA,EAAAC,WAAA,EAAAC,WAAA,CAAA;QACFC,IAAAA,kBAAA,EAAA,IAAA,EAAA,YAAA,KAAA;QAlFAC,IAAAA,kBACEL,EAAAA,IACAC,EAAU,aAC2E,KACrFE;8BAhBF,EAAA,IAAA,EAAA,QAAQ3B,KAAAA;8BACR,EAAA,IAAA,EAAA,iBAAA,KAAA;8BAEA,EAAA,IAAA,EAAA,iBAAA,KAAA;YACA,CAAAA,QAAA,GAAAwB;YACA,CAAAR,IAAA,GAAAS;YAkBE,CAAApB,aAAa,GAAGmB;YAChB,CAAAT,aAAYU,GAAAA;;kDAGd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["PasteUnfurling.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport {\n COMMAND_PRIORITY_EDITOR,\n COMMAND_PRIORITY_LOW,\n PASTE_COMMAND,\n $insertNodes,\n $createTextNode,\n} from '@fluentui-copilot/text-editor';\nimport type {\n PasteUnfurlingPluginBaseProps,\n PasteUnfurlingTransformedPart,\n PasteUnfurlingTransformResult,\n} 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 const transformPromises: Promise<PasteUnfurlingTransformResult<ExtraDataType, NodePropsType>>[] = [];\n\n for (const transform of transforms) {\n transformPromises.push(Promise.resolve(transform(event, editor)));\n }\n\n Promise.allSettled(transformPromises).then(results => {\n let handledPaste = false;\n\n for (const result of results) {\n if (result.status === 'fulfilled') {\n const transformResult = result.value;\n if (transformResult.transformedParts) {\n insertParts(transformResult.transformedParts);\n }\n\n if (transformResult.handled) {\n handledPaste = true;\n break;\n }\n }\n }\n\n if (!handledPaste) {\n const commandsMap = editor._commands;\n const defaultEditorListeners = commandsMap.get(PASTE_COMMAND)?.[COMMAND_PRIORITY_EDITOR];\n if (defaultEditorListeners) {\n // After the promises have resolved, we're not guaranteed to be in the same update state as the original command\n editor.update(() => {\n for (const listener of defaultEditorListeners) {\n const defaultHandled = listener(event, editor);\n if (defaultHandled) {\n break;\n }\n }\n });\n }\n }\n });\n\n return true;\n }\n\n return editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_LOW);\n}\n"],"names":["registerPasteUnfurlingPlugin","unhandledPart","part","Error","editor","props","entityPluginId","
|
|
1
|
+
{"version":3,"sources":["PasteUnfurling.base.ts"],"sourcesContent":["import type { LexicalEditor } from '@fluentui-copilot/text-editor';\nimport {\n COMMAND_PRIORITY_EDITOR,\n COMMAND_PRIORITY_LOW,\n PASTE_COMMAND,\n $insertNodes,\n $createTextNode,\n} from '@fluentui-copilot/text-editor';\nimport type {\n PasteUnfurlingPluginBaseProps,\n PasteUnfurlingTransformedPart,\n PasteUnfurlingTransformResult,\n} 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 const transformPromises: Promise<PasteUnfurlingTransformResult<ExtraDataType, NodePropsType>>[] = [];\n\n for (const transform of transforms) {\n transformPromises.push(Promise.resolve(transform(event, editor)));\n }\n\n Promise.allSettled(transformPromises).then(results => {\n let handledPaste = false;\n\n for (const result of results) {\n if (result.status === 'fulfilled') {\n const transformResult = result.value;\n if (transformResult.transformedParts) {\n insertParts(transformResult.transformedParts);\n }\n\n if (transformResult.handled) {\n handledPaste = true;\n break;\n }\n }\n }\n\n if (!handledPaste) {\n const commandsMap = editor._commands;\n const defaultEditorListeners = commandsMap.get(PASTE_COMMAND)?.[COMMAND_PRIORITY_EDITOR];\n if (defaultEditorListeners) {\n // After the promises have resolved, we're not guaranteed to be in the same update state as the original command\n editor.update(() => {\n for (const listener of defaultEditorListeners) {\n const defaultHandled = listener(event, editor);\n if (defaultHandled) {\n break;\n }\n }\n });\n }\n }\n });\n\n return true;\n }\n\n return editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_LOW);\n}\n"],"names":["registerPasteUnfurlingPlugin","unhandledPart","part","Error","editor","props","entityPluginId","insertParts","nodes","parts","map","$createEntityNode","$insertNodes","transformPromises","handlePaste","event","Promise","transform","handledPaste","result","results","transformResult","handled","transformedParts","defaultEditorListeners","update","_commands","listener","get","PASTE_COMMAND","_commandsMap_get","COMMAND_PRIORITY_EDITOR","defaultHandled"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAkBgBA;;;eAAAA;;;4BAXT;AAOP,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;wCACQW,EAAAA;;;aAINC,YAAAC,KAAA;cAEAC,oBAAmBH,EAAAA;mBACjBI,aAAIC,WAAe;8BAERC,IAAAA,CAAAA,QAAUC,OAAS,CAAAH,UAAAF,OAAAX;;0BAE1B,CAAAS,mBAAMQ,IAAkBF,CAAAA,CAAAA;+BACpBE;iCACFd,QAAYc;iCACd,KAAA,aAAA;4CAEIA,OAAgBC,KAAAA;wCAClBJ,gBAAe,EAAA;oCACfG,gBAAAE,gBAAA;;wCAEJD,OAAA,EAAA;wBACFJ,eAAA;wBAEA;;;;+BAGMM;;oCAEKC,OAAOC,SAAA;+CACDC,CAAAA,mBAAYH,YAAwBI,GAAA,CAAAC,yBAAA,CAAA,MAAA,QAAAC,qBAAA,KAAA,IAAA,KAAA,IAAAA,gBAAA,CAAAC,mCAAA,CAAA;4CACvCC;oIACc;;+CAEpBR,uBAAA;mDACFG,SAAAZ,OAAAX;gDACF;gCACF;4BACF;wBACF;oBAEA;gBACF;YAEA;QACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["PasteUnfurlingTestUtils.ts"],"sourcesContent":["import type { LexicalNode } from '@fluentui-copilot/text-editor';\nimport { TextNode } from '@fluentui-copilot/text-editor';\nimport type { PasteUnfurlingTransformedPart, PasteUnfurlingTransformResult } from '..';\n\nexport class MockClipboardEvent extends Event implements ClipboardEvent {\n clipboardData: DataTransfer | null = null;\n}\n\nexport function createPasteEvent(data: { mimeType: string; value: string }[]) {\n const event = new MockClipboardEvent('paste');\n\n event.clipboardData = {\n types: [data.map(({ mimeType }) => mimeType)],\n getData: (format: string) => {\n const item = data.find(({ mimeType }) => mimeType === format);\n if (item) {\n return item.value;\n }\n return '';\n },\n } as unknown as DataTransfer;\n\n return event;\n}\n\nexport class MockEntityNode extends TextNode {\n url: string;\n\n constructor(text: string, url: string) {\n super(text);\n this.url = url;\n }\n\n static getType(): string {\n return 'mockEntity';\n }\n}\n\nexport type ExtraDataType = { url: string };\n\nexport function $createMockEntityNode(text: string, url: string): MockEntityNode {\n return new MockEntityNode(text, url);\n}\n\nexport function $isMockEntityNode(node: LexicalNode | null | undefined): node is MockEntityNode {\n return node instanceof MockEntityNode;\n}\n\nexport const parseLinkPreview = (event: ClipboardEvent): PasteUnfurlingTransformResult<ExtraDataType, {}> => {\n let previewData;\n try {\n const previewDataString = event.clipboardData?.getData('text/link-preview');\n if (previewDataString === undefined || previewDataString === '') {\n return { handled: false };\n }\n\n previewData = JSON.parse(previewDataString);\n } catch (e) {\n return { handled: false };\n }\n\n const title: string | undefined = previewData.title;\n const url: string | undefined = previewData.url;\n if (!title || !url) {\n return { handled: false };\n }\n\n return {\n handled: true,\n transformedParts: [{ type: 'entity', value: { text: title, data: { url } } }],\n };\n};\nconst urlRegex = /(\\b(?:https?):\\/\\/[^\\s]+)/gi;\n\nexport const parseLink = (event: ClipboardEvent): PasteUnfurlingTransformResult<ExtraDataType, {}> => {\n const text = event.clipboardData?.getData('text/plain');\n if (!text) {\n return {\n handled: false,\n };\n }\n\n const parts = text.split(urlRegex);\n // If an entity was found, parts will be at least 3 elements long\n if (parts.length < 3) {\n return { handled: false };\n }\n const transformedParts = parts\n .map((str, i) => {\n if (i % 2 === 0) {\n return { type: 'text', value: str };\n } else {\n return {\n type: 'entity',\n value: { text: str, data: { url: str } },\n };\n }\n })\n // Filter out all the nulls for empty strings\n .filter(node => node !== null) as PasteUnfurlingTransformedPart<ExtraDataType, {}>[];\n\n return { handled: true, transformedParts };\n};\n\n// A transform can be async in case it needs to fetch data from a server.\nexport const parseEntity = async (event: ClipboardEvent): Promise<PasteUnfurlingTransformResult<ExtraDataType, {}>> => {\n const text = event.clipboardData?.getData('text/plain');\n if (!text) {\n return {\n handled: false,\n };\n }\n\n // Assume entities come in the syntax <entity>title</entity>\n const re = /<entity[^>]*>([^<]*)<\\/entity>/g;\n const parts = text.split(re);\n // If an entity was found, parts will be at least 3 elements long\n if (parts.length < 3) {\n return { handled: false };\n }\n\n // Even elements are text, odd elements are entities\n // [\"\", entity, \"\", entity, \"\", ...]\n const transformedParts = parts\n .map((str, i) => {\n if (i % 2 === 0) {\n return { type: 'text', value: str };\n } else {\n return {\n type: 'entity',\n value: { text: str, data: { url: str } },\n };\n }\n })\n // Filter out all the nulls for empty strings\n .filter(node => node !== null) as PasteUnfurlingTransformedPart<ExtraDataType, {}>[];\n\n return { handled: true, transformedParts };\n};\n"],"names":["$createMockEntityNode","$isMockEntityNode","MockClipboardEvent","MockEntityNode","createPasteEvent","parseEntity","parseLink","parseLinkPreview","Event","clipboardData","data","event","types","map","mimeType","getData","
|
|
1
|
+
{"version":3,"sources":["PasteUnfurlingTestUtils.ts"],"sourcesContent":["import type { LexicalNode } from '@fluentui-copilot/text-editor';\nimport { TextNode } from '@fluentui-copilot/text-editor';\nimport type { PasteUnfurlingTransformedPart, PasteUnfurlingTransformResult } from '..';\n\nexport class MockClipboardEvent extends Event implements ClipboardEvent {\n clipboardData: DataTransfer | null = null;\n}\n\nexport function createPasteEvent(data: { mimeType: string; value: string }[]) {\n const event = new MockClipboardEvent('paste');\n\n event.clipboardData = {\n types: [data.map(({ mimeType }) => mimeType)],\n getData: (format: string) => {\n const item = data.find(({ mimeType }) => mimeType === format);\n if (item) {\n return item.value;\n }\n return '';\n },\n } as unknown as DataTransfer;\n\n return event;\n}\n\nexport class MockEntityNode extends TextNode {\n url: string;\n\n constructor(text: string, url: string) {\n super(text);\n this.url = url;\n }\n\n static getType(): string {\n return 'mockEntity';\n }\n}\n\nexport type ExtraDataType = { url: string };\n\nexport function $createMockEntityNode(text: string, url: string): MockEntityNode {\n return new MockEntityNode(text, url);\n}\n\nexport function $isMockEntityNode(node: LexicalNode | null | undefined): node is MockEntityNode {\n return node instanceof MockEntityNode;\n}\n\nexport const parseLinkPreview = (event: ClipboardEvent): PasteUnfurlingTransformResult<ExtraDataType, {}> => {\n let previewData;\n try {\n const previewDataString = event.clipboardData?.getData('text/link-preview');\n if (previewDataString === undefined || previewDataString === '') {\n return { handled: false };\n }\n\n previewData = JSON.parse(previewDataString);\n } catch (e) {\n return { handled: false };\n }\n\n const title: string | undefined = previewData.title;\n const url: string | undefined = previewData.url;\n if (!title || !url) {\n return { handled: false };\n }\n\n return {\n handled: true,\n transformedParts: [{ type: 'entity', value: { text: title, data: { url } } }],\n };\n};\nconst urlRegex = /(\\b(?:https?):\\/\\/[^\\s]+)/gi;\n\nexport const parseLink = (event: ClipboardEvent): PasteUnfurlingTransformResult<ExtraDataType, {}> => {\n const text = event.clipboardData?.getData('text/plain');\n if (!text) {\n return {\n handled: false,\n };\n }\n\n const parts = text.split(urlRegex);\n // If an entity was found, parts will be at least 3 elements long\n if (parts.length < 3) {\n return { handled: false };\n }\n const transformedParts = parts\n .map((str, i) => {\n if (i % 2 === 0) {\n return { type: 'text', value: str };\n } else {\n return {\n type: 'entity',\n value: { text: str, data: { url: str } },\n };\n }\n })\n // Filter out all the nulls for empty strings\n .filter(node => node !== null) as PasteUnfurlingTransformedPart<ExtraDataType, {}>[];\n\n return { handled: true, transformedParts };\n};\n\n// A transform can be async in case it needs to fetch data from a server.\nexport const parseEntity = async (event: ClipboardEvent): Promise<PasteUnfurlingTransformResult<ExtraDataType, {}>> => {\n const text = event.clipboardData?.getData('text/plain');\n if (!text) {\n return {\n handled: false,\n };\n }\n\n // Assume entities come in the syntax <entity>title</entity>\n const re = /<entity[^>]*>([^<]*)<\\/entity>/g;\n const parts = text.split(re);\n // If an entity was found, parts will be at least 3 elements long\n if (parts.length < 3) {\n return { handled: false };\n }\n\n // Even elements are text, odd elements are entities\n // [\"\", entity, \"\", entity, \"\", ...]\n const transformedParts = parts\n .map((str, i) => {\n if (i % 2 === 0) {\n return { type: 'text', value: str };\n } else {\n return {\n type: 'entity',\n value: { text: str, data: { url: str } },\n };\n }\n })\n // Filter out all the nulls for empty strings\n .filter(node => node !== null) as PasteUnfurlingTransformedPart<ExtraDataType, {}>[];\n\n return { handled: true, transformedParts };\n};\n"],"names":["$createMockEntityNode","$isMockEntityNode","MockClipboardEvent","MockEntityNode","createPasteEvent","parseEntity","parseLink","parseLinkPreview","Event","clipboardData","data","event","types","map","mimeType","getData","item","find","value","TextNode","getType","constructor","url","text","_define_property","node","_event_clipboardData","undefined","previewDataString","handled","JSON","parse","title","previewData","transformedParts","urlRegex","parts","split","length","str","i","filter","re"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;;;;;;;;IA0CAA,qBAAA;eAAAA;;IAIAC,iBAAA;eAAAA;;IA1CaC,kBAAAA;eAAAA;;IA8BTC,cAAO;eAAPA;;IA1BYC,gBAAAA;eAAAA;;IAiGHC,WAAAA;eAAAA;;IA/BAC,SAAAA;eAAAA;;IAxBPC,gBAAA;eAAAA;;;;4BAjDmB;AAGlB,MAAML,2BAA2BM;;;8BACtCC,EAAAA,IAAAA,EAAAA,iBAAAA;;AACF;AAEO,SAASL,iBAAiBM,IAA2C;UAC1EC,QAAMA,IAAQT,mBAAIA;UAElBS,aAAMF,GAAa;eACjBG;YAAAA,KAAOC,GAAA,CAAA,CAAA,UAACH,KAAqCI;SAAA;iBAC7CC,CAAAA;kBACEC,OAAMA,KAAAA,IAAON,CAAAA,CAAKO,UACdD,kBACKA;sBACT;uBACAA,KAAOE,KAAA;;YAEX,OAAA;QAEA;IACF;IAEA,OAAOP;;MASHR,uBAAOgB,oBAAA;WACTC,UAAA;QAPAC,OAAAA;;gBAFAC,IAAAA,EAAAA,GAAAA,CAAAA;aAIE,CAAAC;QACFC,IAAAA,kBAAA,EAAA,IAAA,EAAA,OAAA,KAAA;QAKF,IAAA,CAAAF,GAAA,GAAAA;IAIA;;AAEA,SAAAtB,sBAAAuB,IAAA,EAAAD,GAAA;IAEA,OAAO,IAAAnB,eAASF,MAAkBwB;;AAElC,SAAAxB,kBAAAwB,IAAA;IAEA,OAAOA,gBAAMlB;;AAEX,MAAIA,mBAAAI,CAAAA;;;YAEFe;kCACS,AAAAA,CAAAA,uBAAAf,MAAAF,aAAA,MAAA,QAAAiB,yBAAA,KAAA,IAAA,KAAA,IAAAA,qBAAAX,OAAA,CAAA;kCAAWY,aAAAC,sBAAA,IAAA;mBAAM;gBAC1BC,SAAA;;QAGF;sBACSC,KAAAC,KAAA,CAAAH;gBAAEC;eAAe;YAC1BA,SAAA;QAEA;;UAEIG,QAACA,YAAeA,KAAA;UAClBV,MAAAW,YAAOX,GAAA;kBAAEO,CAAAA,KAAS;eAAM;YAC1BA,SAAA;QAEA;;WAEEK;iBAAmB;0BAAQ;YAAA;;;;;;;;;;;AAE/B;AACA,MAAMC,WAAW;AAEV,MAAM7B,YAAYK,CAAAA;;UACvBY,OAAMA,CAAAA,uBAAOZ,MAAAA,aAAMF,MAAa,QAAAiB,yBAAnBf,KAAAA,IAAAA,KAAAA,IAAAA,qBAAAA,OAAqBI,CAAAA;QAClC,CAAAQ,MAAKA;eACH;qBACEM;;;UAIJO,QAAMA,KAAQb,KAAKc,CAAAA;qEACnB;QACAD,MAAIA,MAAME,GAAM,GAAG;eACjB;qBAAST;;;UAEXK,mBAAMA,MAAmBE,GACtBvB,CAAAA,CAAG0B,KAAEA;YACJC,IAAIA,MAAI,GAAA;mBACN;;;;eACF;mBACE;;;;;;;;;;OAKJ,6CACA;WACCC,CAAAA,CAAAA,OAAOhB,SAAQA;WAElB;iBAASI;;;AACX;AAGO,MAAMxB,cAAc,OAAAM;;UACzBY,OAAMA,CAAAA,uBAAOZ,MAAAA,aAAMF,MAAa,QAAAiB,yBAAnBf,KAAAA,IAAAA,KAAAA,IAAAA,qBAAAA,OAAqBI,CAAAA;QAClC,CAAAQ,MAAKA;eACH;qBACEM;;;gEAIJ;UACAa,KAAMA;UACNN,QAAMA,KAAQb,KAAKc,CAAAA;qEACnB;QACAD,MAAIA,MAAME,GAAM,GAAG;eACjB;qBAAST;;;wDAGX;wCACA;UACAK,mBAAMA,MAAmBE,GACtBvB,CAAAA,CAAG0B,KAAEA;YACJC,IAAIA,MAAI,GAAA;mBACN;;;;eACF;mBACE;;;;;;;;;;OAKJ,6CACA;WACCC,CAAAA,CAAAA,OAAOhB,SAAQA;WAElB;iBAASI;;;AACX"}
|
package/lib-commonjs/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluentui-copilot/chat-input-plugins",
|
|
3
|
-
"version": "0.4.2-hotfix.
|
|
3
|
+
"version": "0.4.2-hotfix.3",
|
|
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.3.1-hotfix.
|
|
15
|
+
"@fluentui-copilot/text-editor": "0.3.1-hotfix.3",
|
|
16
16
|
"@swc/helpers": "^0.5.1"
|
|
17
17
|
},
|
|
18
18
|
"beachball": {},
|