message-content.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import { useRef, useEffect, type FC } from 'react'
  2. // @ts-ignore
  3. import Linkify from 'react-linkify'
  4. import useIsMounted from '../../../shared/hooks/use-is-mounted'
  5. import { configureMathJax } from '../../mathjax/configure'
  6. import { loadMathJax } from '../../mathjax/load-mathjax'
  7. import { debugConsole } from '@/utils/debugging'
  8. const MessageContent: FC<{ content: string }> = ({ content }) => {
  9. const root = useRef<HTMLDivElement | null>(null)
  10. const mounted = useIsMounted()
  11. useEffect(() => {
  12. if (root.current) {
  13. // adds attributes to all the links generated by <Linkify/>, required due to https://github.com/tasti/react-linkify/issues/99
  14. for (const a of root.current.getElementsByTagName('a')) {
  15. a.setAttribute('target', '_blank')
  16. a.setAttribute('rel', 'noreferrer noopener')
  17. }
  18. // MathJax v2 typesetting
  19. if (window.MathJax?.Hub) {
  20. const { Hub } = window.MathJax
  21. const timeout = setTimeout(() => {
  22. configureMathJax()
  23. Hub.Queue(['Typeset', Hub, root.current])
  24. }, 0)
  25. return () => clearTimeout(timeout)
  26. }
  27. // MathJax v3 typesetting
  28. loadMathJax()
  29. .then(MathJax => {
  30. if (mounted.current) {
  31. MathJax.typesetPromise([root.current]).catch(debugConsole.error)
  32. }
  33. })
  34. .catch(debugConsole.error)
  35. }
  36. }, [content, mounted])
  37. return (
  38. <p ref={root}>
  39. <Linkify>{content}</Linkify>
  40. </p>
  41. )
  42. }
  43. export default MessageContent