mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
fix prompt editor
This commit is contained in:
@ -9,7 +9,10 @@ import {
|
||||
$getRoot,
|
||||
TextNode,
|
||||
} from 'lexical'
|
||||
import { CodeNode } from '@lexical/code'
|
||||
import {
|
||||
CodeHighlightNode,
|
||||
CodeNode,
|
||||
} from '@lexical/code'
|
||||
import { LexicalComposer } from '@lexical/react/LexicalComposer'
|
||||
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
|
||||
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
|
||||
@ -44,6 +47,7 @@ import { VariableValueBlockNode } from './plugins/variable-value-block/node'
|
||||
import { CustomTextNode } from './plugins/custom-text/node'
|
||||
import OnBlurBlock from './plugins/on-blur-or-focus-block'
|
||||
import UpdateBlock from './plugins/update-block'
|
||||
import CodeHighlightBlock from './plugins/code-highlight-block'
|
||||
import { textToEditorState } from './utils'
|
||||
import type {
|
||||
ContextBlockType,
|
||||
@ -61,6 +65,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
|
||||
export type PromptEditorProps = {
|
||||
instanceId?: string
|
||||
compact?: boolean
|
||||
className?: string
|
||||
placeholder?: string
|
||||
placeholderClassName?: string
|
||||
@ -80,6 +85,7 @@ export type PromptEditorProps = {
|
||||
|
||||
const PromptEditor: FC<PromptEditorProps> = ({
|
||||
instanceId,
|
||||
compact,
|
||||
className,
|
||||
placeholder,
|
||||
placeholderClassName,
|
||||
@ -101,6 +107,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
||||
namespace: 'prompt-editor',
|
||||
nodes: [
|
||||
CodeNode,
|
||||
CodeHighlightNode,
|
||||
CustomTextNode,
|
||||
{
|
||||
replace: TextNode,
|
||||
@ -141,8 +148,8 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
||||
<LexicalComposer initialConfig={{ ...initialConfig, editable }}>
|
||||
<div className='relative'>
|
||||
<RichTextPlugin
|
||||
contentEditable={<ContentEditable className={`${className} outline-none text-sm text-gray-700 leading-6`} style={style || {}} />}
|
||||
placeholder={<Placeholder value={placeholder} className={placeholderClassName} />}
|
||||
contentEditable={<ContentEditable className={`${className} outline-none ${compact ? 'leading-5 text-[13px]' : 'leading-6 text-sm'} text-gray-700`} style={style || {}} />}
|
||||
placeholder={<Placeholder value={placeholder} className={placeholderClassName} compact={compact} />}
|
||||
ErrorBoundary={LexicalErrorBoundary}
|
||||
/>
|
||||
<ComponentPickerBlock
|
||||
@ -207,6 +214,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
||||
<OnChangePlugin onChange={handleEditorChange} />
|
||||
<OnBlurBlock onBlur={onBlur} onFocus={onFocus} />
|
||||
<UpdateBlock instanceId={instanceId} />
|
||||
<CodeHighlightBlock />
|
||||
{/* <TreeView /> */}
|
||||
</div>
|
||||
</LexicalComposer>
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import { useEffect } from 'react'
|
||||
import { registerCodeHighlighting } from '@lexical/code'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
|
||||
export default function CodeHighlightPlugin() {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
useEffect(() => {
|
||||
return registerCodeHighlighting(editor)
|
||||
}, [editor])
|
||||
|
||||
return null
|
||||
}
|
||||
@ -195,7 +195,7 @@ export const useOptions = (
|
||||
variableOptions,
|
||||
externalToolOptions,
|
||||
workflowVariableOptions,
|
||||
allOptions: [...promptOptions, ...variableOptions, ...externalToolOptions, ...workflowVariableOptions],
|
||||
allOptions: [...promptOptions, ...variableOptions, ...externalToolOptions],
|
||||
}
|
||||
}, [promptOptions, variableOptions, externalToolOptions, workflowVariableOptions])
|
||||
}
|
||||
|
||||
@ -82,11 +82,12 @@ const ComponentPicker = ({
|
||||
matchingString: string,
|
||||
) => {
|
||||
editor.update(() => {
|
||||
if (nodeToRemove)
|
||||
if (nodeToRemove && selectedOption?.key)
|
||||
nodeToRemove.remove()
|
||||
|
||||
if (selectedOption?.onSelect)
|
||||
selectedOption.onSelect(matchingString)
|
||||
|
||||
closeMenu()
|
||||
})
|
||||
},
|
||||
@ -104,9 +105,9 @@ const ComponentPicker = ({
|
||||
anchorElementRef,
|
||||
{ selectedIndex, selectOptionAndCleanUp, setHighlightedIndex },
|
||||
) => {
|
||||
if (anchorElementRef.current && allOptions.length) {
|
||||
if (anchorElementRef.current && (allOptions.length || workflowVariableOptions.length)) {
|
||||
return ReactDOM.createPortal(
|
||||
<div className='mt-[25px] w-[260px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
|
||||
<div className='w-[260px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
|
||||
{
|
||||
!!promptOptions.length && (
|
||||
<>
|
||||
@ -196,8 +197,7 @@ const ComponentPicker = ({
|
||||
<VarReferenceVars
|
||||
hideSearch
|
||||
vars={workflowVariableOptions}
|
||||
onChange={(variables: string[], item: any) => {
|
||||
selectOptionAndCleanUp(item)
|
||||
onChange={(variables: string[]) => {
|
||||
handleSelectWorkflowVariable(variables)
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -1,20 +1,27 @@
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import cn from 'classnames'
|
||||
|
||||
const Placeholder = ({
|
||||
compact,
|
||||
value,
|
||||
className,
|
||||
}: {
|
||||
compact?: boolean
|
||||
value?: string
|
||||
className?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'absolute top-0 left-0 h-full w-full text-sm text-gray-300 select-none pointer-events-none leading-6')}>
|
||||
<div className={cn(
|
||||
className,
|
||||
'absolute top-0 left-0 h-full w-full text-sm text-gray-300 select-none pointer-events-none',
|
||||
compact ? 'leading-5 text-[13px]' : 'leading-6 text-sm',
|
||||
)}>
|
||||
{value || t('common.promptEditor.placeholder')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Placeholder
|
||||
export default memo(Placeholder)
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { $insertNodes } from 'lexical'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { textToEditorState } from '../utils'
|
||||
import { CustomTextNode } from './custom-text/node'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
|
||||
export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'
|
||||
export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'
|
||||
|
||||
type UpdateBlockProps = {
|
||||
instanceId?: string
|
||||
@ -20,6 +23,16 @@ const UpdateBlock = ({
|
||||
}
|
||||
})
|
||||
|
||||
eventEmitter?.useSubscription((v: any) => {
|
||||
if (v.type === PROMPT_EDITOR_INSERT_QUICKLY && v.instanceId === instanceId) {
|
||||
editor.focus()
|
||||
editor.update(() => {
|
||||
const textNode = new CustomTextNode('/')
|
||||
$insertNodes([textNode])
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ const WorkflowVariableBlockComponent: FC<WorkflowVariableBlockComponentProps> =
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
mr-[2px] relative group/wrap flex items-center h-[20px] pl-0.5 pr-[3px] rounded-[5px] border
|
||||
mx-0.5 relative group/wrap flex items-center h-[18px] pl-0.5 pr-[3px] rounded-[5px] border
|
||||
${isSelected ? ' border-[#84ADFF] bg-[#F5F8FF]' : ' border-black/5 bg-white'}
|
||||
`}
|
||||
ref={ref}
|
||||
|
||||
@ -3,6 +3,8 @@ import {
|
||||
useEffect,
|
||||
} from 'react'
|
||||
import {
|
||||
$getNodeByKey,
|
||||
$getPreviousSelection,
|
||||
$insertNodes,
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
createCommand,
|
||||
@ -39,9 +41,16 @@ const WorkflowVariableBlock = memo(({
|
||||
editor.registerCommand(
|
||||
INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND,
|
||||
(variables: string[]) => {
|
||||
const contextBlockNode = $createWorkflowVariableBlockNode(variables, getWorkflowNode)
|
||||
const workflowVariableBlockNode = $createWorkflowVariableBlockNode(variables, getWorkflowNode)
|
||||
const prevNodeKey = ($getPreviousSelection() as any)?.anchor?.key
|
||||
|
||||
$insertNodes([contextBlockNode])
|
||||
if (prevNodeKey) {
|
||||
const prevNode = $getNodeByKey(prevNodeKey)
|
||||
|
||||
prevNode?.remove()
|
||||
}
|
||||
|
||||
$insertNodes([workflowVariableBlockNode])
|
||||
if (onInsert)
|
||||
onInsert()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user