query-block-replacement-block.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import type { FC } from 'react'
  2. import {
  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 {
  12. $createQueryBlockNode,
  13. QueryBlockNode,
  14. } from './query-block/node'
  15. import type { QueryBlockProps } from './query-block/index'
  16. import { CustomTextNode } from './custom-text/node'
  17. const REGEX = new RegExp(QUERY_PLACEHOLDER_TEXT)
  18. const QueryBlockReplacementBlock: FC<QueryBlockProps> = ({
  19. onInsert,
  20. }) => {
  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. return mergeRegister(
  44. editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createQueryBlockNode)),
  45. )
  46. }, [])
  47. return null
  48. }
  49. export default QueryBlockReplacementBlock