index.tsx 6.2 KB

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