mirror of
				https://github.com/langgenius/dify.git
				synced 2025-11-03 20:33:00 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			227 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
'use client'
 | 
						|
 | 
						|
import type { FC } from 'react'
 | 
						|
import { useEffect } from 'react'
 | 
						|
import type {
 | 
						|
  EditorState,
 | 
						|
} from 'lexical'
 | 
						|
import {
 | 
						|
  $getRoot,
 | 
						|
  TextNode,
 | 
						|
} from 'lexical'
 | 
						|
import { CodeNode } from '@lexical/code'
 | 
						|
import { LexicalComposer } from '@lexical/react/LexicalComposer'
 | 
						|
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
 | 
						|
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
 | 
						|
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'
 | 
						|
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
 | 
						|
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'
 | 
						|
// import TreeView from './plugins/tree-view'
 | 
						|
import Placeholder from './plugins/placeholder'
 | 
						|
import ComponentPickerBlock from './plugins/component-picker-block'
 | 
						|
import {
 | 
						|
  ContextBlock,
 | 
						|
  ContextBlockNode,
 | 
						|
  ContextBlockReplacementBlock,
 | 
						|
} from './plugins/context-block'
 | 
						|
import {
 | 
						|
  QueryBlock,
 | 
						|
  QueryBlockNode,
 | 
						|
  QueryBlockReplacementBlock,
 | 
						|
} from './plugins/query-block'
 | 
						|
import {
 | 
						|
  HistoryBlock,
 | 
						|
  HistoryBlockNode,
 | 
						|
  HistoryBlockReplacementBlock,
 | 
						|
} from './plugins/history-block'
 | 
						|
import {
 | 
						|
  WorkflowVariableBlock,
 | 
						|
  WorkflowVariableBlockNode,
 | 
						|
  WorkflowVariableBlockReplacementBlock,
 | 
						|
} from './plugins/workflow-variable-block'
 | 
						|
import VariableBlock from './plugins/variable-block'
 | 
						|
import VariableValueBlock from './plugins/variable-value-block'
 | 
						|
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 { textToEditorState } from './utils'
 | 
						|
import type {
 | 
						|
  ContextBlockType,
 | 
						|
  ExternalToolBlockType,
 | 
						|
  HistoryBlockType,
 | 
						|
  QueryBlockType,
 | 
						|
  VariableBlockType,
 | 
						|
  WorkflowVariableBlockType,
 | 
						|
} from './types'
 | 
						|
import {
 | 
						|
  UPDATE_DATASETS_EVENT_EMITTER,
 | 
						|
  UPDATE_HISTORY_EVENT_EMITTER,
 | 
						|
} from './constants'
 | 
						|
import { useEventEmitterContextContext } from '@/context/event-emitter'
 | 
						|
import cn from '@/utils/classnames'
 | 
						|
 | 
						|
export type PromptEditorProps = {
 | 
						|
  instanceId?: string
 | 
						|
  compact?: boolean
 | 
						|
  className?: string
 | 
						|
  placeholder?: string
 | 
						|
  placeholderClassName?: string
 | 
						|
  style?: React.CSSProperties
 | 
						|
  value?: string
 | 
						|
  editable?: boolean
 | 
						|
  onChange?: (text: string) => void
 | 
						|
  onBlur?: () => void
 | 
						|
  onFocus?: () => void
 | 
						|
  contextBlock?: ContextBlockType
 | 
						|
  queryBlock?: QueryBlockType
 | 
						|
  historyBlock?: HistoryBlockType
 | 
						|
  variableBlock?: VariableBlockType
 | 
						|
  externalToolBlock?: ExternalToolBlockType
 | 
						|
  workflowVariableBlock?: WorkflowVariableBlockType
 | 
						|
  isSupportFileVar?: boolean
 | 
						|
}
 | 
						|
 | 
						|
const PromptEditor: FC<PromptEditorProps> = ({
 | 
						|
  instanceId,
 | 
						|
  compact,
 | 
						|
  className,
 | 
						|
  placeholder,
 | 
						|
  placeholderClassName,
 | 
						|
  style,
 | 
						|
  value,
 | 
						|
  editable = true,
 | 
						|
  onChange,
 | 
						|
  onBlur,
 | 
						|
  onFocus,
 | 
						|
  contextBlock,
 | 
						|
  queryBlock,
 | 
						|
  historyBlock,
 | 
						|
  variableBlock,
 | 
						|
  externalToolBlock,
 | 
						|
  workflowVariableBlock,
 | 
						|
  isSupportFileVar,
 | 
						|
}) => {
 | 
						|
  const { eventEmitter } = useEventEmitterContextContext()
 | 
						|
  const initialConfig = {
 | 
						|
    namespace: 'prompt-editor',
 | 
						|
    nodes: [
 | 
						|
      CodeNode,
 | 
						|
      CustomTextNode,
 | 
						|
      {
 | 
						|
        replace: TextNode,
 | 
						|
        with: (node: TextNode) => new CustomTextNode(node.__text),
 | 
						|
      },
 | 
						|
      ContextBlockNode,
 | 
						|
      HistoryBlockNode,
 | 
						|
      QueryBlockNode,
 | 
						|
      WorkflowVariableBlockNode,
 | 
						|
      VariableValueBlockNode,
 | 
						|
    ],
 | 
						|
    editorState: textToEditorState(value || ''),
 | 
						|
    onError: (error: Error) => {
 | 
						|
      throw error
 | 
						|
    },
 | 
						|
  }
 | 
						|
 | 
						|
  const handleEditorChange = (editorState: EditorState) => {
 | 
						|
    const text = editorState.read(() => {
 | 
						|
      return $getRoot().getChildren().map(p => p.getTextContent()).join('\n')
 | 
						|
    })
 | 
						|
    if (onChange)
 | 
						|
      onChange(text)
 | 
						|
  }
 | 
						|
 | 
						|
  useEffect(() => {
 | 
						|
    eventEmitter?.emit({
 | 
						|
      type: UPDATE_DATASETS_EVENT_EMITTER,
 | 
						|
      payload: contextBlock?.datasets,
 | 
						|
    } as any)
 | 
						|
  }, [eventEmitter, contextBlock?.datasets])
 | 
						|
  useEffect(() => {
 | 
						|
    eventEmitter?.emit({
 | 
						|
      type: UPDATE_HISTORY_EVENT_EMITTER,
 | 
						|
      payload: historyBlock?.history,
 | 
						|
    } as any)
 | 
						|
  }, [eventEmitter, historyBlock?.history])
 | 
						|
 | 
						|
  return (
 | 
						|
    <LexicalComposer initialConfig={{ ...initialConfig, editable }}>
 | 
						|
      <div className='relative min-h-5'>
 | 
						|
        <RichTextPlugin
 | 
						|
          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={cn('truncate', placeholderClassName)} compact={compact} />}
 | 
						|
          ErrorBoundary={LexicalErrorBoundary}
 | 
						|
        />
 | 
						|
        <ComponentPickerBlock
 | 
						|
          triggerString='/'
 | 
						|
          contextBlock={contextBlock}
 | 
						|
          historyBlock={historyBlock}
 | 
						|
          queryBlock={queryBlock}
 | 
						|
          variableBlock={variableBlock}
 | 
						|
          externalToolBlock={externalToolBlock}
 | 
						|
          workflowVariableBlock={workflowVariableBlock}
 | 
						|
          isSupportFileVar={isSupportFileVar}
 | 
						|
        />
 | 
						|
        <ComponentPickerBlock
 | 
						|
          triggerString='{'
 | 
						|
          contextBlock={contextBlock}
 | 
						|
          historyBlock={historyBlock}
 | 
						|
          queryBlock={queryBlock}
 | 
						|
          variableBlock={variableBlock}
 | 
						|
          externalToolBlock={externalToolBlock}
 | 
						|
          workflowVariableBlock={workflowVariableBlock}
 | 
						|
          isSupportFileVar={isSupportFileVar}
 | 
						|
        />
 | 
						|
        {
 | 
						|
          contextBlock?.show && (
 | 
						|
            <>
 | 
						|
              <ContextBlock {...contextBlock} />
 | 
						|
              <ContextBlockReplacementBlock {...contextBlock} />
 | 
						|
            </>
 | 
						|
          )
 | 
						|
        }
 | 
						|
        {
 | 
						|
          queryBlock?.show && (
 | 
						|
            <>
 | 
						|
              <QueryBlock {...queryBlock} />
 | 
						|
              <QueryBlockReplacementBlock />
 | 
						|
            </>
 | 
						|
          )
 | 
						|
        }
 | 
						|
        {
 | 
						|
          historyBlock?.show && (
 | 
						|
            <>
 | 
						|
              <HistoryBlock {...historyBlock} />
 | 
						|
              <HistoryBlockReplacementBlock {...historyBlock} />
 | 
						|
            </>
 | 
						|
          )
 | 
						|
        }
 | 
						|
        {
 | 
						|
          (variableBlock?.show || externalToolBlock?.show) && (
 | 
						|
            <>
 | 
						|
              <VariableBlock />
 | 
						|
              <VariableValueBlock />
 | 
						|
            </>
 | 
						|
          )
 | 
						|
        }
 | 
						|
        {
 | 
						|
          workflowVariableBlock?.show && (
 | 
						|
            <>
 | 
						|
              <WorkflowVariableBlock {...workflowVariableBlock} />
 | 
						|
              <WorkflowVariableBlockReplacementBlock {...workflowVariableBlock} />
 | 
						|
            </>
 | 
						|
          )
 | 
						|
        }
 | 
						|
        <OnChangePlugin onChange={handleEditorChange} />
 | 
						|
        <OnBlurBlock onBlur={onBlur} onFocus={onFocus} />
 | 
						|
        <UpdateBlock instanceId={instanceId} />
 | 
						|
        <HistoryPlugin />
 | 
						|
        {/* <TreeView /> */}
 | 
						|
      </div>
 | 
						|
    </LexicalComposer>
 | 
						|
  )
 | 
						|
}
 | 
						|
 | 
						|
export default PromptEditor
 |