diff --git a/src/py/reactpy/pyproject.toml b/src/py/reactpy/pyproject.toml index 659ddbf94..d8c67c8fd 100644 --- a/src/py/reactpy/pyproject.toml +++ b/src/py/reactpy/pyproject.toml @@ -41,23 +41,27 @@ all = ["reactpy[starlette,sanic,fastapi,flask,tornado,testing]"] starlette = [ "starlette >=0.13.6", "uvicorn[standard] >=0.19.0", + "jinja2-simple-tags", ] sanic = [ "sanic >=21", "sanic-cors", "uvicorn[standard] >=0.19.0", + "jinja2-simple-tags", ] fastapi = [ "fastapi >=0.63.0", "uvicorn[standard] >=0.19.0", + "jinja2-simple-tags", ] flask = [ "flask", "markupsafe>=1.1.1,<2.1", "flask-cors", "flask-sock", + "jinja2-simple-tags", ] -tornado = [ +tornado = [ # TODO: Torando does not use Jinja. We will need to write something custom for this. "tornado", ] testing = [ diff --git a/src/py/reactpy/reactpy/templatetag.py b/src/py/reactpy/reactpy/templatetag.py new file mode 100644 index 000000000..1fd525b49 --- /dev/null +++ b/src/py/reactpy/reactpy/templatetag.py @@ -0,0 +1,44 @@ +from jinja2_simple_tags import StandaloneTag +from uuid import uuid4 +import urllib.parse + +REACTPY_WEBSOCKET_URL: str +REACTPY_WEB_MODULES_URL: str +REACTPY_RECONNECT_MAX: str +REACTPY_CLIENT_URL: str + + +class ComponentTag(StandaloneTag): + """This allows enables a `component` tag to be used in any Jinja2 rendering context.""" + safe_output = True + tags = {"component"} + + def render(self, dotted_path: str, *args, **kwargs): + uuid = uuid4().hex + class_ = kwargs.pop("class", "") + kwargs.pop("key", "") # `key` is effectively useless for the root node + + # Generate the websocket URL + # TODO: This will require rewriting the websocket URL to `reactpy-ws/?` + component_ws_url = f"{REACTPY_WEBSOCKET_URL}/{uuid}" + if kwargs.get("args") is not None: + raise ValueError("Cannot specify `args` as a keyword argument") + if args: + kwargs["args"] = args + if kwargs: + component_ws_url += f"?{urllib.parse.urlencode(kwargs)}" + + return ( + f'
' + '" + )