Forráskód Böngészése

pass lang and custom_attrs from app to html root (#2697)

* pass lang and custom_attrs from app to html root

* fix some pre-commit errors and try adding lang

* fix tests

* really fix test

* cleanup with @benedikt-bartscher

* fix props and tests

* use str instead of var

* change typing of html_custom_attrs to not allow Vars
macmoritz 1 éve
szülő
commit
9e0452beb0

+ 12 - 1
reflex/app.py

@@ -133,6 +133,12 @@ class App(Base):
     # Components to add to the head of every page.
     head_components: List[Component] = []
 
+    # The language to add to the html root tag of every page.
+    html_lang: Optional[str] = None
+
+    # Attributes to add to the html root tag of every page.
+    html_custom_attrs: Optional[Dict[str, str]] = None
+
     # A component that is present on every page.
     overlay_component: Optional[
         Union[Component, ComponentCallable]
@@ -782,7 +788,12 @@ class App(Base):
             submit_work(compiler.compile_root_stylesheet, self.stylesheets)
 
             # Compile the root document.
-            submit_work(compiler.compile_document_root, self.head_components)
+            submit_work(
+                compiler.compile_document_root,
+                self.head_components,
+                html_lang=self.html_lang,
+                html_custom_attrs=self.html_custom_attrs,
+            )
 
             # Compile the theme.
             submit_work(compiler.compile_theme, style=self.style)

+ 12 - 3
reflex/compiler/compiler.py

@@ -4,7 +4,7 @@ from __future__ import annotations
 
 import os
 from pathlib import Path
-from typing import Iterable, Optional, Type
+from typing import Dict, Iterable, Optional, Type, Union
 
 from reflex import constants
 from reflex.compiler import templates, utils
@@ -19,6 +19,7 @@ from reflex.config import get_config
 from reflex.state import BaseState
 from reflex.style import LIGHT_COLOR_MODE
 from reflex.utils.imports import ImportVar
+from reflex.vars import Var
 
 
 def _compile_document_root(root: Component) -> str:
@@ -299,11 +300,17 @@ def _compile_tailwind(
     )
 
 
-def compile_document_root(head_components: list[Component]) -> tuple[str, str]:
+def compile_document_root(
+    head_components: list[Component],
+    html_lang: Optional[str] = None,
+    html_custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+) -> tuple[str, str]:
     """Compile the document root.
 
     Args:
         head_components: The components to include in the head.
+        html_lang: The language of the document, will be added to the html root element.
+        html_custom_attrs: custom attributes added to the html root element.
 
     Returns:
         The path and code of the compiled document root.
@@ -312,7 +319,9 @@ def compile_document_root(head_components: list[Component]) -> tuple[str, str]:
     output_path = utils.get_page_path(constants.PageNames.DOCUMENT_ROOT)
 
     # Create the document root.
-    document_root = utils.create_document_root(head_components)
+    document_root = utils.create_document_root(
+        head_components, html_lang=html_lang, html_custom_attrs=html_custom_attrs
+    )
 
     # Compile the document root.
     code = _compile_document_root(document_root)

+ 11 - 2
reflex/compiler/utils.py

@@ -2,7 +2,7 @@
 from __future__ import annotations
 
 import os
-from typing import Any, Callable, Type
+from typing import Any, Callable, Dict, Optional, Type, Union
 from urllib.parse import urlparse
 
 from pydantic.fields import ModelField
@@ -24,6 +24,7 @@ from reflex.components.component import Component, ComponentStyle, CustomCompone
 from reflex.state import BaseState, Cookie, LocalStorage
 from reflex.style import Style
 from reflex.utils import console, format, imports, path_ops
+from reflex.vars import Var
 
 # To re-export this function.
 merge_imports = imports.merge_imports
@@ -261,11 +262,17 @@ def compile_custom_component(
     )
 
 
-def create_document_root(head_components: list[Component] | None = None) -> Component:
+def create_document_root(
+    head_components: list[Component] | None = None,
+    html_lang: Optional[str] = None,
+    html_custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+) -> Component:
     """Create the document root.
 
     Args:
         head_components: The components to add to the head.
+        html_lang: The language of the document, will be added to the html root element.
+        html_custom_attrs: custom attributes added to the html root element.
 
     Returns:
         The document root.
@@ -277,6 +284,8 @@ def create_document_root(head_components: list[Component] | None = None) -> Comp
             Main.create(),
             NextScript.create(),
         ),
+        lang=html_lang or "en",
+        custom_attrs=html_custom_attrs or {},
     )
 
 

+ 4 - 0
reflex/components/base/document.py

@@ -1,5 +1,7 @@
 """Document components."""
 
+from typing import Optional
+
 from reflex.components.component import Component
 
 
@@ -14,6 +16,8 @@ class Html(NextDocumentLib):
 
     tag = "Html"
 
+    lang: Optional[str]
+
 
 class DocumentHead(NextDocumentLib):
     """The document head."""

+ 2 - 0
reflex/components/base/document.pyi

@@ -7,6 +7,7 @@ from typing import Any, Dict, Literal, Optional, Union, overload
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.style import Style
+from typing import Optional
 from reflex.components.component import Component
 
 class NextDocumentLib(Component):
@@ -94,6 +95,7 @@ class Html(NextDocumentLib):
     def create(  # type: ignore
         cls,
         *children,
+        lang: Optional[str] = None,
         style: Optional[Style] = None,
         key: Optional[Any] = None,
         id: Optional[Any] = None,

+ 8 - 1
tests/compiler/test_compiler.py

@@ -195,8 +195,11 @@ def test_create_document_root():
     """Test that the document root is created correctly."""
     # Test with no components.
     root = utils.create_document_root()
+    root.render()
     assert isinstance(root, utils.Html)
     assert isinstance(root.children[0], utils.DocumentHead)
+    # Default language.
+    assert root.lang == "en"  # type: ignore
     # No children in head.
     assert len(root.children[0].children) == 0
 
@@ -205,6 +208,10 @@ def test_create_document_root():
         utils.NextScript.create(src="foo.js"),
         utils.NextScript.create(src="bar.js"),
     ]
-    root = utils.create_document_root(head_components=comps)  # type: ignore
+    root = utils.create_document_root(head_components=comps, html_lang="rx", html_custom_attrs={"project": "reflex"})  # type: ignore
     # Two children in head.
+    assert isinstance(root, utils.Html)
     assert len(root.children[0].children) == 2
+    assert root.lang == "rx"  # type: ignore
+    assert isinstance(root.custom_attrs, dict)
+    assert root.custom_attrs == {"project": "reflex"}