You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

context-block-replacement-block.tsx 1.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  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. import { noop } from 'lodash-es'
  18. const REGEX = new RegExp(CONTEXT_PLACEHOLDER_TEXT)
  19. const ContextBlockReplacementBlock = ({
  20. datasets = [],
  21. onAddContext = noop,
  22. onInsert,
  23. canNotAddContext,
  24. }: ContextBlockType) => {
  25. const [editor] = useLexicalComposerContext()
  26. useEffect(() => {
  27. if (!editor.hasNodes([ContextBlockNode]))
  28. throw new Error('ContextBlockNodePlugin: ContextBlockNode not registered on editor')
  29. }, [editor])
  30. const createContextBlockNode = useCallback((): ContextBlockNode => {
  31. if (onInsert)
  32. onInsert()
  33. return $applyNodeReplacement($createContextBlockNode(datasets, onAddContext, canNotAddContext))
  34. }, [datasets, onAddContext, onInsert, canNotAddContext])
  35. const getMatch = useCallback((text: string) => {
  36. const matchArr = REGEX.exec(text)
  37. if (matchArr === null)
  38. return null
  39. const startOffset = matchArr.index
  40. const endOffset = startOffset + CONTEXT_PLACEHOLDER_TEXT.length
  41. return {
  42. end: endOffset,
  43. start: startOffset,
  44. }
  45. }, [])
  46. useEffect(() => {
  47. REGEX.lastIndex = 0
  48. return mergeRegister(
  49. editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createContextBlockNode)),
  50. )
  51. }, [])
  52. return null
  53. }
  54. export default memo(ContextBlockReplacementBlock)