context-block-replacement-block.tsx 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import {
  2. memo,
  3. useCallback,
  4. useEffect,
  5. } from 'react'
  6. import { $applyNodeReplacement } from 'lexical'
  7. import { mergeRegister } from '@lexical/utils'
  8. import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
  9. import { decoratorTransform } from '../../utils'
  10. import { CONTEXT_PLACEHOLDER_TEXT } from '../../constants'
  11. import type { ContextBlockType } from '../../types'
  12. import {
  13. $createContextBlockNode,
  14. ContextBlockNode,
  15. } from '../context-block/node'
  16. import { CustomTextNode } from '../custom-text/node'
  17. const REGEX = new RegExp(CONTEXT_PLACEHOLDER_TEXT)
  18. const ContextBlockReplacementBlock = ({
  19. datasets = [],
  20. onAddContext = () => {},
  21. onInsert,
  22. canNotAddContext,
  23. }: ContextBlockType) => {
  24. const [editor] = useLexicalComposerContext()
  25. useEffect(() => {
  26. if (!editor.hasNodes([ContextBlockNode]))
  27. throw new Error('ContextBlockNodePlugin: ContextBlockNode not registered on editor')
  28. }, [editor])
  29. const createContextBlockNode = useCallback((): ContextBlockNode => {
  30. if (onInsert)
  31. onInsert()
  32. return $applyNodeReplacement($createContextBlockNode(datasets, onAddContext, canNotAddContext))
  33. }, [datasets, onAddContext, onInsert, canNotAddContext])
  34. const getMatch = useCallback((text: string) => {
  35. const matchArr = REGEX.exec(text)
  36. if (matchArr === null)
  37. return null
  38. const startOffset = matchArr.index
  39. const endOffset = startOffset + CONTEXT_PLACEHOLDER_TEXT.length
  40. return {
  41. end: endOffset,
  42. start: startOffset,
  43. }
  44. }, [])
  45. useEffect(() => {
  46. REGEX.lastIndex = 0
  47. return mergeRegister(
  48. editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createContextBlockNode)),
  49. )
  50. }, [])
  51. return null
  52. }
  53. export default memo(ContextBlockReplacementBlock)