link.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. """Components for rendering heading.
  2. https://www.radix-ui.com/themes/docs/theme/typography
  3. """
  4. from __future__ import annotations
  5. from typing import Literal
  6. from reflex.components.component import Component, MemoizationLeaf
  7. from reflex.components.core.breakpoints import Responsive
  8. from reflex.components.core.colors import color
  9. from reflex.components.core.cond import cond
  10. from reflex.components.el.elements.inline import A
  11. from reflex.components.markdown.markdown import MarkdownComponentMap
  12. from reflex.utils.imports import ImportDict, ImportVar
  13. from reflex.vars.base import Var
  14. from ..base import LiteralAccentColor, RadixThemesComponent
  15. from .base import LiteralTextSize, LiteralTextTrim, LiteralTextWeight
  16. LiteralLinkUnderline = Literal["auto", "hover", "always", "none"]
  17. LiteralLinkDiscover = Literal["none", "render"]
  18. class ReactRouterLink(A):
  19. """Links are accessible elements used primarily for navigation. This component is styled to resemble a hyperlink and semantically renders an <a>."""
  20. library = "react-router"
  21. tag = "Link"
  22. alias = "ReactRouterLink"
  23. # The page to link to.
  24. to: Var[str]
  25. # Replaces the current entry in the history stack instead of pushing a new one onto it.
  26. replace: Var[bool]
  27. # Will use document navigation instead of client side routing when the link is clicked: the browser will handle the transition normally (as if it were an <a href>).
  28. reload_document: Var[bool]
  29. # Prevents the scroll position from being reset to the top of the window when the link is clicked and the app is using ScrollRestoration. This only prevents new locations resetting scroll to the top, scroll position will be restored for back/forward button navigation.
  30. prevent_scroll_reset: Var[bool]
  31. # Defines the link discovery behavior
  32. discover: Var[LiteralLinkDiscover]
  33. # Enables a View Transition for this navigation.
  34. view_transition: Var[bool]
  35. class Link(RadixThemesComponent, A, MemoizationLeaf, MarkdownComponentMap):
  36. """A semantic element for navigation between pages."""
  37. tag = "Link"
  38. # Change the default rendered element for the one passed as a child, merging their props and behavior.
  39. as_child: Var[bool]
  40. # Text size: "1" - "9"
  41. size: Var[Responsive[LiteralTextSize]]
  42. # Thickness of text: "light" | "regular" | "medium" | "bold"
  43. weight: Var[Responsive[LiteralTextWeight]]
  44. # Removes the leading trim space: "normal" | "start" | "end" | "both"
  45. trim: Var[Responsive[LiteralTextTrim]]
  46. # Sets the visibility of the underline affordance: "auto" | "hover" | "always" | "none"
  47. underline: Var[LiteralLinkUnderline]
  48. # Overrides the accent color inherited from the Theme.
  49. color_scheme: Var[LiteralAccentColor]
  50. # Whether to render the text with higher contrast color
  51. high_contrast: Var[bool]
  52. # If True, the link will open in a new tab
  53. is_external: Var[bool]
  54. def add_imports(self) -> ImportDict:
  55. """Add imports for the Link component.
  56. Returns:
  57. The import dict.
  58. """
  59. return {
  60. "react-router": [ImportVar(tag="Link", alias="ReactRouterLink")],
  61. }
  62. @classmethod
  63. def create(cls, *children, **props) -> Component:
  64. """Create a Link component.
  65. Args:
  66. *children: The children of the component.
  67. **props: The props of the component.
  68. Raises:
  69. ValueError: in case of missing children
  70. Returns:
  71. Component: The link component
  72. """
  73. props.setdefault("_hover", {"color": color("accent", 8)})
  74. href = props.get("href")
  75. is_external = props.pop("is_external", None)
  76. if is_external is not None:
  77. props["target"] = cond(is_external, "_blank", "")
  78. if href is not None:
  79. if not len(children):
  80. raise ValueError("Link without a child will not display")
  81. if "as_child" not in props:
  82. # Extract props for the ReactRouterLink, the rest go to the Link/A element.
  83. known_react_router_link_props = ReactRouterLink.get_props()
  84. next_link_props = {}
  85. for prop in props.copy():
  86. if prop in known_react_router_link_props:
  87. next_link_props[prop] = props.pop(prop)
  88. next_link_props["to"] = next_link_props.pop("href", href)
  89. # If user does not use `as_child`, by default we render using react_router_link to avoid page refresh during internal navigation
  90. return super().create(
  91. ReactRouterLink.create(*children, **next_link_props),
  92. as_child=True,
  93. **props,
  94. )
  95. else:
  96. props["href"] = "#"
  97. return super().create(*children, **props)
  98. link = Link.create