message-content.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  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. const MessageContent: FC<{ content: string }> = ({ content }) => {
  8. const root = useRef<HTMLDivElement | null>(null)
  9. const mounted = useIsMounted()
  10. useEffect(() => {
  11. if (root.current) {
  12. // adds attributes to all the links generated by <Linkify/>, required due to https://github.com/tasti/react-linkify/issues/99
  13. for (const a of root.current.getElementsByTagName('a')) {
  14. a.setAttribute('target', '_blank')
  15. a.setAttribute('rel', 'noreferrer noopener')
  16. }
  17. // MathJax v2 typesetting
  18. if (window.MathJax?.Hub) {
  19. const { Hub } = window.MathJax
  20. const timeout = setTimeout(() => {
  21. configureMathJax()
  22. Hub.Queue(['Typeset', Hub, root.current])
  23. }, 0)
  24. return () => clearTimeout(timeout)
  25. }
  26. // MathJax v3 typesetting
  27. loadMathJax()
  28. .then(MathJax => {
  29. if (mounted.current) {
  30. MathJax.typesetPromise([root.current]).catch((error: Error) => {
  31. console.error(error)
  32. })
  33. }
  34. })
  35. .catch(error => {
  36. console.error(error)
  37. })
  38. }
  39. }, [content, mounted])
  40. return (
  41. <p ref={root}>
  42. <Linkify>{content}</Linkify>
  43. </p>
  44. )
  45. }
  46. export default MessageContent