query-block-replacement-block.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  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 { QUERY_PLACEHOLDER_TEXT } from '../../constants'
  11. import type { QueryBlockType } from '../../types'
  12. import {
  13. $createQueryBlockNode,
  14. QueryBlockNode,
  15. } from '../query-block/node'
  16. import { CustomTextNode } from '../custom-text/node'
  17. const REGEX = new RegExp(QUERY_PLACEHOLDER_TEXT)
  18. const QueryBlockReplacementBlock = ({
  19. onInsert,
  20. }: QueryBlockType) => {
  21. const [editor] = useLexicalComposerContext()
  22. useEffect(() => {
  23. if (!editor.hasNodes([QueryBlockNode]))
  24. throw new Error('QueryBlockNodePlugin: QueryBlockNode not registered on editor')
  25. }, [editor])
  26. const createQueryBlockNode = useCallback((): QueryBlockNode => {
  27. if (onInsert)
  28. onInsert()
  29. return $applyNodeReplacement($createQueryBlockNode())
  30. }, [onInsert])
  31. const getMatch = useCallback((text: string) => {
  32. const matchArr = REGEX.exec(text)
  33. if (matchArr === null)
  34. return null
  35. const startOffset = matchArr.index
  36. const endOffset = startOffset + QUERY_PLACEHOLDER_TEXT.length
  37. return {
  38. end: endOffset,
  39. start: startOffset,
  40. }
  41. }, [])
  42. useEffect(() => {
  43. REGEX.lastIndex = 0
  44. return mergeRegister(
  45. editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createQueryBlockNode)),
  46. )
  47. }, [])
  48. return null
  49. }
  50. export default memo(QueryBlockReplacementBlock)