markdown.py 3.2 KB

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