Ver Fonte

don't use jsx syntax (#5127)

* don't use jsx syntax

* fix most of the tests

* use v1 for that field

* jsx

* make it compile

* why do we have those???

* huh?

* make the .js files real js files

* _apply_common_imports

* no more fragment import there

* make _is_tag_in_global_scope just a classvar

* simplify render method for bare

* maybe?

* what did i do

* dynamic was the weird guy

* i was being silly
Khaleel Al-Adhami há 1 semana atrás
pai
commit
d65cf697a3
40 ficheiros alterados com 260 adições e 295 exclusões
  1. 7 7
      pyi_hashes.json
  2. 10 10
      reflex/.templates/jinja/web/pages/_app.js.jinja2
  3. 1 1
      reflex/.templates/jinja/web/pages/_document.js.jinja2
  4. 1 1
      reflex/.templates/jinja/web/pages/index.js.jinja2
  5. 1 1
      reflex/.templates/jinja/web/pages/stateful_component.js.jinja2
  6. 35 72
      reflex/.templates/jinja/web/pages/utils.js.jinja2
  7. 6 18
      reflex/.templates/jinja/web/utils/context.js.jinja2
  8. 7 7
      reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js
  9. 5 4
      reflex/.templates/web/components/shiki/code.js
  10. 20 3
      reflex/compiler/compiler.py
  11. 8 5
      reflex/components/base/bare.py
  12. 2 4
      reflex/components/base/body.py
  13. 3 3
      reflex/components/base/link.py
  14. 5 9
      reflex/components/base/meta.py
  15. 13 27
      reflex/components/component.py
  16. 2 2
      reflex/components/core/upload.py
  17. 5 2
      reflex/components/dynamic.py
  18. 4 0
      reflex/components/el/element.py
  19. 1 1
      reflex/components/el/elements/metadata.py
  20. 6 7
      reflex/components/markdown/markdown.py
  21. 1 1
      reflex/components/plotly/plotly.py
  22. 3 2
      reflex/components/radix/themes/layout/list.py
  23. 10 3
      reflex/utils/format.py
  24. 1 0
      reflex/utils/pyi_generator.py
  25. 4 4
      tests/units/components/base/test_bare.py
  26. 4 6
      tests/units/components/base/test_link.py
  27. 5 5
      tests/units/components/base/test_script.py
  28. 2 2
      tests/units/components/core/test_cond.py
  29. 1 1
      tests/units/components/core/test_foreach.py
  30. 5 3
      tests/units/components/core/test_html.py
  31. 10 9
      tests/units/components/core/test_match.py
  32. 2 2
      tests/units/components/datadisplay/test_dataeditor.py
  33. 2 2
      tests/units/components/datadisplay/test_datatable.py
  34. 12 12
      tests/units/components/el/test_svg.py
  35. 1 1
      tests/units/components/forms/test_form.py
  36. 0 0
      tests/units/components/markdown/test_markdown.py
  37. 20 20
      tests/units/components/test_component.py
  38. 4 4
      tests/units/components/test_tag.py
  39. 28 31
      tests/units/test_app.py
  40. 3 3
      tests/units/utils/test_format.py

+ 7 - 7
pyi_hashes.json

@@ -3,13 +3,13 @@
   "reflex/components/__init__.pyi": "76ba0a12cd3a7ba5ab6341a3ae81551f",
   "reflex/components/base/__init__.pyi": "e9aaf47be1e1977eacee97b880c8f7de",
   "reflex/components/base/app_wrap.pyi": "387fc7a0c2da8760d9449e2893e44eec",
-  "reflex/components/base/body.pyi": "2cc870cec4b1c28081dd40467752c2b7",
+  "reflex/components/base/body.pyi": "2d16002f24c8ee0007b46ff2bf1f2c78",
   "reflex/components/base/document.pyi": "30377cdfb02b564f8de29b0473d2346c",
   "reflex/components/base/error_boundary.pyi": "c56b591d14a92b99a1e97e04afe167d7",
   "reflex/components/base/fragment.pyi": "603ee8e03af88d4a8ff6bc1fbce4e022",
   "reflex/components/base/head.pyi": "893047aa32da553711db8f1345adb6b0",
-  "reflex/components/base/link.pyi": "396488afa3b7a5b0d0e6c5e89159f857",
-  "reflex/components/base/meta.pyi": "bc4b4fda6f022a517de339ffdd667e3b",
+  "reflex/components/base/link.pyi": "e96179dc7823f354fb73a6c03e31028c",
+  "reflex/components/base/meta.pyi": "da52c3212fac6b50560863146a7afcc3",
   "reflex/components/base/script.pyi": "530cf8f47eb90082bf65942e8b5d745f",
   "reflex/components/base/strict_mode.pyi": "d972e0ff2a6f961e7df90fc27b8bb51b",
   "reflex/components/core/__init__.pyi": "44bcee7bc4e27e2f4f4707b843acf291",
@@ -26,13 +26,13 @@
   "reflex/components/datadisplay/dataeditor.pyi": "cb03d732e2fe771a8d46c7bcda671f92",
   "reflex/components/datadisplay/shiki_code_block.pyi": "87db7639bfa5cd53e1709e1363f93278",
   "reflex/components/el/__init__.pyi": "09042a2db5e0637e99b5173430600522",
-  "reflex/components/el/element.pyi": "06ac2213b062119323291fa66a1ac19e",
+  "reflex/components/el/element.pyi": "ea6b33a8545c2c845dc6c30ff1c872a4",
   "reflex/components/el/elements/__init__.pyi": "280ed457675f3720e34b560a3f617739",
   "reflex/components/el/elements/base.pyi": "6e533348b5e1a88cf62fbb5a38dbd795",
   "reflex/components/el/elements/forms.pyi": "3ff8fd5d8a36418874e9fe4ff76bbfe8",
   "reflex/components/el/elements/inline.pyi": "f881d229c9ecaa61d17ac6837ac9a839",
   "reflex/components/el/elements/media.pyi": "addd6872281d65d44a484358b895432f",
-  "reflex/components/el/elements/metadata.pyi": "974a86d9f0662f6fc15a5bb4b3a87862",
+  "reflex/components/el/elements/metadata.pyi": "a5b9b30c4649e88aa26a1a5609fc86ef",
   "reflex/components/el/elements/other.pyi": "995a4fbf10bfdb7f48808210dfe413bd",
   "reflex/components/el/elements/scripts.pyi": "cd5bd53c3a6b016fbb913aff36d63344",
   "reflex/components/el/elements/sectioning.pyi": "65aa53b1372598ec1785616cb7016032",
@@ -40,7 +40,7 @@
   "reflex/components/el/elements/typography.pyi": "928ff998c9bbb32ae7ccce5f6cb885a7",
   "reflex/components/gridjs/datatable.pyi": "3db3f994640c19be5c3fa2983f71de56",
   "reflex/components/lucide/icon.pyi": "a5521a8baf8d2d7281e3fdfe6ce7073b",
-  "reflex/components/markdown/markdown.pyi": "6b268afa879e33abf651bda56be5065e",
+  "reflex/components/markdown/markdown.pyi": "1fc31d2652d3ff015c6da2c7cbab716a",
   "reflex/components/moment/moment.pyi": "6dd0c7cee5f0f29bc11d830c697d7f92",
   "reflex/components/next/base.pyi": "14aafd5b018a4bc9748a3c9980fcfe3e",
   "reflex/components/next/image.pyi": "3a0d1970e69144e9c6806e68ab99f181",
@@ -101,7 +101,7 @@
   "reflex/components/radix/themes/layout/container.pyi": "4020c3dca660027b84d11cc4198393c4",
   "reflex/components/radix/themes/layout/flex.pyi": "f814281a5635ad43dd1df23f8e356c66",
   "reflex/components/radix/themes/layout/grid.pyi": "6062188367a2c253f014f916197c963d",
-  "reflex/components/radix/themes/layout/list.pyi": "0e91d3f1c82c9094f328e5b8ecd2f60a",
+  "reflex/components/radix/themes/layout/list.pyi": "930009f82662686841e9ce97bfd4a1ea",
   "reflex/components/radix/themes/layout/section.pyi": "41895910072e023ed0fef6a8ad956046",
   "reflex/components/radix/themes/layout/spacer.pyi": "029eb0eaa731bcdff7c496e0437e22b1",
   "reflex/components/radix/themes/layout/stack.pyi": "3b0da99b00c826d087ed89fc67c595c1",

+ 10 - 10
reflex/.templates/jinja/web/pages/_app.js.jinja2

@@ -22,7 +22,7 @@ function AppWrap({children}) {
   {{ renderHooks(hooks) }}
 
   return (
-    {{utils.render(render, indent_width=0)}}
+    {{utils.render(render)}}
   )
 }
 
@@ -37,15 +37,15 @@ export default function MyApp({ Component, pageProps }) {
     window["__reflex"] = windowImports;
   }, []);
   return (
-    <ThemeProvider defaultTheme={ defaultColorMode } attribute="class">
-      <StateProvider>
-        <EventLoopProvider>
-            <AppWrap>
-              <Component {...pageProps} />
-            </AppWrap>
-        </EventLoopProvider>
-      </StateProvider>
-    </ThemeProvider>
+    jsx(ThemeProvider, {defaultTheme:defaultColorMode,attribute:"class"},
+      jsx(StateProvider, {},
+        jsx(EventLoopProvider, {}, 
+          jsx(AppWrap, {},
+            jsx(Component, pageProps)
+          )
+        )
+      )
+    )
   );
 }
 

+ 1 - 1
reflex/.templates/jinja/web/pages/_document.js.jinja2

@@ -3,7 +3,7 @@
 {% block export %}
 export default function Document() {
   return (
-    {{utils.render(document, indent_width=0)}}
+    {{utils.render(document)}}
   )
 }
 {% endblock %}

+ 1 - 1
reflex/.templates/jinja/web/pages/index.js.jinja2

@@ -12,7 +12,7 @@ export default function Component() {
     {{ renderHooks(hooks)}}
 
   return (
-    {{utils.render(render, indent_width=0)}}
+    {{utils.render(render)}}
   )
 }
 {% endblock %}

+ 1 - 1
reflex/.templates/jinja/web/pages/stateful_component.js.jinja2

@@ -6,6 +6,6 @@ export function {{tag_name}} () {
   {{ renderHooksWithMemo(all_hooks, memo_trigger_hooks) }}
   
   return (
-    {{utils.render(component.render(), indent_width=0)}}
+    {{utils.render(component.render())}}
   )
 }

+ 35 - 72
reflex/.templates/jinja/web/pages/utils.js.jinja2

@@ -1,46 +1,37 @@
 {# Rendering components recursively. #}
 {# Args: #}
 {#     component: component dictionary #}
-{#     indent_width: indent width #}
-{% macro render(component, indent_width=0) %}
-{% filter indent(width=indent_width) %}
-  {%- if component is not mapping %}
-    {{- component }}
-  {%- elif "iterable" in component %}
-    {{- render_iterable_tag(component) }}
-  {%- elif component.name == "match"%}
-    {{- render_match_tag(component) }}
-  {%- elif "cond" in component %}
-    {{- render_condition_tag(component) }}
-  {%- elif component.children|length %}
-    {{- render_tag(component) }}
-  {%- else %}
-    {{- render_self_close_tag(component) }}
-  {%- endif %}
-{% endfilter %}
+{% macro render(component) %}
+{%- if component is not mapping %}{{ component }}
+{%- elif "iterable" in component %}{{ render_iterable_tag(component) }}
+{%- elif component.name == "match"%}{{ render_match_tag(component) }}
+{%- elif "cond" in component %}{{ render_condition_tag(component) }}
+{%- elif component.children|length %}{{ render_tag(component) }}
+{%- else %}{{ render_self_close_tag(component) }}
+{%- endif %}
 {% endmacro %}
 
 {# Rendering self close tag. #}
 {# Args: #}
 {#     component: component dictionary #}
 {% macro render_self_close_tag(component) %}
-{%- if component.name|length %}
-<{{ component.name }} {{- render_props(component.props) }}{% if component.autofocus %} ref={focusRef} {% endif %}/>
-{%- else %}
-  {{- component.contents }}
-{%- endif %}
+{% if component.name|length %}
+jsx({{ component.name }},{{ render_props(component.props) }},{{ component.contents }})
+{% elif component.contents|length -%}{{ component.contents }}
+{% else %}""
+{% endif %}
 {% endmacro %}
 
 {# Rendering close tag with args and props. #}
 {# Args: #}
 {#     component: component dictionary #}
 {% macro render_tag(component) %}
-<{{component.name}} {{- render_props(component.props) }}>
-{{ component.contents }}
-{% for child in component.children %}
-{{ render(child) }}
-{% endfor %}
-</{{component.name}}>
+jsx(
+{% if component.name|length %}{{ component.name }}{% else %}Fragment{% endif %},
+{{ render_props(component.props) }},
+{% if component.contents|length %}{{ component.contents }},{% endif %}
+{% for child in component.children %}{% if child is mapping or child|length %}{{ render(child) }},{% endif %}{% endfor %}
+)
 {%- endmacro %}
 
 
@@ -48,11 +39,7 @@
 {# Args: #}
 {#     component: component dictionary #}
 {% macro render_condition_tag(component) %}
-{ {{- component.cond_state }} ? (
-  {{ render(component.true_value) }}
-) : (
-  {{ render(component.false_value) }}
-)}
+({{ component.cond_state }} ? ({{ render(component.true_value) }}) : ({{ render(component.false_value) }}))
 {%- endmacro %}
 
 
@@ -60,57 +47,33 @@
 {# Args: #}
 {#     component: component dictionary #}
 {% macro render_iterable_tag(component) %}
-<>{ {{ component.iterable_state }}.map(({{ component.arg_name }}, {{ component.arg_index }}) => (
-  {% for child in component.children %}
-  {{ render(child) }}
-  {% endfor %}
-))}</>
+{{ component.iterable_state }}.map(({{ component.arg_name }},{{ component.arg_index }})=>({% for child in component.children %}{{ render(child) }}{% endfor %}))
 {%- endmacro %}
 
 
 {# Rendering props of a component. #}
 {# Args: #}
 {#     component: component dictionary #}
-{% macro render_props(props) %}
-{% if props|length %} {{ props|join(" ") }}{% endif %}
-{% endmacro %}
+{% macro render_props(props) %}{{ "{" }}{% if props|length %}{{ props|join(",") }}{% endif %}{{ "}" }}{% endmacro %}
 
 {# Rendering Match component. #}
 {# Args: #}
 {#     component: component dictionary #}
 {% macro render_match_tag(component) %}
-{
-    (() => {
-        switch (JSON.stringify({{ component.cond._js_expr }})) {
-        {% for case in component.match_cases %}
-            {% for condition in case[:-1] %}
-                case JSON.stringify({{ condition._js_expr }}):
-            {% endfor %}
-                return {{ render(case[-1]) }};
-                break;
-        {% endfor %}
-            default:
-                return {{ render(component.default) }};
-                break;
-        }
-    })()
-  }
-{%- endmacro %}
-
-
-{# Rendering content with args. #}
-{# Args: #}
-{#     component: component dictionary #}
-{% macro render_arg_content(component) %}
-{% filter indent(width=2) %}
-{# no string below for a line break #}
-
-{({ {{component.args|join(", ")}} }) => (
-  {% for child in component.children %}
-  {{ render(child) }}
+(() => {
+  switch (JSON.stringify({{ component.cond._js_expr }})) {
+  {% for case in component.match_cases %}
+    {% for condition in case[:-1] %}
+      case JSON.stringify({{ condition._js_expr }}):
+    {% endfor %}
+      return {{ render(case[-1]) }};
+      break;
   {% endfor %}
-)}
-{% endfilter %}
+    default:
+      return {{ render(component.default) }};
+      break;
+  }
+})()
 {% endmacro %}
 
 

+ 6 - 18
reflex/.templates/jinja/web/utils/context.js.jinja2

@@ -1,4 +1,4 @@
-import { createContext, useContext, useMemo, useReducer, useState } from "react"
+import { createContext, useContext, useMemo, useReducer, useState, createElement } from "react"
 import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "$/utils/state.js"
 
 {% if initial_state %}
@@ -77,11 +77,7 @@ export function UploadFilesProvider({ children }) {
     delete newFilesById[id]
     return newFilesById
   })
-  return (
-    <UploadFilesContext value={[filesById, setFilesById]}>
-      {children}
-    </UploadFilesContext>
-  )
+  return createElement(UploadFilesContext, {value:[filesById, setFilesById]}, children);
 }
 
 export function EventLoopProvider({ children }) {
@@ -91,11 +87,7 @@ export function EventLoopProvider({ children }) {
     initialEvents,
     clientStorage,
   )
-  return (
-    <EventLoopContext value={[addEvents, connectErrors]}>
-      {children}
-    </EventLoopContext>
-  )
+  return createElement(EventLoopContext, {value:[addEvents, connectErrors]}, children);
 }
 
 export function StateProvider({ children }) {
@@ -112,13 +104,9 @@ export function StateProvider({ children }) {
 
   return (
     {% for state_name in initial_state %}
-    <StateContexts.{{state_name|var_name}} value={ {{state_name|var_name}} }>
-    {% endfor %}
-      <DispatchContext value={dispatchers}>
-        {children}
-      </DispatchContext>
-    {% for state_name in initial_state|reverse %}
-    </StateContexts.{{state_name|var_name}}>
+    createElement(StateContexts.{{state_name|var_name}},{value: {{state_name|var_name}}},
     {% endfor %}
+    createElement(DispatchContext.Provider, {value: dispatchers}, children),
+    {% for state_name in initial_state|reverse %}){% endfor %}
   )
 }

+ 7 - 7
reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js

@@ -1,5 +1,5 @@
 import { useTheme } from "next-themes";
-import { useRef, useEffect, useState } from "react";
+import { useRef, useEffect, useState, createElement } from "react";
 import {
   ColorModeContext,
   defaultColorMode,
@@ -50,11 +50,11 @@ export default function RadixThemesColorModeProvider({ children }) {
     }
     setTheme(mode);
   };
-  return (
-    <ColorModeContext
-      value={{ rawColorMode, resolvedColorMode, toggleColorMode, setColorMode }}
-    >
-      {children}
-    </ColorModeContext>
+  return createElement(
+    ColorModeContext,
+    {
+      value: { rawColorMode, resolvedColorMode, toggleColorMode, setColorMode },
+    },
+    children,
   );
 }

+ 5 - 4
reflex/.templates/web/components/shiki/code.js

@@ -1,4 +1,4 @@
-import { useEffect, useState } from "react";
+import { useEffect, useState, createElement } from "react";
 import { codeToHtml } from "shiki";
 
 /**
@@ -33,7 +33,8 @@ export function Code({
     }
     fetchCode();
   }, [code, language, theme, transformers, decorations]);
-  return (
-    <div dangerouslySetInnerHTML={{ __html: codeResult }} {...divProps}></div>
-  );
+  return createElement("div", {
+    dangerouslySetInnerHTML: { __html: codeResult },
+    ...divProps,
+  });
 }

+ 20 - 3
reflex/compiler/compiler.py

@@ -30,6 +30,13 @@ from reflex.utils.prerequisites import get_web_dir
 from reflex.vars.base import LiteralVar, Var
 
 
+def _apply_common_imports(
+    imports: dict[str, list[ImportVar]],
+):
+    imports.setdefault("@emotion/react", []).append(ImportVar("jsx"))
+    imports.setdefault("react", []).append(ImportVar("Fragment"))
+
+
 def _compile_document_root(root: Component) -> str:
     """Compile the document root.
 
@@ -39,8 +46,10 @@ def _compile_document_root(root: Component) -> str:
     Returns:
         The compiled document root.
     """
+    document_root_imports = root._get_all_imports()
+    _apply_common_imports(document_root_imports)
     return templates.DOCUMENT_ROOT.render(
-        imports=utils.compile_imports(root._get_all_imports()),
+        imports=utils.compile_imports(document_root_imports),
         document=root.render(),
     )
 
@@ -74,8 +83,11 @@ def _compile_app(app_root: Component) -> str:
         (_normalize_library_name(name), name) for name in bundled_libraries
     ]
 
+    app_root_imports = app_root._get_all_imports()
+    _apply_common_imports(app_root_imports)
+
     return templates.APP_ROOT.render(
-        imports=utils.compile_imports(app_root._get_all_imports()),
+        imports=utils.compile_imports(app_root_imports),
         custom_codes=app_root._get_all_custom_code(),
         hooks=app_root._get_all_hooks(),
         window_libraries=window_libraries,
@@ -143,6 +155,7 @@ def _compile_page(
         The compiled component.
     """
     imports = component._get_all_imports()
+    _apply_common_imports(imports)
     imports = utils.compile_imports(imports)
 
     # Compile the code to render the component.
@@ -325,7 +338,7 @@ def _compile_components(
     """
     imports = {
         "react": [ImportVar(tag="memo")],
-        f"$/{constants.Dirs.STATE_PATH}": [ImportVar(tag="E"), ImportVar(tag="isTrue")],
+        f"$/{constants.Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
     }
     component_renders = []
 
@@ -335,6 +348,8 @@ def _compile_components(
         component_renders.append(component_render)
         imports = utils.merge_imports(imports, component_imports)
 
+    _apply_common_imports(imports)
+
     dynamic_imports = {
         comp_import: None
         for comp_render in component_renders
@@ -427,6 +442,8 @@ def _compile_stateful_components(
     all_imports.pop(
         f"$/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None
     )
+    if rendered_components:
+        _apply_common_imports(all_imports)
 
     return templates.STATEFUL_COMPONENTS.render(
         imports=utils.compile_imports(all_imports),

+ 8 - 5
reflex/components/base/bare.py

@@ -169,11 +169,14 @@ class Bare(Component):
         return refs
 
     def _render(self) -> Tag:
-        if isinstance(self.contents, Var):
-            if isinstance(self.contents, (BooleanVar, ObjectVar)):
-                return Tagless(contents=f"{{{self.contents.to_string()!s}}}")
-            return Tagless(contents=f"{{{self.contents!s}}}")
-        return Tagless(contents=str(self.contents))
+        contents = (
+            Var.create(self.contents)
+            if not isinstance(self.contents, Var)
+            else self.contents
+        )
+        if isinstance(contents, (BooleanVar, ObjectVar)):
+            return Tagless(contents=f"{contents.to_string()!s}")
+        return Tagless(contents=f"{contents!s}")
 
     def _add_style_recursive(
         self, style: ComponentStyle, theme: Component | None = None

+ 2 - 4
reflex/components/base/body.py

@@ -1,9 +1,7 @@
 """Display the page body."""
 
-from reflex.components.component import Component
+from reflex.components.el import elements
 
 
-class Body(Component):
+class Body(elements.Body):
     """A body component."""
-
-    tag = "body"

+ 3 - 3
reflex/components/base/link.py

@@ -1,10 +1,10 @@
 """Display the title of the current page."""
 
-from reflex.components.component import Component
+from reflex.components.el.elements.base import BaseHTML
 from reflex.vars.base import Var
 
 
-class RawLink(Component):
+class RawLink(BaseHTML):
     """A component that displays the title of the current page."""
 
     tag = "link"
@@ -16,7 +16,7 @@ class RawLink(Component):
     rel: Var[str]
 
 
-class ScriptTag(Component):
+class ScriptTag(BaseHTML):
     """A script tag with the specified type and source."""
 
     tag = "script"

+ 5 - 9
reflex/components/base/meta.py

@@ -3,14 +3,12 @@
 from __future__ import annotations
 
 from reflex.components.base.bare import Bare
-from reflex.components.component import Component
+from reflex.components.el import elements
 
 
-class Title(Component):
+class Title(elements.Title):
     """A component that displays the title of the current page."""
 
-    tag = "title"
-
     def render(self) -> dict:
         """Render the title component.
 
@@ -26,11 +24,9 @@ class Title(Component):
         return super().render()
 
 
-class Meta(Component):
+class Meta(elements.Meta):
     """A component that displays metadata for the current page."""
 
-    tag = "meta"
-
     # The description of character encoding.
     char_set: str | None = None
 
@@ -47,14 +43,14 @@ class Meta(Component):
     http_equiv: str | None = None
 
 
-class Description(Meta):
+class Description(elements.Meta):
     """A component that displays the title of the current page."""
 
     # The type of the description.
     name: str | None = "description"
 
 
-class Image(Meta):
+class Image(elements.Meta):
     """A component that displays the title of the current page."""
 
     # The type of the image.

+ 13 - 27
reflex/components/component.py

@@ -268,6 +268,9 @@ class Component(BaseComponent, ABC):
     # The alias for the tag.
     alias: str | None = pydantic.v1.Field(default_factory=lambda: None)
 
+    # Whether the component is a global scope tag. True for tags like `html`, `head`, `body`.
+    _is_tag_in_global_scope: ClassVar[bool] = False
+
     # Whether the import is default or named.
     is_default: bool | None = pydantic.v1.Field(default_factory=lambda: False)
 
@@ -689,9 +692,14 @@ class Component(BaseComponent, ABC):
         Returns:
             The tag to render.
         """
+        # Create the base tag.
+        name = (self.tag if not self.alias else self.alias) or ""
+        if self._is_tag_in_global_scope and self.library is None:
+            name = '"' + name + '"'
+
         # Create the base tag.
         tag = Tag(
-            name=(self.tag if not self.alias else self.alias) or "",
+            name=name,
             special_props=self.special_props,
         )
 
@@ -2570,12 +2578,12 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
     special_props = []
 
     for prop_str in tag["props"]:
-        if "=" not in prop_str:
+        if ":" not in prop_str:
             special_props.append(Var(prop_str).to(ObjectVar))
             continue
-        prop = prop_str.index("=")
+        prop = prop_str.index(":")
         key = prop_str[:prop]
-        value = prop_str[prop + 2 : -1]
+        value = prop_str[prop + 1 :]
         props[key] = value
 
     props = LiteralObjectVar.create(
@@ -2585,19 +2593,11 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
     for prop in special_props:
         props = props.merge(prop)
 
-    contents = tag["contents"][1:-1] if tag["contents"] else None
+    contents = tag["contents"] if tag["contents"] else None
 
     raw_tag_name = tag.get("name")
     tag_name = Var(raw_tag_name or "Fragment")
 
-    tag_name = (
-        LiteralStringVar.create(raw_tag_name)
-        if raw_tag_name
-        and raw_tag_name.split(".")[0] not in imported_names
-        and raw_tag_name.lower() == raw_tag_name
-        else tag_name
-    )
-
     return FunctionStringVar.create(
         "jsx",
     ).call(
@@ -2642,23 +2642,9 @@ class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
         """
         return VarData.merge(
             self._var_data,
-            VarData(
-                imports={
-                    "@emotion/react": [
-                        ImportVar(tag="jsx"),
-                    ],
-                }
-            ),
             VarData(
                 imports=self._var_value._get_all_imports(),
             ),
-            VarData(
-                imports={
-                    "react": [
-                        ImportVar(tag="Fragment"),
-                    ],
-                }
-            ),
         )
 
     def __hash__(self) -> int:

+ 2 - 2
reflex/components/core/upload.py

@@ -361,7 +361,7 @@ class Upload(MemoizationLeaf):
         upload = Input.create(type="file")
         upload.special_props = [
             Var(
-                _js_expr=f"{{...{input_props_unique_name}()}}",
+                _js_expr=f"{input_props_unique_name}()",
                 _var_type=None,
                 _var_data=var_data,
             )
@@ -375,7 +375,7 @@ class Upload(MemoizationLeaf):
         )
         zone.special_props = [
             Var(
-                _js_expr=f"{{...{root_props_unique_name}()}}",
+                _js_expr=f"{root_props_unique_name}()",
                 _var_type=None,
                 _var_data=var_data,
             )

+ 5 - 2
reflex/components/dynamic.py

@@ -72,7 +72,7 @@ def load_dynamic_serializer():
             The generated code
         """
         # Causes a circular import, so we import here.
-        from reflex.compiler import templates, utils
+        from reflex.compiler import compiler, templates, utils
         from reflex.components.base.bare import Bare
 
         component = Bare.create(Var.create(component))
@@ -97,8 +97,11 @@ def load_dynamic_serializer():
 
         libs_in_window = bundled_libraries
 
+        component_imports = component._get_all_imports()
+        compiler._apply_common_imports(component_imports)
+
         imports = {}
-        for lib, names in component._get_all_imports().items():
+        for lib, names in component_imports.items():
             formatted_lib_name = format_library_name(lib)
             if (
                 not lib.startswith((".", "/", "$/"))

+ 4 - 0
reflex/components/el/element.py

@@ -1,11 +1,15 @@
 """Base class definition for raw HTML elements."""
 
+from typing import ClassVar
+
 from reflex.components.component import Component
 
 
 class Element(Component):
     """The base class for all raw HTML elements."""
 
+    _is_tag_in_global_scope: ClassVar[bool] = True
+
     def __eq__(self, other: object):
         """Two elements are equal if they have the same tag.
 

+ 1 - 1
reflex/components/el/elements/metadata.py

@@ -89,7 +89,7 @@ class StyleEl(Element):
 
     media: Var[str]
 
-    special_props: list[Var] = [Var(_js_expr="suppressHydrationWarning")]
+    suppress_hydration_warning: Var[bool] = Var.create(True)
 
 
 base = Base.create

+ 6 - 7
reflex/components/markdown/markdown.py

@@ -18,8 +18,8 @@ from reflex.vars.number import ternary_operation
 
 # Special vars used in the component map.
 _CHILDREN = Var(_js_expr="children", _var_type=str)
-_PROPS = Var(_js_expr="...props")
-_PROPS_IN_TAG = Var(_js_expr="{...props}")
+_PROPS = Var(_js_expr="props")
+_PROPS_SPREAD = Var(_js_expr="...props")
 _MOCK_ARG = Var(_js_expr="", _var_type=str)
 _LANGUAGE = Var(_js_expr="_language", _var_type=str)
 
@@ -128,7 +128,7 @@ class MarkdownComponentMap:
         Returns:
             The function arguments as a list of strings.
         """
-        return ["node", _CHILDREN._js_expr, _PROPS._js_expr]
+        return ["node", _CHILDREN._js_expr, _PROPS_SPREAD._js_expr]
 
     @classmethod
     def get_fn_body(cls) -> Var:
@@ -297,7 +297,7 @@ let {_LANGUAGE!s} = match ? match[1] : '';
                 "inline",
                 "className",
                 _CHILDREN._js_expr,
-                _PROPS._js_expr,
+                _PROPS_SPREAD._js_expr,
             ),
             fn_body=Var(_js_expr=formatted_code),
             explicit_return=True,
@@ -321,7 +321,7 @@ let {_LANGUAGE!s} = match ? match[1] : '';
         if tag not in self.component_map:
             raise ValueError(f"No markdown component found for tag: {tag}.")
 
-        special_props = [_PROPS_IN_TAG]
+        special_props = [_PROPS]
         children = [
             _CHILDREN
             if tag != "codeblock"
@@ -338,9 +338,8 @@ let {_LANGUAGE!s} = match ? match[1] : '';
             special_props = []
 
         # If the children are set as a prop, don't pass them as children.
-        children_prop = props.pop("children", None)
+        children_prop = props.get("children")
         if children_prop is not None:
-            special_props.append(Var(_js_expr=f"children={{{children_prop!s}}}"))
             children = []
         # Get the component.
         component = self.component_map[tag](*children, **props).set(

+ 1 - 1
reflex/components/plotly/plotly.py

@@ -252,7 +252,7 @@ const extractPoints = (points) => {
             )
         else:
             # Spread the figure dict over props, nothing to merge.
-            tag.special_props.append(Var(_js_expr=f"{{...{figure!s}}}"))
+            tag.special_props.append(Var(_js_expr=f"{figure!s}"))
         return tag
 
 

+ 3 - 2
reflex/components/radix/themes/layout/list.py

@@ -5,8 +5,9 @@ from __future__ import annotations
 from collections.abc import Iterable
 from typing import Any, Literal
 
-from reflex.components.component import Component, ComponentNamespace
+from reflex.components.component import ComponentNamespace
 from reflex.components.core.foreach import Foreach
+from reflex.components.el.elements.base import BaseHTML
 from reflex.components.el.elements.typography import Li, Ol, Ul
 from reflex.components.lucide.icon import Icon
 from reflex.components.markdown.markdown import MarkdownComponentMap
@@ -38,7 +39,7 @@ LiteralListStyleTypeOrdered = Literal[
 ]
 
 
-class BaseList(Component, MarkdownComponentMap):
+class BaseList(BaseHTML, MarkdownComponentMap):
     """Base class for ordered and unordered lists."""
 
     tag = "ul"

+ 10 - 3
reflex/utils/format.py

@@ -439,12 +439,19 @@ def format_props(*single_props, **key_value_props) -> list[str]:
     from reflex.vars.base import LiteralVar, Var
 
     return [
-        (
-            f"{name}={{{format_prop(prop if isinstance(prop, Var) else LiteralVar.create(prop))}}}"
+        ":".join(
+            [
+                str(name if "-" not in name else LiteralVar.create(name)),
+                str(
+                    format_prop(
+                        prop if isinstance(prop, Var) else LiteralVar.create(prop)
+                    )
+                ),
+            ]
         )
         for name, prop in sorted(key_value_props.items())
         if prop is not None
-    ] + [(f"{LiteralVar.create(prop)!s}") for prop in single_props]
+    ] + [(f"...{LiteralVar.create(prop)!s}") for prop in single_props]
 
 
 def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:

+ 1 - 0
reflex/utils/pyi_generator.py

@@ -50,6 +50,7 @@ EXCLUDED_PROPS = [
     "tag",
     "is_default",
     "special_props",
+    "_is_tag_in_global_scope",
     "_invalid_children",
     "_memoization_mode",
     "_rename_props",

+ 4 - 4
tests/units/components/base/test_bare.py

@@ -9,10 +9,10 @@ STATE_VAR = Var(_js_expr="default_state.name")
 @pytest.mark.parametrize(
     "contents,expected",
     [
-        ("hello", '{"hello"}'),
-        ("{}", '{"{}"}'),
-        (None, '{""}'),
-        (STATE_VAR, "{default_state.name}"),
+        ("hello", '"hello"'),
+        ("{}", '"{}"'),
+        (None, '""'),
+        (STATE_VAR, "default_state.name"),
     ],
 )
 def test_fstrings(contents, expected):

+ 4 - 6
tests/units/components/base/test_link.py

@@ -3,13 +3,11 @@ from reflex.components.base.link import RawLink, ScriptTag
 
 def test_raw_link():
     raw_link = RawLink.create("https://example.com").render()
-    assert raw_link["name"] == "link"
-    assert raw_link["children"][0]["contents"] == '{"https://example.com"}'
+    assert raw_link["name"] == '"link"'
+    assert raw_link["children"][0]["contents"] == '"https://example.com"'
 
 
 def test_script_tag():
     script_tag = ScriptTag.create("console.log('Hello, world!');").render()
-    assert script_tag["name"] == "script"
-    assert (
-        script_tag["children"][0]["contents"] == "{\"console.log('Hello, world!');\"}"
-    )
+    assert script_tag["name"] == '"script"'
+    assert script_tag["children"][0]["contents"] == "\"console.log('Hello, world!');\""

+ 5 - 5
tests/units/components/base/test_script.py

@@ -14,7 +14,7 @@ def test_script_inline():
     assert render_dict["name"] == "Script"
     assert not render_dict["contents"]
     assert len(render_dict["children"]) == 1
-    assert render_dict["children"][0]["contents"] == '{"let x = 42"}'
+    assert render_dict["children"][0]["contents"] == '"let x = 42"'
 
 
 def test_script_src():
@@ -24,7 +24,7 @@ def test_script_src():
     assert render_dict["name"] == "Script"
     assert not render_dict["contents"]
     assert not render_dict["children"]
-    assert 'src={"foo.js"}' in render_dict["props"]
+    assert 'src:"foo.js"' in render_dict["props"]
 
 
 def test_script_neither():
@@ -62,14 +62,14 @@ def test_script_event_handler():
     )
     render_dict = component.render()
     assert (
-        f'onReady={{((...args) => (addEvents([(Event("{EvState.get_full_name()}.on_ready", ({{  }}), ({{  }})))], args, ({{  }}))))}}'
+        f'onReady:((...args) => (addEvents([(Event("{EvState.get_full_name()}.on_ready", ({{  }}), ({{  }})))], args, ({{  }}))))'
         in render_dict["props"]
     )
     assert (
-        f'onLoad={{((...args) => (addEvents([(Event("{EvState.get_full_name()}.on_load", ({{  }}), ({{  }})))], args, ({{  }}))))}}'
+        f'onLoad:((...args) => (addEvents([(Event("{EvState.get_full_name()}.on_load", ({{  }}), ({{  }})))], args, ({{  }}))))'
         in render_dict["props"]
     )
     assert (
-        f'onError={{((...args) => (addEvents([(Event("{EvState.get_full_name()}.on_error", ({{  }}), ({{  }})))], args, ({{  }}))))}}'
+        f'onError:((...args) => (addEvents([(Event("{EvState.get_full_name()}.on_error", ({{  }}), ({{  }})))], args, ({{  }}))))'
         in render_dict["props"]
     )

+ 2 - 2
tests/units/components/core/test_cond.py

@@ -57,7 +57,7 @@ def test_validate_cond(cond_state: BaseState):
 
     [true_value_text] = true_value["children"]
     assert true_value_text["name"] == "RadixThemesText"
-    assert true_value_text["children"][0]["contents"] == '{"cond is True"}'
+    assert true_value_text["children"][0]["contents"] == '"cond is True"'
 
     # false value
     false_value = condition["false_value"]
@@ -65,7 +65,7 @@ def test_validate_cond(cond_state: BaseState):
 
     [false_value_text] = false_value["children"]
     assert false_value_text["name"] == "RadixThemesText"
-    assert false_value_text["children"][0]["contents"] == '{"cond is False"}'
+    assert false_value_text["children"][0]["contents"] == '"cond is False"'
 
 
 @pytest.mark.parametrize(

+ 1 - 1
tests/units/components/core/test_foreach.py

@@ -282,7 +282,7 @@ def test_foreach_component_styles():
         )
     )
     component._add_style_recursive({box: {"color": "red"}})
-    assert 'css={({ ["color"] : "red" })}' in str(component)
+    assert 'css:({ ["color"] : "red" })' in str(component)
 
 
 def test_foreach_component_state():

+ 5 - 3
tests/units/components/core/test_html.py

@@ -19,7 +19,7 @@ def test_html_create():
     assert str(html.dangerouslySetInnerHTML) == '({ ["__html"] : "<p>Hello !</p>" })'  # pyright: ignore [reportAttributeAccessIssue]
     assert (
         str(html)
-        == '<div className={"rx-Html"} dangerouslySetInnerHTML={({ ["__html"] : "<p>Hello !</p>" })}/>'
+        == 'jsx("div",{className:"rx-Html",dangerouslySetInnerHTML:({ ["__html"] : "<p>Hello !</p>" })},)\n'
     )
 
 
@@ -31,11 +31,13 @@ def test_html_fstring_create():
 
     html = Html.create(f"<p>Hello {TestState.myvar}!</p>")
 
+    html_dangerouslySetInnerHTML = html.dangerouslySetInnerHTML  # pyright: ignore [reportAttributeAccessIssue]
+
     assert (
-        str(html.dangerouslySetInnerHTML)  # pyright: ignore [reportAttributeAccessIssue]
+        str(html_dangerouslySetInnerHTML)
         == f'({{ ["__html"] : ("<p>Hello "+{TestState.myvar!s}+"!</p>") }})'
     )
     assert (
         str(html)
-        == f'<div className={{"rx-Html"}} dangerouslySetInnerHTML={{{html.dangerouslySetInnerHTML!s}}}/>'  # pyright: ignore [reportAttributeAccessIssue]
+        == f'jsx("div",{{className:"rx-Html",dangerouslySetInnerHTML:{html_dangerouslySetInnerHTML!s}}},)\n'
     )

+ 10 - 9
tests/units/components/core/test_match.py

@@ -1,3 +1,4 @@
+import re
 from collections.abc import Mapping, Sequence
 
 import pytest
@@ -47,7 +48,7 @@ def test_match_components():
     assert match_cases[0][0]._var_type is int
     first_return_value_render = match_cases[0][1]
     assert first_return_value_render["name"] == "RadixThemesText"
-    assert first_return_value_render["children"][0]["contents"] == '{"first value"}'
+    assert first_return_value_render["children"][0]["contents"] == '"first value"'
 
     assert match_cases[1][0]._js_expr == "2"
     assert match_cases[1][0]._var_type is int
@@ -55,36 +56,36 @@ def test_match_components():
     assert match_cases[1][1]._var_type is int
     second_return_value_render = match_cases[1][2]
     assert second_return_value_render["name"] == "RadixThemesText"
-    assert second_return_value_render["children"][0]["contents"] == '{"second value"}'
+    assert second_return_value_render["children"][0]["contents"] == '"second value"'
 
     assert match_cases[2][0]._js_expr == "[1, 2]"
     assert match_cases[2][0]._var_type == Sequence[int]
     third_return_value_render = match_cases[2][1]
     assert third_return_value_render["name"] == "RadixThemesText"
-    assert third_return_value_render["children"][0]["contents"] == '{"third value"}'
+    assert third_return_value_render["children"][0]["contents"] == '"third value"'
 
     assert match_cases[3][0]._js_expr == '"random"'
     assert match_cases[3][0]._var_type is str
     fourth_return_value_render = match_cases[3][1]
     assert fourth_return_value_render["name"] == "RadixThemesText"
-    assert fourth_return_value_render["children"][0]["contents"] == '{"fourth value"}'
+    assert fourth_return_value_render["children"][0]["contents"] == '"fourth value"'
 
     assert match_cases[4][0]._js_expr == '({ ["foo"] : "bar" })'
     assert match_cases[4][0]._var_type == Mapping[str, str]
     fifth_return_value_render = match_cases[4][1]
     assert fifth_return_value_render["name"] == "RadixThemesText"
-    assert fifth_return_value_render["children"][0]["contents"] == '{"fifth value"}'
+    assert fifth_return_value_render["children"][0]["contents"] == '"fifth value"'
 
     assert match_cases[5][0]._js_expr == f"({MatchState.get_name()}.num + 1)"
     assert match_cases[5][0]._var_type is int
     fifth_return_value_render = match_cases[5][1]
     assert fifth_return_value_render["name"] == "RadixThemesText"
-    assert fifth_return_value_render["children"][0]["contents"] == '{"sixth value"}'
+    assert fifth_return_value_render["children"][0]["contents"] == '"sixth value"'
 
     default = match_child["default"]
 
     assert default["name"] == "RadixThemesText"
-    assert default["children"][0]["contents"] == '{"default value"}'
+    assert default["children"][0]["contents"] == '"default value"'
 
 
 @pytest.mark.parametrize(
@@ -264,7 +265,7 @@ def test_match_case_tuple_elements(match_case):
                 ([1, 2], rx.text("third value")),
                 rx.text("default value"),
             ),
-            'Match cases should have the same return types. Case 3 with return value `<RadixThemesText as={"p"}> {"first value"} </RadixThemesText>` '
+            'Match cases should have the same return types. Case 3 with return value `jsx( RadixThemesText, {as:"p"}, "first value" ,)` '
             "of type <class 'reflex.components.radix.themes.typography.text.Text'> is not <class 'reflex.vars.base.Var'>",
         ),
     ],
@@ -276,7 +277,7 @@ def test_match_different_return_types(cases: tuple, error_msg: str):
         cases: The match cases.
         error_msg: Expected error message.
     """
-    with pytest.raises(MatchTypeError, match=error_msg):
+    with pytest.raises(MatchTypeError, match=re.escape(error_msg)):
         Match.create(MatchState.value, *cases)
 
 

+ 2 - 2
tests/units/components/datadisplay/test_dataeditor.py

@@ -4,8 +4,8 @@ from reflex.components.datadisplay.dataeditor import DataEditor
 def test_dataeditor():
     editor_wrapper = DataEditor.create().render()
     editor = editor_wrapper["children"][0]
-    assert editor_wrapper["name"] == "div"
+    assert editor_wrapper["name"] == '"div"'
     assert editor_wrapper["props"] == [
-        'css={({ ["width"] : "100%", ["height"] : "100%" })}'
+        'css:({ ["width"] : "100%", ["height"] : "100%" })'
     ]
     assert editor["name"] == "DataEditor"

+ 2 - 2
tests/units/components/datadisplay/test_datatable.py

@@ -47,8 +47,8 @@ def test_validate_data_table(data_table_state: rx.State, expected):
     expected = f"{state_name}.{expected}" if expected else state_name
 
     assert data_table_dict["props"] == [
-        f"columns={{{expected}.columns}}",
-        f"data={{{expected}.data}}",
+        f"columns:{expected}.columns",
+        f"data:{expected}.data",
     ]
 
 

+ 12 - 12
tests/units/components/el/test_svg.py

@@ -16,59 +16,59 @@ from reflex.components.el.elements.media import (
 
 def test_circle():
     circle = Circle.create().render()
-    assert circle["name"] == "circle"
+    assert circle["name"] == '"circle"'
 
 
 def test_defs():
     defs = Defs.create().render()
-    assert defs["name"] == "defs"
+    assert defs["name"] == '"defs"'
 
 
 def test_ellipse():
     ellipse = Ellipse.create().render()
-    assert ellipse["name"] == "ellipse"
+    assert ellipse["name"] == '"ellipse"'
 
 
 def test_line():
     line = Line.create().render()
-    assert line["name"] == "line"
+    assert line["name"] == '"line"'
 
 
 def test_linear_gradient():
     linear_gradient = LinearGradient.create().render()
-    assert linear_gradient["name"] == "linearGradient"
+    assert linear_gradient["name"] == '"linearGradient"'
 
 
 def test_path():
     path = Path.create().render()
-    assert path["name"] == "path"
+    assert path["name"] == '"path"'
 
 
 def test_polygon():
     polygon = Polygon.create().render()
-    assert polygon["name"] == "polygon"
+    assert polygon["name"] == '"polygon"'
 
 
 def test_radial_gradient():
     radial_gradient = RadialGradient.create().render()
-    assert radial_gradient["name"] == "radialGradient"
+    assert radial_gradient["name"] == '"radialGradient"'
 
 
 def test_rect():
     rect = Rect.create().render()
-    assert rect["name"] == "rect"
+    assert rect["name"] == '"rect"'
 
 
 def test_svg():
     svg = Svg.create().render()
-    assert svg["name"] == "svg"
+    assert svg["name"] == '"svg"'
 
 
 def test_text():
     text = Text.create().render()
-    assert text["name"] == "text"
+    assert text["name"] == '"text"'
 
 
 def test_stop():
     stop = Stop.create().render()
-    assert stop["name"] == "stop"
+    assert stop["name"] == '"stop"'

+ 1 - 1
tests/units/components/forms/test_form.py

@@ -11,7 +11,7 @@ def test_render_on_submit():
     )
     f = Form.create(on_submit=submit_it)
     exp_submit_name = f"handleSubmit_{f.handle_submit_unique_name}"  # pyright: ignore [reportAttributeAccessIssue]
-    assert f"onSubmit={{{exp_submit_name}}}" in f.render()["props"]
+    assert f"onSubmit:{exp_submit_name}" in f.render()["props"]
 
 
 def test_render_no_on_submit():

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
tests/units/components/markdown/test_markdown.py


+ 20 - 20
tests/units/components/test_component.py

@@ -686,14 +686,14 @@ def test_component_create_unallowed_types(children, test_component):
                 "children": [
                     {
                         "name": "RadixThemesText",
-                        "props": ['as={"p"}'],
+                        "props": ['as:"p"'],
                         "contents": "",
                         "special_props": [],
                         "children": [
                             {
                                 "name": "",
                                 "props": [],
-                                "contents": '{"first_text"}',
+                                "contents": '"first_text"',
                                 "special_props": [],
                                 "children": [],
                                 "autofocus": False,
@@ -716,7 +716,7 @@ def test_component_create_unallowed_types(children, test_component):
                             {
                                 "autofocus": False,
                                 "children": [],
-                                "contents": '{"first_text"}',
+                                "contents": '"first_text"',
                                 "name": "",
                                 "props": [],
                                 "special_props": [],
@@ -724,7 +724,7 @@ def test_component_create_unallowed_types(children, test_component):
                         ],
                         "contents": "",
                         "name": "RadixThemesText",
-                        "props": ['as={"p"}'],
+                        "props": ['as:"p"'],
                         "special_props": [],
                     },
                     {
@@ -733,7 +733,7 @@ def test_component_create_unallowed_types(children, test_component):
                             {
                                 "autofocus": False,
                                 "children": [],
-                                "contents": '{"second_text"}',
+                                "contents": '"second_text"',
                                 "name": "",
                                 "props": [],
                                 "special_props": [],
@@ -741,7 +741,7 @@ def test_component_create_unallowed_types(children, test_component):
                         ],
                         "contents": "",
                         "name": "RadixThemesText",
-                        "props": ['as={"p"}'],
+                        "props": ['as:"p"'],
                         "special_props": [],
                     },
                 ],
@@ -762,7 +762,7 @@ def test_component_create_unallowed_types(children, test_component):
                             {
                                 "autofocus": False,
                                 "children": [],
-                                "contents": '{"first_text"}',
+                                "contents": '"first_text"',
                                 "name": "",
                                 "props": [],
                                 "special_props": [],
@@ -770,7 +770,7 @@ def test_component_create_unallowed_types(children, test_component):
                         ],
                         "contents": "",
                         "name": "RadixThemesText",
-                        "props": ['as={"p"}'],
+                        "props": ['as:"p"'],
                         "special_props": [],
                     },
                     {
@@ -785,7 +785,7 @@ def test_component_create_unallowed_types(children, test_component):
                                             {
                                                 "autofocus": False,
                                                 "children": [],
-                                                "contents": '{"second_text"}',
+                                                "contents": '"second_text"',
                                                 "name": "",
                                                 "props": [],
                                                 "special_props": [],
@@ -793,7 +793,7 @@ def test_component_create_unallowed_types(children, test_component):
                                         ],
                                         "contents": "",
                                         "name": "RadixThemesText",
-                                        "props": ['as={"p"}'],
+                                        "props": ['as:"p"'],
                                         "special_props": [],
                                     }
                                 ],
@@ -1163,10 +1163,10 @@ def test_component_with_only_valid_children(fixture, request):
 @pytest.mark.parametrize(
     "component,rendered",
     [
-        (rx.text("hi"), '<RadixThemesText as={"p"}>\n\n{"hi"}\n</RadixThemesText>'),
+        (rx.text("hi"), 'jsx(\nRadixThemesText,\n{as:"p"},\n"hi"\n,)'),
         (
             rx.box(rx.heading("test", size="3")),
-            '<RadixThemesBox>\n\n<RadixThemesHeading size={"3"}>\n\n{"test"}\n</RadixThemesHeading>\n</RadixThemesBox>',
+            'jsx(\nRadixThemesBox,\n{},\njsx(\nRadixThemesHeading,\n{size:"3"},\n"test"\n,),)',
         ),
     ],
 )
@@ -1789,14 +1789,14 @@ def test_rename_props():
 
     c1 = C1.create(prop1="prop1_1", prop2="prop2_1")
     rendered_c1 = c1.render()
-    assert 'renamed_prop1={"prop1_1"}' in rendered_c1["props"]
-    assert 'renamed_prop2={"prop2_1"}' in rendered_c1["props"]
+    assert 'renamed_prop1:"prop1_1"' in rendered_c1["props"]
+    assert 'renamed_prop2:"prop2_1"' in rendered_c1["props"]
 
     c2 = C2.create(prop1="prop1_2", prop2="prop2_2", prop3="prop3_2")
     rendered_c2 = c2.render()
-    assert 'renamed_prop1={"prop1_2"}' in rendered_c2["props"]
-    assert 'subclass_prop2={"prop2_2"}' in rendered_c2["props"]
-    assert 'renamed_prop3={"prop3_2"}' in rendered_c2["props"]
+    assert 'renamed_prop1:"prop1_2"' in rendered_c2["props"]
+    assert 'subclass_prop2:"prop2_2"' in rendered_c2["props"]
+    assert 'renamed_prop3:"prop3_2"' in rendered_c2["props"]
 
 
 def test_custom_component_get_imports():
@@ -2183,7 +2183,7 @@ def test_add_style_embedded_vars(test_state: BaseState):
     assert "useParent" in page._get_all_hooks_internal()
     assert (
         str(page).count(
-            f'css={{({{ ["fakeParent"] : "parent", ["color"] : "var(--plum-10)", ["fake"] : "text", ["margin"] : ({test_state.get_name()}.num+"%") }})}}'
+            f'css:({{ ["fakeParent"] : "parent", ["color"] : "var(--plum-10)", ["fake"] : "text", ["margin"] : ({test_state.get_name()}.num+"%") }})'
         )
         == 1
     )
@@ -2204,10 +2204,10 @@ def test_add_style_foreach():
     assert len(page.children[0].children) == 1
 
     # Expect the style to be added to the child of the foreach
-    assert 'css={({ ["color"] : "red" })}' in str(page.children[0].children[0])
+    assert 'css:({ ["color"] : "red" })' in str(page.children[0].children[0])
 
     # Expect only one instance of this CSS dict in the rendered page
-    assert str(page).count('css={({ ["color"] : "red" })}') == 1
+    assert str(page).count('css:({ ["color"] : "red" })') == 1
 
 
 class TriggerState(rx.State):

+ 4 - 4
tests/units/components/test_tag.py

@@ -8,10 +8,10 @@ from reflex.vars.base import LiteralVar, Var
     "props,test_props",
     [
         ({}, []),
-        ({"key-hypen": 1}, ["key-hypen={1}"]),
-        ({"key": 1}, ["key={1}"]),
-        ({"key": "value"}, ['key={"value"}']),
-        ({"key": True, "key2": "value2"}, ["key={true}", 'key2={"value2"}']),
+        ({"key-hypen": 1}, ['"key-hypen":1']),
+        ({"key": 1}, ["key:1"]),
+        ({"key": "value"}, ['key:"value"']),
+        ({"key": True, "key2": "value2"}, ["key:true", 'key2:"value2"']),
     ],
 )
 def test_format_props(props: dict[str, Var], test_props: list):

+ 28 - 31
tests/units/test_app.py

@@ -1364,24 +1364,23 @@ def test_app_wrap_compile_theme(
         line.strip() for line in app_js_contents.splitlines() if line.strip()
     ]
     lines = "".join(app_js_lines)
-    assert (
+    expected = (
         "function AppWrap({children}) {"
         "return ("
-        + ("<StrictMode>" if react_strict_mode else "")
-        + "<RadixThemesColorModeProvider>"
-        "<RadixThemesTheme accentColor={\"plum\"} css={{...theme.styles.global[':root'], ...theme.styles.global.body}}>"
-        "<Fragment>"
-        "<MemoizedToastProvider/>"
-        "<Fragment>"
-        "{children}"
-        "</Fragment>"
-        "</Fragment>"
-        "</RadixThemesTheme>"
-        "</RadixThemesColorModeProvider>"
-        + ("</StrictMode>" if react_strict_mode else "")
-        + ")"
+        + ("jsx(StrictMode,{}," if react_strict_mode else "")
+        + "jsx(RadixThemesColorModeProvider,{},"
+        "jsx(RadixThemesTheme,{accentColor:\"plum\",css:{...theme.styles.global[':root'], ...theme.styles.global.body}},"
+        "jsx(Fragment,{},"
+        "jsx(MemoizedToastProvider,{},),"
+        "jsx(Fragment,{},"
+        "children,"
+        "),"
+        "),"
+        "),"
+        ")" + (",)" if react_strict_mode else "") + ")"
         "}"
-    ) in lines
+    )
+    assert expected in lines
 
 
 @pytest.mark.parametrize(
@@ -1431,23 +1430,21 @@ def test_app_wrap_priority(
         line.strip() for line in app_js_contents.splitlines() if line.strip()
     ]
     lines = "".join(app_js_lines)
-    assert (
+    expected = (
         "function AppWrap({children}) {"
-        "return (" + ("<StrictMode>" if react_strict_mode else "") + "<RadixThemesBox>"
-        '<RadixThemesText as={"p"}>'
-        "<RadixThemesColorModeProvider>"
-        "<Fragment2>"
-        "<Fragment>"
-        "<MemoizedToastProvider/>"
-        "<Fragment>"
-        "{children}"
-        "</Fragment>"
-        "</Fragment>"
-        "</Fragment2>"
-        "</RadixThemesColorModeProvider>"
-        "</RadixThemesText>"
-        "</RadixThemesBox>" + ("</StrictMode>" if react_strict_mode else "")
-    ) in lines
+        "return ("
+        + ("jsx(StrictMode,{}," if react_strict_mode else "")
+        + "jsx(RadixThemesBox,{},"
+        'jsx(RadixThemesText,{as:"p"},'
+        "jsx(RadixThemesColorModeProvider,{},"
+        "jsx(Fragment2,{},"
+        "jsx(Fragment,{},"
+        "jsx(MemoizedToastProvider,{},),"
+        "jsx(Fragment,{},"
+        "children"
+        ",),),),),)" + (",)" if react_strict_mode else "")
+    )
+    assert expected in lines
 
 
 def test_app_state_determination():

+ 3 - 3
tests/units/utils/test_format.py

@@ -457,7 +457,7 @@ def test_format_match(
                     _js_expr=f"(({{node, ...props}}) => <Heading {{...props}} {''.join(Tag(name='', props=Style({'as_': 'h1'})).format_props())} />)"
                 ),
             },
-            '({ ["h1"] : (({node, ...props}) => <Heading {...props} as={"h1"} />) })',
+            '({ ["h1"] : (({node, ...props}) => <Heading {...props} as:"h1" />) })',
         ),
     ],
 )
@@ -475,9 +475,9 @@ def test_format_prop(prop: Var, formatted: str):
     "single_props,key_value_props,output",
     [
         (
-            [Var(_js_expr="{...props}")],
+            [Var(_js_expr="props")],
             {"key": 42},
-            ["key={42}", "{...props}"],
+            ["key:42", "...props"],
         ),
     ],
 )

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff