diff --git a/app/components/CodeEditor.tsx b/app/components/CodeEditor.tsx
index 18704aa..22c282a 100644
--- a/app/components/CodeEditor.tsx
+++ b/app/components/CodeEditor.tsx
@@ -73,7 +73,7 @@ export default function CodeEditor({
};
return (
-
+
);
case "nav-tab-content":
@@ -526,10 +527,12 @@ export function RenderedChildren({
children,
onChange,
state,
+ className,
}: {
children: Array;
onChange: OnChange;
state: Record;
+ className?: string;
}) {
let elements = children.map((node, idx) => {
let key;
@@ -538,6 +541,10 @@ export function RenderedChildren({
} else {
key = `idx:${idx}`;
}
+ let prevClassName = node.props.className || "";
+ if (className && !prevClassName.includes(className)) {
+ node.props.className = `${className} ${prevClassName}`;
+ }
return (
str:
if value is None:
return BLANK_OPTION
@@ -54,17 +66,17 @@ def nav_tab_content():
return _node("nav-tab-content")
-def div(**props) -> core.NestingCtx:
- return tag("div", **props)
+def div(*, style: StyleProp = None, **props) -> core.NestingCtx:
+ return tag("div", style=style, **props)
def link(*, to: str, **props) -> core.NestingCtx:
return _node("Link", to=to, **props)
-def tag(tag_name: str, **props) -> core.NestingCtx:
+def tag(tag_name: str, *, style: StyleProp = None, **props) -> core.NestingCtx:
props["__reactjsxelement"] = tag_name
- return _node("tag", **props)
+ return _node("tag", style=style, **props)
def html(body: str, **props):
@@ -115,11 +127,30 @@ def markdown(
def _node(nodename: str, **props):
+ if style := props.get("style"):
+ selector = style.pop("selector", None)
+ if selector:
+ identifier = "." + core.md5_values(selector)
+ for s, rules in selector.items():
+ _node("css-in-js", selector=s.replace("&", identifier), rules=rules)
+ props["className"] = " ".join(
+ filter(None, (props.get("className"), identifier))
+ )
+ # media = style.pop("@media", None)
node = core.RenderTreeNode(name=nodename, props=props)
node.mount()
return core.NestingCtx(node)
+def styled(css: str) -> core.RenderTreeNode:
+ css = dedent(css).strip()
+ className = "gui-" + core.md5_values(css)
+ selector = "." + className
+ css = css.replace("&", selector)
+ core.add_styles(className, css)
+ return _node("", className=className)
+
+
def text(body: str, **props):
core.RenderTreeNode(
name="pre",
diff --git a/py/gooey_gui/core/__init__.py b/py/gooey_gui/core/__init__.py
index 602aa15..4191848 100644
--- a/py/gooey_gui/core/__init__.py
+++ b/py/gooey_gui/core/__init__.py
@@ -16,7 +16,14 @@
realtime_clear_subs,
md5_values,
)
-from .renderer import RenderTreeNode, NestingCtx, renderer, route, current_root_ctx
+from .renderer import (
+ RenderTreeNode,
+ NestingCtx,
+ renderer,
+ route,
+ current_root_ctx,
+ add_styles,
+)
from .state import (
get_session_state,
set_session_state,
diff --git a/py/gooey_gui/core/renderer.py b/py/gooey_gui/core/renderer.py
index 4157f20..50a16b4 100644
--- a/py/gooey_gui/core/renderer.py
+++ b/py/gooey_gui/core/renderer.py
@@ -23,6 +23,10 @@ def current_root_ctx() -> "NestingCtx":
return threadlocal.root_ctx
+def add_styles(className: str, css: str):
+ threadlocal.styles[className] = css
+
+
class RenderTreeNode(BaseModel):
name: str
props: ReactHTMLProps = {}
@@ -108,17 +112,27 @@ def renderer(
set_query_params(query_params or {})
realtime_clear_subs()
threadlocal.use_state_count = 0
+ threadlocal.styles = {}
while True:
try:
root = RenderTreeNode(name="root")
threadlocal.root_ctx = NestingCtx(root)
with threadlocal.root_ctx:
+ styles_node = RenderTreeNode(
+ name="tag",
+ props=dict(__reactjsxelement="style"),
+ ).mount()
try:
ret = render()
except StopException:
ret = None
except RedirectException as e:
return RedirectResponse(e.url, status_code=e.status_code)
+ if threadlocal.styles:
+ styles_node.props["dangerouslySetInnerHTML"] = {
+ "__html": "\n".join(threadlocal.styles.values())
+ }
+ print(get_subscriptions())
if isinstance(ret, Response):
return ret
return JSONResponse(