index.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. 'use client'
  2. import type { FC } from 'react'
  3. import { useEffect } from 'react'
  4. import type {
  5. EditorState,
  6. } from 'lexical'
  7. import {
  8. $getRoot,
  9. TextNode,
  10. } from 'lexical'
  11. import { CodeNode } from '@lexical/code'
  12. import { LexicalComposer } from '@lexical/react/LexicalComposer'
  13. import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
  14. import { ContentEditable } from '@lexical/react/LexicalContentEditable'
  15. import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'
  16. import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
  17. import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'
  18. // import TreeView from './plugins/tree-view'
  19. import Placeholder from './plugins/placeholder'
  20. import ComponentPickerBlock from './plugins/component-picker-block'
  21. import {
  22. ContextBlock,
  23. ContextBlockNode,
  24. ContextBlockReplacementBlock,
  25. } from './plugins/context-block'
  26. import {
  27. QueryBlock,
  28. QueryBlockNode,
  29. QueryBlockReplacementBlock,
  30. } from './plugins/query-block'
  31. import {
  32. HistoryBlock,
  33. HistoryBlockNode,
  34. HistoryBlockReplacementBlock,
  35. } from './plugins/history-block'
  36. import {
  37. WorkflowVariableBlock,
  38. WorkflowVariableBlockNode,
  39. WorkflowVariableBlockReplacementBlock,
  40. } from './plugins/workflow-variable-block'
  41. import VariableBlock from './plugins/variable-block'
  42. import VariableValueBlock from './plugins/variable-value-block'
  43. import { VariableValueBlockNode } from './plugins/variable-value-block/node'
  44. import { CustomTextNode } from './plugins/custom-text/node'
  45. import OnBlurBlock from './plugins/on-blur-or-focus-block'
  46. import UpdateBlock from './plugins/update-block'
  47. import { textToEditorState } from './utils'
  48. import type {
  49. ContextBlockType,
  50. ExternalToolBlockType,
  51. HistoryBlockType,
  52. QueryBlockType,
  53. VariableBlockType,
  54. WorkflowVariableBlockType,
  55. } from './types'
  56. import {
  57. UPDATE_DATASETS_EVENT_EMITTER,
  58. UPDATE_HISTORY_EVENT_EMITTER,
  59. } from './constants'
  60. import { useEventEmitterContextContext } from '@/context/event-emitter'
  61. export type PromptEditorProps = {
  62. instanceId?: string
  63. compact?: boolean
  64. className?: string
  65. placeholder?: string
  66. placeholderClassName?: string
  67. style?: React.CSSProperties
  68. value?: string
  69. editable?: boolean
  70. onChange?: (text: string) => void
  71. onBlur?: () => void
  72. onFocus?: () => void
  73. contextBlock?: ContextBlockType
  74. queryBlock?: QueryBlockType
  75. historyBlock?: HistoryBlockType
  76. variableBlock?: VariableBlockType
  77. externalToolBlock?: ExternalToolBlockType
  78. workflowVariableBlock?: WorkflowVariableBlockType
  79. }
  80. const PromptEditor: FC<PromptEditorProps> = ({
  81. instanceId,
  82. compact,
  83. className,
  84. placeholder,
  85. placeholderClassName,
  86. style,
  87. value,
  88. editable = true,
  89. onChange,
  90. onBlur,
  91. onFocus,
  92. contextBlock,
  93. queryBlock,
  94. historyBlock,
  95. variableBlock,
  96. externalToolBlock,
  97. workflowVariableBlock,
  98. }) => {
  99. const { eventEmitter } = useEventEmitterContextContext()
  100. const initialConfig = {
  101. namespace: 'prompt-editor',
  102. nodes: [
  103. CodeNode,
  104. CustomTextNode,
  105. {
  106. replace: TextNode,
  107. with: (node: TextNode) => new CustomTextNode(node.__text),
  108. },
  109. ContextBlockNode,
  110. HistoryBlockNode,
  111. QueryBlockNode,
  112. WorkflowVariableBlockNode,
  113. VariableValueBlockNode,
  114. ],
  115. editorState: textToEditorState(value || ''),
  116. onError: (error: Error) => {
  117. throw error
  118. },
  119. }
  120. const handleEditorChange = (editorState: EditorState) => {
  121. const text = editorState.read(() => $getRoot().getTextContent())
  122. if (onChange)
  123. onChange(text.replaceAll('\n\n', '\n'))
  124. }
  125. useEffect(() => {
  126. eventEmitter?.emit({
  127. type: UPDATE_DATASETS_EVENT_EMITTER,
  128. payload: contextBlock?.datasets,
  129. } as any)
  130. }, [eventEmitter, contextBlock?.datasets])
  131. useEffect(() => {
  132. eventEmitter?.emit({
  133. type: UPDATE_HISTORY_EVENT_EMITTER,
  134. payload: historyBlock?.history,
  135. } as any)
  136. }, [eventEmitter, historyBlock?.history])
  137. return (
  138. <LexicalComposer initialConfig={{ ...initialConfig, editable }}>
  139. <div className='relative'>
  140. <RichTextPlugin
  141. contentEditable={<ContentEditable className={`${className} outline-none ${compact ? 'leading-5 text-[13px]' : 'leading-6 text-sm'} text-gray-700`} style={style || {}} />}
  142. placeholder={<Placeholder value={placeholder} className={placeholderClassName} compact={compact} />}
  143. ErrorBoundary={LexicalErrorBoundary}
  144. />
  145. <ComponentPickerBlock
  146. triggerString='/'
  147. contextBlock={contextBlock}
  148. historyBlock={historyBlock}
  149. queryBlock={queryBlock}
  150. variableBlock={variableBlock}
  151. externalToolBlock={externalToolBlock}
  152. workflowVariableBlock={workflowVariableBlock}
  153. />
  154. <ComponentPickerBlock
  155. triggerString='{'
  156. contextBlock={contextBlock}
  157. historyBlock={historyBlock}
  158. queryBlock={queryBlock}
  159. variableBlock={variableBlock}
  160. externalToolBlock={externalToolBlock}
  161. workflowVariableBlock={workflowVariableBlock}
  162. />
  163. {
  164. contextBlock?.show && (
  165. <>
  166. <ContextBlock {...contextBlock} />
  167. <ContextBlockReplacementBlock {...contextBlock} />
  168. </>
  169. )
  170. }
  171. {
  172. queryBlock?.show && (
  173. <>
  174. <QueryBlock {...queryBlock} />
  175. <QueryBlockReplacementBlock />
  176. </>
  177. )
  178. }
  179. {
  180. historyBlock?.show && (
  181. <>
  182. <HistoryBlock {...historyBlock} />
  183. <HistoryBlockReplacementBlock {...historyBlock} />
  184. </>
  185. )
  186. }
  187. {
  188. (variableBlock?.show || externalToolBlock?.show) && (
  189. <>
  190. <VariableBlock />
  191. <VariableValueBlock />
  192. </>
  193. )
  194. }
  195. {
  196. workflowVariableBlock?.show && (
  197. <>
  198. <WorkflowVariableBlock {...workflowVariableBlock} />
  199. <WorkflowVariableBlockReplacementBlock {...workflowVariableBlock} />
  200. </>
  201. )
  202. }
  203. <OnChangePlugin onChange={handleEditorChange} />
  204. <OnBlurBlock onBlur={onBlur} onFocus={onFocus} />
  205. <UpdateBlock instanceId={instanceId} />
  206. <HistoryPlugin />
  207. {/* <TreeView /> */}
  208. </div>
  209. </LexicalComposer>
  210. )
  211. }
  212. export default PromptEditor