markdown.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """Markdown component."""
  2. import textwrap
  3. from typing import List, Union
  4. from pynecone.components.component import Component
  5. from pynecone.utils import types
  6. from pynecone.var import BaseVar, Var
  7. class Markdown(Component):
  8. """A markdown component."""
  9. library = "react-markdown"
  10. tag = "ReactMarkdown"
  11. @classmethod
  12. def create(cls, *children, **props) -> Component:
  13. """Create a markdown component.
  14. Args:
  15. children: The children of the component.
  16. props: The properties of the component.
  17. Returns:
  18. The markdown component.
  19. """
  20. assert len(children) == 1 and types._isinstance(
  21. children[0], Union[str, Var]
  22. ), "Markdown component must have exactly one child containing the markdown source."
  23. # Get the markdown source.
  24. src = children[0]
  25. if isinstance(src, str):
  26. src = textwrap.dedent(src)
  27. return super().create(src, **props)
  28. def _get_imports(self):
  29. imports = super()._get_imports()
  30. imports["@chakra-ui/react"] = {
  31. "Heading",
  32. "Code",
  33. "Text",
  34. "Link",
  35. "UnorderedList",
  36. "OrderedList",
  37. "ListItem",
  38. }
  39. imports["react-syntax-highlighter"] = {"Prism"}
  40. imports["remark-math"] = {"remarkMath"}
  41. imports["remark-gfm"] = {"remarkGfm"}
  42. imports["rehype-katex"] = {"rehypeKatex"}
  43. imports["rehype-raw"] = {"rehypeRaw"}
  44. imports[""] = {"katex/dist/katex.min.css"}
  45. return imports
  46. def _render(self):
  47. return (
  48. super()
  49. ._render()
  50. .add_props(
  51. components={
  52. "h1": "{({node, ...props}) => <Heading size='2xl' {...props} />}",
  53. "h2": "{({node, ...props}) => <Heading size='xl' {...props} />}",
  54. "h3": "{({node, ...props}) => <Heading size='lg' {...props} />}",
  55. "ul": "{UnorderedList}",
  56. "ol": "{OrderedList}",
  57. "li": "{ListItem}",
  58. "p": "{Text}",
  59. "a": "{Link}",
  60. "code": """{({node, inline, className, children, ...props}) =>
  61. {
  62. const match = (className || '').match(/language-(?<lang>.*)/);
  63. return !inline ? (
  64. <Prism
  65. children={String(children).replace(/\n$/, '')}
  66. language={match ? match[1] : ''}
  67. {...props}
  68. />
  69. ) : (
  70. <Code {...props}>
  71. {children}
  72. </Code>
  73. );
  74. }}""".replace(
  75. "\n", " "
  76. ),
  77. },
  78. remark_plugins=BaseVar(name="[remarkMath, remarkGfm]", type_=List[str]),
  79. rehype_plugins=BaseVar(
  80. name="[rehypeKatex, rehypeRaw]", type_=List[str]
  81. ),
  82. )
  83. )