Skip to content
5 changes: 3 additions & 2 deletions reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import asyncio
import contextlib
import copy
import functools
import os
from multiprocessing.pool import ThreadPool
Expand Down Expand Up @@ -589,9 +590,9 @@ def get_frontend_packages(self, imports: Dict[str, set[ImportVar]]):

def _app_root(self, app_wrappers):
order = sorted(app_wrappers, key=lambda k: k[0], reverse=True)
root = parent = app_wrappers[order[0]]
root = parent = copy.deepcopy(app_wrappers[order[0]])
for key in order[1:]:
child = app_wrappers[key]
child = copy.deepcopy(app_wrappers[key])
parent.children.append(child)
parent = child
return root
Expand Down
25 changes: 13 additions & 12 deletions reflex/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@

# Imports to be included in every Reflex app.
DEFAULT_IMPORTS: imports.ImportDict = {
"react": {
"react": [
ImportVar(tag="Fragment"),
ImportVar(tag="useEffect"),
ImportVar(tag="useRef"),
ImportVar(tag="useState"),
ImportVar(tag="useContext"),
},
"next/router": {ImportVar(tag="useRouter")},
f"/{constants.Dirs.STATE_PATH}": {
],
"next/router": [ImportVar(tag="useRouter")],
f"/{constants.Dirs.STATE_PATH}": [
ImportVar(tag="uploadFiles"),
ImportVar(tag="Event"),
ImportVar(tag="isTrue"),
Expand All @@ -34,17 +34,17 @@
ImportVar(tag="getRefValues"),
ImportVar(tag="getAllLocalStorageItems"),
ImportVar(tag="useEventLoop"),
},
"/utils/context.js": {
],
"/utils/context.js": [
ImportVar(tag="EventLoopContext"),
ImportVar(tag="initialEvents"),
ImportVar(tag="StateContext"),
ImportVar(tag="ColorModeContext"),
},
"/utils/helpers/range.js": {
],
"/utils/helpers/range.js": [
ImportVar(tag="range", is_default=True),
},
"": {ImportVar(tag="focus-visible/dist/focus-visible", install=False)},
],
"": [ImportVar(tag="focus-visible/dist/focus-visible", install=False)],
}


Expand Down Expand Up @@ -129,6 +129,7 @@ def _compile_page(
"""
# Merge the default imports with the app-specific imports.
imports = utils.merge_imports(DEFAULT_IMPORTS, component.get_imports())
imports = {k: list(set(v)) for k, v in imports.items()}
utils.validate_imports(imports)
imports = utils.compile_imports(imports)

Expand Down Expand Up @@ -216,8 +217,8 @@ def _compile_components(components: set[CustomComponent]) -> str:
The compiled components.
"""
imports = {
"react": {ImportVar(tag="memo")},
f"/{constants.Dirs.STATE_PATH}": {ImportVar(tag="E"), ImportVar(tag="isTrue")},
"react": [ImportVar(tag="memo")],
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="E"), ImportVar(tag="isTrue")],
}
component_renders = []

Expand Down
16 changes: 8 additions & 8 deletions reflex/compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
merge_imports = imports.merge_imports


def compile_import_statement(fields: set[ImportVar]) -> tuple[str, set[str]]:
def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]:
"""Compile an import statement.

Args:
Expand All @@ -42,17 +42,17 @@ def compile_import_statement(fields: set[ImportVar]) -> tuple[str, set[str]]:
rest: rest of libraries. When install "import {rest1, rest2} from library"
"""
# ignore the ImportVar fields with render=False during compilation
fields = {field for field in fields if field.render}
fields_set = {field for field in fields if field.render}

# Check for default imports.
defaults = {field for field in fields if field.is_default}
defaults = {field for field in fields_set if field.is_default}
assert len(defaults) < 2

# Get the default import, and the specific imports.
default = next(iter({field.name for field in defaults}), "")
rest = {field.name for field in fields - defaults}
rest = {field.name for field in fields_set - defaults}

return default, rest
return default, list(rest)


def validate_imports(imports: imports.ImportDict):
Expand Down Expand Up @@ -109,7 +109,7 @@ def compile_imports(imports: imports.ImportDict) -> list[dict]:
return import_dicts


def get_import_dict(lib: str, default: str = "", rest: set[str] | None = None) -> dict:
def get_import_dict(lib: str, default: str = "", rest: list[str] | None = None) -> dict:
"""Get dictionary for import template.

Args:
Expand All @@ -123,7 +123,7 @@ def get_import_dict(lib: str, default: str = "", rest: set[str] | None = None) -
return {
"lib": lib,
"default": default,
"rest": rest if rest else set(),
"rest": rest if rest else [],
}


Expand Down Expand Up @@ -235,7 +235,7 @@ def compile_custom_component(
A tuple of the compiled component and the imports required by the component.
"""
# Render the component.
render = component.get_component()
render = component.get_component(component)

# Get the imports.
imports = {
Expand Down
35 changes: 20 additions & 15 deletions reflex/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import typing
from abc import ABC
from functools import wraps
from functools import lru_cache, wraps
from typing import Any, Callable, Dict, List, Optional, Set, Type, Union

from reflex.base import Base
Expand Down Expand Up @@ -399,6 +399,7 @@ def _render(self, props: dict[str, Any] | None = None) -> Tag:
return tag.add_props(**props)

@classmethod
@lru_cache(maxsize=None)
def get_props(cls) -> Set[str]:
"""Get the unique fields for the component.

Expand All @@ -408,6 +409,7 @@ def get_props(cls) -> Set[str]:
return set(cls.get_fields()) - set(Component.get_fields())

@classmethod
@lru_cache(maxsize=None)
def get_initial_props(cls) -> Set[str]:
"""Get the initial props to set for the component.

Expand All @@ -417,6 +419,7 @@ def get_initial_props(cls) -> Set[str]:
return set()

@classmethod
@lru_cache(maxsize=None)
def get_component_props(cls) -> set[str]:
"""Get the props that expected a component as value.

Expand Down Expand Up @@ -619,29 +622,27 @@ def get_dynamic_imports(self) -> Set[str]:
# Return the dynamic imports
return dynamic_imports

def _get_props_imports(self) -> imports.ImportDict:
def _get_props_imports(self) -> List[str]:
"""Get the imports needed for components props.

Returns:
The imports for the components props of the component.
"""
return imports.merge_imports(
*[
getattr(self, prop).get_imports()
for prop in self.get_component_props()
if getattr(self, prop) is not None
]
)
return [
getattr(self, prop).get_imports()
for prop in self.get_component_props()
if getattr(self, prop) is not None
]

def _get_dependencies_imports(self) -> imports.ImportDict:
"""Get the imports from lib_dependencies for installing.

Returns:
The dependencies imports of the component.
"""
return imports.merge_imports(
{dep: {ImportVar(tag=None, render=False)} for dep in self.lib_dependencies}
)
return {
dep: [ImportVar(tag=None, render=False)] for dep in self.lib_dependencies
}

def _get_imports(self) -> imports.ImportDict:
"""Get all the libraries and fields that are used by the component.
Expand All @@ -654,7 +655,7 @@ def _get_imports(self) -> imports.ImportDict:
_imports[self.library] = {self.import_var}

return imports.merge_imports(
self._get_props_imports(),
*self._get_props_imports(),
self._get_dependencies_imports(),
_imports,
)
Expand Down Expand Up @@ -804,7 +805,8 @@ def import_var(self):
alias = self.alias.partition(".")[0] if self.alias else None
return ImportVar(tag=tag, is_default=self.is_default, alias=alias)

def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
@staticmethod
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
"""Get the app wrap components for the component.

Returns:
Expand Down Expand Up @@ -948,7 +950,9 @@ def get_custom_components(
# Avoid adding the same component twice.
if self.tag not in seen:
seen.add(self.tag)
custom_components |= self.get_component().get_custom_components(seen=seen)
custom_components |= self.get_component(self).get_custom_components(
seen=seen
)
return custom_components

def _render(self) -> Tag:
Expand All @@ -975,6 +979,7 @@ def get_prop_vars(self) -> List[BaseVar]:
for name, prop in self.props.items()
]

@lru_cache(maxsize=None) # noqa
def get_component(self) -> Component:
"""Render the component.

Expand Down
3 changes: 2 additions & 1 deletion reflex/components/datadisplay/dataeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ def create(cls, *children, **props) -> Component:
height=props.pop("height", "100%"),
)

def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
@staticmethod
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
"""Get the app wrap components for the component.

Returns:
Expand Down
4 changes: 2 additions & 2 deletions reflex/components/forms/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@ class Editor(NoSSRComponent):

def _get_imports(self):
imports = super()._get_imports()
imports[""] = {
imports[""] = [
ImportVar(tag="suneditor/dist/css/suneditor.min.css", install=False)
}
]
return imports

def get_event_triggers(self) -> Dict[str, Any]:
Expand Down
2 changes: 1 addition & 1 deletion reflex/components/forms/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,5 @@ def _get_hooks(self) -> str | None:
def _get_imports(self) -> imports.ImportDict:
return {
**super()._get_imports(),
f"/{constants.Dirs.STATE_PATH}": {ImportVar(tag="upload_files")},
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="upload_files")],
}
8 changes: 8 additions & 0 deletions reflex/components/layout/cond.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ def create(
)
)

def _get_props_imports(self):
"""Get the imports needed for components props.

Returns:
The imports for the components props of the component.
"""
return []

def _render(self) -> Tag:
return CondTag(
cond=self.cond,
Expand Down
42 changes: 34 additions & 8 deletions reflex/components/libs/chakra.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Components that are based on Chakra-UI."""
from __future__ import annotations

from functools import lru_cache
from typing import List, Literal

from reflex.components.component import Component
Expand All @@ -17,10 +18,27 @@ class ChakraComponent(Component):
"framer-motion@10.16.4",
]

def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
@staticmethod
@lru_cache(maxsize=None)
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
return {
**super()._get_app_wrap_components(),
(60, "ChakraProvider"): ChakraProvider.create(),
(60, "ChakraProvider"): chakra_provider,
}

@classmethod
@lru_cache(maxsize=None)
def _get_dependencies_imports(cls) -> imports.ImportDict:
"""Get the imports from lib_dependencies for installing.

Returns:
The dependencies imports of the component.
"""
return {
dep: [ImportVar(tag=None, render=False)]
for dep in [
"@chakra-ui/system@2.5.7",
"framer-motion@10.16.4",
]
}


Expand Down Expand Up @@ -58,13 +76,13 @@ def create(cls) -> Component:

def _get_imports(self) -> imports.ImportDict:
imports = super()._get_imports()
imports.setdefault(self.__fields__["library"].default, set()).add(
imports.setdefault(self.__fields__["library"].default, []).append(
ImportVar(tag="extendTheme", is_default=False),
)
imports.setdefault("/utils/theme.js", set()).add(
imports.setdefault("/utils/theme.js", []).append(
ImportVar(tag="theme", is_default=True),
)
imports.setdefault(Global.__fields__["library"].default, set()).add(
imports.setdefault(Global.__fields__["library"].default, []).append(
ImportVar(tag="css", is_default=False),
)
return imports
Expand All @@ -82,12 +100,17 @@ def _get_custom_code(self) -> str | None:
`;
"""

def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
@staticmethod
@lru_cache(maxsize=None)
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
return {
(50, "ChakraColorModeProvider"): ChakraColorModeProvider.create(),
(50, "ChakraColorModeProvider"): chakra_color_mode_provider,
}


chakra_provider = ChakraProvider.create()


class ChakraColorModeProvider(Component):
"""Next-themes integration for chakra colorModeProvider."""

Expand All @@ -96,6 +119,9 @@ class ChakraColorModeProvider(Component):
is_default = True


chakra_color_mode_provider = ChakraColorModeProvider.create()


LiteralColorScheme = Literal[
"none",
"gray",
Expand Down
Loading