Skip to content

Commit

Permalink
fix: Correctly handle void elements
Browse files Browse the repository at this point in the history
- Ref: #54
  • Loading branch information
paveldedik committed Jun 2, 2024
1 parent 9ffa2c8 commit ce4eea7
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 16 deletions.
6 changes: 3 additions & 3 deletions ludic/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class BaseElement(metaclass=ABCMeta):
html_header: ClassVar[str | None] = None
html_name: ClassVar[str | None] = None

always_pair: ClassVar[bool] = False
void_element: ClassVar[bool] = False
formatter: ClassVar[FormatContext] = FormatContext("element_formatter")

classes: ClassVar[Sequence[str]] = []
Expand Down Expand Up @@ -226,10 +226,10 @@ def to_html(self) -> str:
attributes_str = dom._format_attributes(classes, is_html=True)
element_tag += f" {attributes_str}"

if dom.children or dom.always_pair:
if dom.children or not dom.void_element:
element_tag += f">{children_str}</{dom.html_name}>"
else:
element_tag += " />"
element_tag += ">"

return element_tag

Expand Down
2 changes: 1 addition & 1 deletion ludic/catalog/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Loading(Component[AnyChildren, GlobalAttrs]):
@override
def render(self) -> div:
return div(
div(div(""), div(""), div(""), div(""), classes=["lds-ellipsis"]),
div(div(), div(), div(), div(), classes=["lds-ellipsis"]),
**self.attrs_for(div),
)

Expand Down
22 changes: 16 additions & 6 deletions ludic/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class a(Element[AnyChildren, HyperlinkAttrs]):


class br(Element[NoChildren, GlobalAttrs]):
void_element = True
html_name = "br"


Expand Down Expand Up @@ -163,6 +164,7 @@ class section(Element[AnyChildren, GlobalAttrs]):


class input(Element[NoChildren, InputAttrs]):
void_element = True
html_name = "input"


Expand All @@ -187,7 +189,6 @@ class select(Element[AnyChildren, SelectAttrs]):


class textarea(Element[PrimitiveChildren, TextAreaAttrs]):
always_pair = True
html_name = "textarea"


Expand All @@ -200,6 +201,7 @@ class form(Element[AnyChildren, FormAttrs]):


class img(Element[NoChildren, ImgAttrs]):
void_element = True
html_name = "img"


Expand Down Expand Up @@ -319,7 +321,8 @@ class title(Element[PrimitiveChildren, NoAttrs]):
html_name = "title"


class link(Element[PrimitiveChildren, HeadLinkAttrs]):
class link(Element[NoChildren, HeadLinkAttrs]):
void_element = True
html_name = "link"


Expand Down Expand Up @@ -403,15 +406,14 @@ def render(self) -> BaseElement:

class script(Element[PrimitiveChildren, ScriptAttrs]):
html_name = "script"
always_pair = True


class noscript(Element[AnyChildren, GlobalAttrs]):
html_name = "noscript"
always_pair = True


class meta(Element[PrimitiveChildren, MetaAttrs]):
class meta(Element[NoChildren, MetaAttrs]):
void_element = True
html_name = "meta"


Expand All @@ -433,7 +435,6 @@ class html(ElementStrict[head, body, HtmlTagAttrs]):


class iframe(Element[NoChildren, IframeAttrs]):
always_pair = True
html_name = "iframe"


Expand All @@ -450,6 +451,7 @@ class caption(Element[AnyChildren, GlobalAttrs]):


class col(Element[NoChildren, ColAttrs]):
void_element = True
html_name = "col"


Expand All @@ -458,6 +460,7 @@ class colgroup(Element[AnyChildren, GlobalAttrs]):


class area(Element[NoChildren, AreaAttrs]):
void_element = True
html_name = "area"


Expand All @@ -466,6 +469,7 @@ class aside(Element[AnyChildren, GlobalAttrs]):


class source(Element[NoChildren, SourceAttrs]):
void_element = True
html_name = "source"


Expand All @@ -474,6 +478,7 @@ class audio(Element[AnyChildren, AudioAttrs]):


class base(Element[NoChildren, BaseAttrs]):
void_element = True
html_name = "base"


Expand Down Expand Up @@ -510,6 +515,7 @@ class dialog(Element[AnyChildren, DialogAttrs]):


class embed(Element[NoChildren, EmbedAttrs]):
void_element = True
html_name = "embed"


Expand All @@ -526,6 +532,7 @@ class hrgroup(Element[AnyChildren, GlobalAttrs]):


class hr(Element[NoChildren, GlobalAttrs]):
void_element = True
html_name = "hr"


Expand Down Expand Up @@ -554,6 +561,7 @@ class object(Element[AnyChildren, ObjectAttrs]):


class param(Element[NoChildren, ParamAttrs]):
void_element = True
html_name = "param"


Expand Down Expand Up @@ -610,6 +618,7 @@ class time(Element[AnyChildren, TimeAttrs]):


class track(Element[NoChildren, TrackAttrs]):
void_element = True
html_name = "track"


Expand All @@ -622,4 +631,5 @@ class video(Element[AnyChildren, VideoAttrs]):


class wbr(Element[NoChildren, GlobalAttrs]):
void_element = True
html_name = "wbr"
2 changes: 1 addition & 1 deletion ludic/styles/themes.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Header:
"""Header for a theme."""

size: BaseSize = SizeClamp(1.5, 2, 2.5)
anchor: bool = True
anchor: bool = False


@dataclass
Expand Down
4 changes: 2 additions & 2 deletions tests/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def test_form_fields() -> None:
assert form.to_html() == (
'<form class="form stack">'
'<div class="form-field">'
'<input value="Name" name="name" id="name" />'
'<input value="Name" name="name" id="name">'
"</div>"
'<div class="form-field">'
'<textarea name="description" id="description">Description</textarea>'
Expand All @@ -137,7 +137,7 @@ def test_form_fields() -> None:
'<form class="form stack">'
'<div class="form-field">'
'<label for="name">Foo</label>'
'<input value="Name" name="name" id="name" />'
'<input value="Name" name="name" id="name">'
"</div>"
'<div class="form-field">'
'<label for="description">Bar</label>'
Expand Down
11 changes: 8 additions & 3 deletions tests/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
button,
div,
i,
input,
label,
p,
script,
Expand All @@ -20,17 +21,21 @@

def test_empty_element() -> None:
dom = div()
assert dom.to_html() == "<div />"
assert dom.to_html() == "<div></div>"
assert dom.to_string() == "<div />"

dom2 = p("")
dom2 = p()
assert dom2.to_html() == "<p></p>"
assert dom2.to_string() == "<p></p>"
assert dom2.to_string() == "<p />"

dom3 = script()
assert dom3.to_html() == "<script></script>"
assert dom3.to_string() == "<script />"

dom4 = input()
assert dom4.to_html() == "<input>"
assert dom4.to_string() == "<input />"


def test_html_paragraph() -> None:
paragraph = p(f"Hello, World! {b("Something bold")} and {i("Something italic")}")
Expand Down

0 comments on commit ce4eea7

Please sign in to comment.