From 74536d067660d6be4d8d79191834913bc9ac5d96 Mon Sep 17 00:00:00 2001
From: Keith Philpott <keith.philpott@icloud.com>
Date: Thu, 7 Dec 2023 20:17:18 -0800
Subject: [PATCH 1/6] wip

---
 simple_html/__init__.py   | 70 ++++++++++++++++++++++++++++++++++++---
 tests/test_simple_html.py | 47 +++++++++++++++++---------
 2 files changed, 98 insertions(+), 19 deletions(-)

diff --git a/simple_html/__init__.py b/simple_html/__init__.py
index fbae2c4..aec84c2 100644
--- a/simple_html/__init__.py
+++ b/simple_html/__init__.py
@@ -1,6 +1,6 @@
 from html import escape
 from types import GeneratorType
-from typing import Tuple, Union, Dict, List, FrozenSet, Generator, Iterable
+from typing import Tuple, Union, Dict, List, FrozenSet, Generator, Iterable, Any
 
 
 class SafeString:
@@ -12,6 +12,12 @@ def __init__(self, safe_str: str) -> None:
     def __hash__(self) -> int:
         return hash(f"SafeString__{self.safe_str}")
 
+    def __eq__(self, other: Any) -> bool:
+        return isinstance(other, SafeString) and other.safe_str == self.safe_str
+
+    def __repr__(self) -> str:
+        return f"SafeString(safe_str='{self.safe_str}')"
+
 
 Node = Union[
     str,
@@ -102,9 +108,9 @@ def __init__(self, name: str, self_closing: bool = False) -> None:
         self.rendered = f"{self.tag_start}{self.no_children_close}"
 
     def __call__(
-        self,
-        attributes: Dict[Union[SafeString, str], Union[str, SafeString, None]],
-        *children: Node,
+            self,
+            attributes: Dict[Union[SafeString, str], Union[str, SafeString, None]],
+            *children: Node,
     ) -> TagTuple:
         if attributes:
             # in this case this is faster than attrs = "".join([...])
@@ -273,6 +279,62 @@ def _render(nodes: Iterable[Node], strs: List[str]) -> None:
             raise TypeError(f"Got unknown type: {type(node)}")
 
 
+_common_safe_css_props = frozenset({
+    "color", "border", "margin", "font-style", "transform", "background-color", "align-content", "align-items",
+    "align-self", "all", "animation", "animation-delay", "animation-direction", "animation-duration",
+    "animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state",
+    "animation-timing-function", "backface-visibility", "background", "background-attachment", "background-blend-mode",
+    "background-clip", "background-color", "background-image", "background-origin", "background-position",
+    "background-repeat", "background-size", "border", "border-bottom", "border-bottom-color",
+    "border-bottom-left-radius", "border-bottom-right-radius", "border-bottom-style", "border-bottom-width",
+    "border-collapse", "border-color", "border-image", "border-image-outset", "border-image-repeat",
+    "border-image-slice", "border-image-source", "border-image-width", "border-left", "border-left-color",
+    "border-left-style", "border-left-width", "border-radius", "border-right", "border-right-color",
+    "border-right-style", "border-right-width", "border-spacing", "border-style", "border-top", "border-top-color",
+    "border-top-left-radius", "border-top-right-radius", "border-top-style", "border-top-width", "border-width",
+    "bottom", "box-shadow", "box-sizing", "caption-side", "caret-color", "@charset", "clear", "clip", "clip-path",
+    "color", "column-count", "column-fill", "column-gap", "column-rule", "column-rule-color", "column-rule-style",
+    "column-rule-width", "column-span", "column-width", "columns", "content", "counter-increment", "counter-reset",
+    "cursor", "direction", "display", "empty-cells", "filter", "flex", "flex-basis", "flex-direction", "flex-flow",
+    "flex-grow", "flex-shrink", "flex-wrap", "float", "font", "@font-face", "font-family", "font-kerning", "font-size",
+    "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "grid", "grid-area",
+    "grid-auto-columns", "grid-auto-flow", "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
+    "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start", "grid-template",
+    "grid-template-areas", "grid-template-columns", "grid-template-rows", "height", "hyphens", "@import",
+    "justify-content", "@keyframes", "left", "letter-spacing", "line-height", "list-style", "list-style-image",
+    "list-style-position", "list-style-type", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top",
+    "max-height", "max-width", "@media", "min-height", "min-width", "object-fit", "object-position", "opacity", "order",
+    "outline", "outline-color", "outline-offset", "outline-style", "outline-width", "overflow", "overflow-x",
+    "overflow-y", "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", "page-break-after",
+    "page-break-before", "page-break-inside", "perspective", "perspective-origin", "pointer-events", "position",
+    "quotes", "right", "scroll-behavior", "table-layout", "text-align", "text-align-last", "text-decoration",
+    "text-decoration-color", "text-decoration-line", "text-decoration-style", "text-indent", "text-justify",
+    "text-overflow", "text-shadow", "text-transform", "top", "transform", "transform-origin", "transform-style",
+    "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function",
+    "user-select", "vertical-align", "visibility", "white-space", "width", "word-break", "word-spacing", "word-wrap",
+    "writing-mode", "z-index"
+})
+
+
+def render_styles(styles: dict[str | SafeString, str | SafeString]) -> SafeString:
+    ret = ""
+    for k, v in styles.items():
+        if k not in _common_safe_css_props:
+            if isinstance(k, SafeString):
+                k = k.safe_str
+            else:
+                k = escape(k, True)
+
+        if isinstance(v, SafeString):
+            v = v.safe_str
+        else:
+            v = escape(v, True)
+
+        ret += f"{k}:{v};"
+
+    return SafeString(ret)
+
+
 def render(*nodes: Node) -> str:
     results: List[str] = []
     _render(nodes, results)
diff --git a/tests/test_simple_html.py b/tests/test_simple_html.py
index 0d29484..421808e 100644
--- a/tests/test_simple_html.py
+++ b/tests/test_simple_html.py
@@ -19,7 +19,7 @@
     Node,
     DOCTYPE_HTML5,
     render,
-    escape_attribute_key,
+    escape_attribute_key, render_styles,
 )
 
 
@@ -114,8 +114,8 @@ def test_kw_attributes() -> None:
     node = div({"class": "first", "name": "some_name", "style": "color:blue;"}, "okok")
 
     assert (
-        render(node)
-        == '<div class="first" name="some_name" style="color:blue;">okok</div>'
+            render(node)
+            == '<div class="first" name="some_name" style="color:blue;">okok</div>'
     )
 
 
@@ -156,8 +156,8 @@ def test_render_kw_attribute_with_none() -> None:
 def test_can_render_empty() -> None:
     assert render([]) == ""
     assert (
-        render(div({}, [], "hello ", [], span({}, "World!"), []))
-        == "<div>hello <span>World!</span></div>"
+            render(div({}, [], "hello ", [], span({}, "World!"), []))
+            == "<div>hello <span>World!</span></div>"
     )
 
 
@@ -175,24 +175,24 @@ def test_escape_key() -> None:
     assert escape_attribute_key("=") == "&#x3D;"
     assert escape_attribute_key("`") == "&#x60;"
     assert (
-        escape_attribute_key("something with spaces")
-        == "something&nbsp;with&nbsp;spaces"
+            escape_attribute_key("something with spaces")
+            == "something&nbsp;with&nbsp;spaces"
     )
 
 
 def test_render_with_escaped_attributes() -> None:
     assert (
-        render(div({'onmousenter="alert(1)" noop': "1"}))
-        == '<div onmousenter&#x3D;&quot;alert(1)&quot;&nbsp;noop="1"></div>'
+            render(div({'onmousenter="alert(1)" noop': "1"}))
+            == '<div onmousenter&#x3D;&quot;alert(1)&quot;&nbsp;noop="1"></div>'
     )
     assert (
-        render(span({"<script>\"</script>": "\">"}))
-        == '<span &lt;script&gt;&quot;&lt;/script&gt;="&quot;&gt;"></span>'
+            render(span({"<script>\"</script>": "\">"}))
+            == '<span &lt;script&gt;&quot;&lt;/script&gt;="&quot;&gt;"></span>'
     )
     # vals and keys escape slightly differently
     assert (
-        render(div({'onmousenter="alert(1)" noop': 'onmousenter="alert(1)" noop'}))
-        == '<div onmousenter&#x3D;&quot;alert(1)&quot;&nbsp;noop="onmousenter=&quot;alert(1)&quot; noop"></div>'
+            render(div({'onmousenter="alert(1)" noop': 'onmousenter="alert(1)" noop'}))
+            == '<div onmousenter&#x3D;&quot;alert(1)&quot;&nbsp;noop="onmousenter=&quot;alert(1)&quot; noop"></div>'
     )
 
 
@@ -200,6 +200,23 @@ def test_render_with_safestring_attributes() -> None:
     bad_key = 'onmousenter="alert(1)" noop'
     bad_val = "<script></script>"
     assert (
-        render(div({SafeString(bad_key): SafeString(bad_val)}))
-        == f'<div {bad_key}="{bad_val}"></div>'
+            render(div({SafeString(bad_key): SafeString(bad_val)}))
+            == f'<div {bad_key}="{bad_val}"></div>'
     )
+
+
+def test_safestring_repr() -> None:
+    assert repr(SafeString("abc123")) == "SafeString(safe_str='abc123')"
+
+
+def test_safe_string_eq() -> None:
+    assert "abc123" != SafeString("abc123")
+    assert SafeString("a") != SafeString("abc123")
+    assert SafeString("abc123") == SafeString("abc123")
+
+
+def test_render_styles() -> None:
+    assert render_styles({}) == SafeString("")
+    assert render_styles({"abc": "123"}) == SafeString("abc:123;")
+    assert render_styles({"padding": "0",
+                          "margin": "0 10"}) == SafeString("padding:0;margin:0 10;")

From 3fa8a86ac332b2549c2fb9a5d890d93428c29e99 Mon Sep 17 00:00:00 2001
From: Keith Philpott <keith.philpott@icloud.com>
Date: Thu, 7 Dec 2023 20:58:16 -0800
Subject: [PATCH 2/6] tests and docs

---
 README.md                 | 19 +++++++++++++++++++
 pyproject.toml            |  2 +-
 simple_html/__init__.py   |  5 +++--
 tests/test_simple_html.py | 13 +++++++++++--
 4 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index f3a3c50..dabcc38 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,25 @@ render(
 # <div empty-str-attribute="" key-only-attr></div>
 ```
 
+You can render inline css styles with `render_styles`:
+```python
+from simple_html import div, render, render_styles
+
+node = div({"style": render_styles({"min-width": "25px"})}, 
+           "cool")
+
+render(node) # <div style="min-width:25px;">cool</div>
+
+# ints and floats can be values for styles
+styles = render_styles({"padding": 0, "flex-grow": 0.6})
+
+render(
+    div({"style": styles},
+        "wow")
+)
+# <div style="padding:0;flex-grow:0.6;">wow</div>
+```
+
 
 Lists and generators are both valid collections of nodes:
 ```python
diff --git a/pyproject.toml b/pyproject.toml
index 284162d..e8a126e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "simple-html"
-version = "1.1.1"
+version = "1.2.0"
 readme = "README.md"
 description = "Template-less html rendering in Python"
 authors = ["Keith Philpott <fakekeith@example.org>"]
diff --git a/simple_html/__init__.py b/simple_html/__init__.py
index aec84c2..f0a2007 100644
--- a/simple_html/__init__.py
+++ b/simple_html/__init__.py
@@ -316,7 +316,7 @@ def _render(nodes: Iterable[Node], strs: List[str]) -> None:
 })
 
 
-def render_styles(styles: dict[str | SafeString, str | SafeString]) -> SafeString:
+def render_styles(styles: dict[str | SafeString, str | int | float | SafeString]) -> SafeString:
     ret = ""
     for k, v in styles.items():
         if k not in _common_safe_css_props:
@@ -327,8 +327,9 @@ def render_styles(styles: dict[str | SafeString, str | SafeString]) -> SafeStrin
 
         if isinstance(v, SafeString):
             v = v.safe_str
-        else:
+        elif isinstance(v, str):
             v = escape(v, True)
+        # note that ints and floats pass through these condition checks
 
         ret += f"{k}:{v};"
 
diff --git a/tests/test_simple_html.py b/tests/test_simple_html.py
index 421808e..c75178f 100644
--- a/tests/test_simple_html.py
+++ b/tests/test_simple_html.py
@@ -217,6 +217,15 @@ def test_safe_string_eq() -> None:
 
 def test_render_styles() -> None:
     assert render_styles({}) == SafeString("")
-    assert render_styles({"abc": "123"}) == SafeString("abc:123;")
-    assert render_styles({"padding": "0",
+    assert render_styles({"abc": 123.45}) == SafeString("abc:123.45;")
+    assert render_styles({"padding": 0,
                           "margin": "0 10"}) == SafeString("padding:0;margin:0 10;")
+
+    assert render(div({"style": render_styles({"min-width": "25px"})},
+                      "cool")) == '<div style="min-width:25px;">cool</div>'
+
+
+def test_render_styles_escapes() -> None:
+    assert render_styles({'"><': "><>\""}) == SafeString(
+        safe_str='&quot;&gt;&lt;:&gt;&lt;&gt;&quot;;'
+    )

From 197cc8995dc964fc7a005ae9fada8b07331ba06b Mon Sep 17 00:00:00 2001
From: Keith Philpott <keith.philpott@icloud.com>
Date: Thu, 7 Dec 2023 21:01:46 -0800
Subject: [PATCH 3/6] wip

---
 simple_html/__init__.py | 260 +++++++++++++++++++++++++++++++++-------
 1 file changed, 219 insertions(+), 41 deletions(-)

diff --git a/simple_html/__init__.py b/simple_html/__init__.py
index f0a2007..3f98bf5 100644
--- a/simple_html/__init__.py
+++ b/simple_html/__init__.py
@@ -108,9 +108,9 @@ def __init__(self, name: str, self_closing: bool = False) -> None:
         self.rendered = f"{self.tag_start}{self.no_children_close}"
 
     def __call__(
-            self,
-            attributes: Dict[Union[SafeString, str], Union[str, SafeString, None]],
-            *children: Node,
+        self,
+        attributes: Dict[Union[SafeString, str], Union[str, SafeString, None]],
+        *children: Node,
     ) -> TagTuple:
         if attributes:
             # in this case this is faster than attrs = "".join([...])
@@ -279,44 +279,222 @@ def _render(nodes: Iterable[Node], strs: List[str]) -> None:
             raise TypeError(f"Got unknown type: {type(node)}")
 
 
-_common_safe_css_props = frozenset({
-    "color", "border", "margin", "font-style", "transform", "background-color", "align-content", "align-items",
-    "align-self", "all", "animation", "animation-delay", "animation-direction", "animation-duration",
-    "animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state",
-    "animation-timing-function", "backface-visibility", "background", "background-attachment", "background-blend-mode",
-    "background-clip", "background-color", "background-image", "background-origin", "background-position",
-    "background-repeat", "background-size", "border", "border-bottom", "border-bottom-color",
-    "border-bottom-left-radius", "border-bottom-right-radius", "border-bottom-style", "border-bottom-width",
-    "border-collapse", "border-color", "border-image", "border-image-outset", "border-image-repeat",
-    "border-image-slice", "border-image-source", "border-image-width", "border-left", "border-left-color",
-    "border-left-style", "border-left-width", "border-radius", "border-right", "border-right-color",
-    "border-right-style", "border-right-width", "border-spacing", "border-style", "border-top", "border-top-color",
-    "border-top-left-radius", "border-top-right-radius", "border-top-style", "border-top-width", "border-width",
-    "bottom", "box-shadow", "box-sizing", "caption-side", "caret-color", "@charset", "clear", "clip", "clip-path",
-    "color", "column-count", "column-fill", "column-gap", "column-rule", "column-rule-color", "column-rule-style",
-    "column-rule-width", "column-span", "column-width", "columns", "content", "counter-increment", "counter-reset",
-    "cursor", "direction", "display", "empty-cells", "filter", "flex", "flex-basis", "flex-direction", "flex-flow",
-    "flex-grow", "flex-shrink", "flex-wrap", "float", "font", "@font-face", "font-family", "font-kerning", "font-size",
-    "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "grid", "grid-area",
-    "grid-auto-columns", "grid-auto-flow", "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
-    "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start", "grid-template",
-    "grid-template-areas", "grid-template-columns", "grid-template-rows", "height", "hyphens", "@import",
-    "justify-content", "@keyframes", "left", "letter-spacing", "line-height", "list-style", "list-style-image",
-    "list-style-position", "list-style-type", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top",
-    "max-height", "max-width", "@media", "min-height", "min-width", "object-fit", "object-position", "opacity", "order",
-    "outline", "outline-color", "outline-offset", "outline-style", "outline-width", "overflow", "overflow-x",
-    "overflow-y", "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", "page-break-after",
-    "page-break-before", "page-break-inside", "perspective", "perspective-origin", "pointer-events", "position",
-    "quotes", "right", "scroll-behavior", "table-layout", "text-align", "text-align-last", "text-decoration",
-    "text-decoration-color", "text-decoration-line", "text-decoration-style", "text-indent", "text-justify",
-    "text-overflow", "text-shadow", "text-transform", "top", "transform", "transform-origin", "transform-style",
-    "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function",
-    "user-select", "vertical-align", "visibility", "white-space", "width", "word-break", "word-spacing", "word-wrap",
-    "writing-mode", "z-index"
-})
-
-
-def render_styles(styles: dict[str | SafeString, str | int | float | SafeString]) -> SafeString:
+_common_safe_css_props = frozenset(
+    {
+        "color",
+        "border",
+        "margin",
+        "font-style",
+        "transform",
+        "background-color",
+        "align-content",
+        "align-items",
+        "align-self",
+        "all",
+        "animation",
+        "animation-delay",
+        "animation-direction",
+        "animation-duration",
+        "animation-fill-mode",
+        "animation-iteration-count",
+        "animation-name",
+        "animation-play-state",
+        "animation-timing-function",
+        "backface-visibility",
+        "background",
+        "background-attachment",
+        "background-blend-mode",
+        "background-clip",
+        "background-color",
+        "background-image",
+        "background-origin",
+        "background-position",
+        "background-repeat",
+        "background-size",
+        "border",
+        "border-bottom",
+        "border-bottom-color",
+        "border-bottom-left-radius",
+        "border-bottom-right-radius",
+        "border-bottom-style",
+        "border-bottom-width",
+        "border-collapse",
+        "border-color",
+        "border-image",
+        "border-image-outset",
+        "border-image-repeat",
+        "border-image-slice",
+        "border-image-source",
+        "border-image-width",
+        "border-left",
+        "border-left-color",
+        "border-left-style",
+        "border-left-width",
+        "border-radius",
+        "border-right",
+        "border-right-color",
+        "border-right-style",
+        "border-right-width",
+        "border-spacing",
+        "border-style",
+        "border-top",
+        "border-top-color",
+        "border-top-left-radius",
+        "border-top-right-radius",
+        "border-top-style",
+        "border-top-width",
+        "border-width",
+        "bottom",
+        "box-shadow",
+        "box-sizing",
+        "caption-side",
+        "caret-color",
+        "@charset",
+        "clear",
+        "clip",
+        "clip-path",
+        "color",
+        "column-count",
+        "column-fill",
+        "column-gap",
+        "column-rule",
+        "column-rule-color",
+        "column-rule-style",
+        "column-rule-width",
+        "column-span",
+        "column-width",
+        "columns",
+        "content",
+        "counter-increment",
+        "counter-reset",
+        "cursor",
+        "direction",
+        "display",
+        "empty-cells",
+        "filter",
+        "flex",
+        "flex-basis",
+        "flex-direction",
+        "flex-flow",
+        "flex-grow",
+        "flex-shrink",
+        "flex-wrap",
+        "float",
+        "font",
+        "@font-face",
+        "font-family",
+        "font-kerning",
+        "font-size",
+        "font-size-adjust",
+        "font-stretch",
+        "font-style",
+        "font-variant",
+        "font-weight",
+        "grid",
+        "grid-area",
+        "grid-auto-columns",
+        "grid-auto-flow",
+        "grid-auto-rows",
+        "grid-column",
+        "grid-column-end",
+        "grid-column-gap",
+        "grid-column-start",
+        "grid-gap",
+        "grid-row",
+        "grid-row-end",
+        "grid-row-gap",
+        "grid-row-start",
+        "grid-template",
+        "grid-template-areas",
+        "grid-template-columns",
+        "grid-template-rows",
+        "height",
+        "hyphens",
+        "@import",
+        "justify-content",
+        "@keyframes",
+        "left",
+        "letter-spacing",
+        "line-height",
+        "list-style",
+        "list-style-image",
+        "list-style-position",
+        "list-style-type",
+        "margin",
+        "margin-bottom",
+        "margin-left",
+        "margin-right",
+        "margin-top",
+        "max-height",
+        "max-width",
+        "@media",
+        "min-height",
+        "min-width",
+        "object-fit",
+        "object-position",
+        "opacity",
+        "order",
+        "outline",
+        "outline-color",
+        "outline-offset",
+        "outline-style",
+        "outline-width",
+        "overflow",
+        "overflow-x",
+        "overflow-y",
+        "padding",
+        "padding-bottom",
+        "padding-left",
+        "padding-right",
+        "padding-top",
+        "page-break-after",
+        "page-break-before",
+        "page-break-inside",
+        "perspective",
+        "perspective-origin",
+        "pointer-events",
+        "position",
+        "quotes",
+        "right",
+        "scroll-behavior",
+        "table-layout",
+        "text-align",
+        "text-align-last",
+        "text-decoration",
+        "text-decoration-color",
+        "text-decoration-line",
+        "text-decoration-style",
+        "text-indent",
+        "text-justify",
+        "text-overflow",
+        "text-shadow",
+        "text-transform",
+        "top",
+        "transform",
+        "transform-origin",
+        "transform-style",
+        "transition",
+        "transition-delay",
+        "transition-duration",
+        "transition-property",
+        "transition-timing-function",
+        "user-select",
+        "vertical-align",
+        "visibility",
+        "white-space",
+        "width",
+        "word-break",
+        "word-spacing",
+        "word-wrap",
+        "writing-mode",
+        "z-index",
+    }
+)
+
+
+def render_styles(
+    styles: dict[Union[str, SafeString], Union[str | int | float | SafeString]]
+) -> SafeString:
     ret = ""
     for k, v in styles.items():
         if k not in _common_safe_css_props:

From efa1a29073612e66c4d1c5ec914fd1661c77a74d Mon Sep 17 00:00:00 2001
From: Keith Philpott <keith.philpott@icloud.com>
Date: Thu, 7 Dec 2023 21:02:53 -0800
Subject: [PATCH 4/6] fix

---
 simple_html/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/simple_html/__init__.py b/simple_html/__init__.py
index 3f98bf5..c93017c 100644
--- a/simple_html/__init__.py
+++ b/simple_html/__init__.py
@@ -493,7 +493,7 @@ def _render(nodes: Iterable[Node], strs: List[str]) -> None:
 
 
 def render_styles(
-    styles: dict[Union[str, SafeString], Union[str | int | float | SafeString]]
+    styles: dict[Union[str, SafeString], Union[str, int, float, SafeString]]
 ) -> SafeString:
     ret = ""
     for k, v in styles.items():

From bf25960247fd7cff4078fe80b636c0d65d60b775 Mon Sep 17 00:00:00 2001
From: Keith Philpott <keith.philpott@icloud.com>
Date: Thu, 7 Dec 2023 21:10:59 -0800
Subject: [PATCH 5/6] fix Dict type

---
 simple_html/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/simple_html/__init__.py b/simple_html/__init__.py
index c93017c..b36e311 100644
--- a/simple_html/__init__.py
+++ b/simple_html/__init__.py
@@ -493,7 +493,7 @@ def _render(nodes: Iterable[Node], strs: List[str]) -> None:
 
 
 def render_styles(
-    styles: dict[Union[str, SafeString], Union[str, int, float, SafeString]]
+    styles: Dict[Union[str, SafeString], Union[str, int, float, SafeString]]
 ) -> SafeString:
     ret = ""
     for k, v in styles.items():

From fe6395d912ea7912203179baa4d19bf8eff990b4 Mon Sep 17 00:00:00 2001
From: Keith Philpott <keith.philpott@icloud.com>
Date: Thu, 7 Dec 2023 21:23:36 -0800
Subject: [PATCH 6/6] update docs

---
 README.md | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index dabcc38..d589b16 100644
--- a/README.md
+++ b/README.md
@@ -65,12 +65,16 @@ You can render inline css styles with `render_styles`:
 ```python
 from simple_html import div, render, render_styles
 
-node = div({"style": render_styles({"min-width": "25px"})}, 
-           "cool")
+styles = render_styles({"min-width": "25px"})
+
+render(
+    div({"style": styles}, 
+        "cool")
+)
+# <div style="min-width:25px;">cool</div>
 
-render(node) # <div style="min-width:25px;">cool</div>
 
-# ints and floats can be values for styles
+# ints and floats are legal values
 styles = render_styles({"padding": 0, "flex-grow": 0.6})
 
 render(