-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: get node variables in prompt editor
- Loading branch information
1 parent
5cb1965
commit 63fd5f5
Showing
11 changed files
with
659 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
...nts/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/components/VariableLabel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { ChevronRightIcon } from '@chakra-ui/icons'; | ||
|
||
export default function VariableLabel({ | ||
variableKey, | ||
variableLabel, | ||
nodeAvatar | ||
}: { | ||
variableKey: string; | ||
variableLabel: string; | ||
nodeAvatar: string; | ||
}) { | ||
const [parentLabel, childLabel] = variableLabel.split('.'); | ||
|
||
return ( | ||
<span | ||
style={{ | ||
display: 'inline-block', | ||
margin: '0 2px', | ||
border: '1px solid #E8EBF0', | ||
borderRadius: '4px', | ||
padding: '2px 4px' | ||
}} | ||
> | ||
<span> | ||
<img src={nodeAvatar} style={{ width: '16px', display: 'inline', margin: '0 2px' }} /> | ||
</span> | ||
<span>{parentLabel}</span> | ||
<span> | ||
<ChevronRightIcon /> | ||
</span> | ||
<span>{childLabel}</span> | ||
</span> | ||
); | ||
} |
62 changes: 62 additions & 0 deletions
62
packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; | ||
import { EditorVariablePickerType } from '../../type'; | ||
import { useCallback, useEffect, useMemo } from 'react'; | ||
import { $createVariableLabelNode, VariableLabelNode } from './node'; | ||
import { TextNode } from 'lexical'; | ||
import { getHashtagRegexString } from './utils'; | ||
import { mergeRegister } from '@lexical/utils'; | ||
import { registerLexicalTextEntity } from '../../utils'; | ||
|
||
const REGEX = new RegExp(getHashtagRegexString(), 'i'); | ||
|
||
export default function VariableLabelPlugin({ | ||
variables | ||
}: { | ||
variables: EditorVariablePickerType[]; | ||
}) { | ||
const [editor] = useLexicalComposerContext(); | ||
useEffect(() => { | ||
if (!editor.hasNodes([VariableLabelNode])) | ||
throw new Error('VariableLabelPlugin: VariableLabelPlugin not registered on editor'); | ||
}, [editor]); | ||
|
||
const variableKeys: Array<string> = useMemo(() => { | ||
return variables.map((item) => `${item.parent?.id}.${item.key}`); | ||
}, [variables]); | ||
|
||
const createVariableLabelPlugin = useCallback((textNode: TextNode): VariableLabelNode => { | ||
const [parentKey, childrenKey] = textNode.getTextContent().slice(3, -3).split('.'); | ||
const currentVariable = variables.find( | ||
(item) => item.parent?.id === parentKey && item.key === childrenKey | ||
); | ||
const variableLabel = `${currentVariable?.parent?.label}.${currentVariable?.label}`; | ||
const nodeAvatar = currentVariable?.parent?.avatar || ''; | ||
return $createVariableLabelNode(textNode.getTextContent(), variableLabel, nodeAvatar); | ||
}, []); | ||
|
||
const getVariableMatch = useCallback((text: string) => { | ||
const matches = REGEX.exec(text); | ||
if (!matches) return null; | ||
// if (variableKeys.indexOf(matches[4]) === -1) return null; | ||
const hashtagLength = matches[4].length + 6; | ||
const startOffset = matches.index; | ||
const endOffset = startOffset + hashtagLength; | ||
return { | ||
end: endOffset, | ||
start: startOffset | ||
}; | ||
}, []); | ||
|
||
useEffect(() => { | ||
mergeRegister( | ||
...registerLexicalTextEntity( | ||
editor, | ||
getVariableMatch, | ||
VariableLabelNode, | ||
createVariableLabelPlugin | ||
) | ||
); | ||
}, [createVariableLabelPlugin, editor, getVariableMatch]); | ||
|
||
return null; | ||
} |
130 changes: 130 additions & 0 deletions
130
packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/node.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { | ||
DecoratorNode, | ||
DOMConversionMap, | ||
DOMExportOutput, | ||
EditorConfig, | ||
LexicalEditor, | ||
LexicalNode, | ||
NodeKey, | ||
SerializedLexicalNode, | ||
Spread, | ||
TextFormatType | ||
} from 'lexical'; | ||
import VariableLabel from './components/VariableLabel'; | ||
|
||
export type SerializedVariableLabelNode = Spread< | ||
{ | ||
variableKey: string; | ||
variableLabel: string; | ||
nodeAvatar: string; | ||
format: number | TextFormatType; | ||
}, | ||
SerializedLexicalNode | ||
>; | ||
|
||
export class VariableLabelNode extends DecoratorNode<JSX.Element> { | ||
__format: number | TextFormatType; | ||
__variableKey: string; | ||
__variableLabel: string; | ||
__nodeAvatar: string; | ||
static getType(): string { | ||
return 'variableLabel'; | ||
} | ||
static clone(node: VariableLabelNode): VariableLabelNode { | ||
return new VariableLabelNode( | ||
node.__variableKey, | ||
node.__variableLabel, | ||
node.__nodeAvatar, | ||
node.__format, | ||
node.__key | ||
); | ||
} | ||
constructor( | ||
variableKey: string, | ||
variableLabel: string, | ||
nodeAvatar: string, | ||
format?: number | TextFormatType, | ||
key?: NodeKey | ||
) { | ||
super(key); | ||
this.__variableKey = variableKey; | ||
this.__format = format || 0; | ||
this.__variableLabel = variableLabel; | ||
this.__nodeAvatar = nodeAvatar; | ||
} | ||
|
||
static importJSON(serializedNode: SerializedVariableLabelNode): VariableLabelNode { | ||
const node = $createVariableLabelNode( | ||
serializedNode.variableKey, | ||
serializedNode.variableLabel, | ||
serializedNode.nodeAvatar | ||
); | ||
node.setFormat(serializedNode.format); | ||
return node; | ||
} | ||
|
||
setFormat(format: number | TextFormatType): void { | ||
const self = this.getWritable(); | ||
self.__format = format; | ||
} | ||
getFormat(): number | TextFormatType { | ||
return this.__format; | ||
} | ||
|
||
exportJSON(): SerializedVariableLabelNode { | ||
return { | ||
format: this.__format || 0, | ||
type: 'variableLabel', | ||
version: 1, | ||
variableKey: this.getVariableKey(), | ||
variableLabel: this.__variableLabel, | ||
nodeAvatar: this.__nodeAvatar | ||
}; | ||
} | ||
createDOM(): HTMLElement { | ||
const element = document.createElement('span'); | ||
return element; | ||
} | ||
exportDOM(): DOMExportOutput { | ||
const element = document.createElement('span'); | ||
return { element }; | ||
} | ||
static importDOM(): DOMConversionMap | null { | ||
return {}; | ||
} | ||
updateDOM(): false { | ||
return false; | ||
} | ||
getVariableKey(): string { | ||
return this.__variableKey; | ||
} | ||
getTextContent( | ||
_includeInert?: boolean | undefined, | ||
_includeDirectionless?: false | undefined | ||
): string { | ||
return `${this.__variableKey}`; | ||
} | ||
decorate(_editor: LexicalEditor, config: EditorConfig): JSX.Element { | ||
return ( | ||
<VariableLabel | ||
variableKey={this.__variableKey} | ||
variableLabel={this.__variableLabel} | ||
nodeAvatar={this.__nodeAvatar} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
export function $createVariableLabelNode( | ||
variableKey: string, | ||
variableLabel: string, | ||
nodeAvatar: string | ||
): VariableLabelNode { | ||
return new VariableLabelNode(variableKey, variableLabel, nodeAvatar); | ||
} | ||
|
||
export function $isVariableLabelNode( | ||
node: VariableLabelNode | LexicalNode | null | undefined | ||
): node is VariableLabelNode { | ||
return node instanceof VariableLabelNode; | ||
} |
Oops, something went wrong.