Source code for domilite.template
import dataclasses as dc
from collections.abc import Iterable
from collections.abc import Mapping
from typing import Any
from typing import ClassVar
from typing import Generic
from typing import TypeVar
from domilite.accessors import AttributesProperty
from domilite.accessors import ClassesProperty
from domilite.accessors import PrefixAccessor
from domilite.dom_tag import dom_tag
__all__ = ["TagTemplate"]
H = TypeVar("H", bound=dom_tag)
[docs]
@dc.dataclass(init=False, eq=False)
class TagTemplate(Generic[H]):
"""A helper for creating tags.
Holds the tag type as well as attributes for the tag. This can be used
by calling the instance as a function to create a tag, or by calling the
:meth:`update` method to apply the attributes to an existing tag.
"""
#: The tag type
tag: type[H]
attributes: ClassVar[AttributesProperty["TagTemplate"]] = AttributesProperty()
classes: ClassVar[ClassesProperty["TagTemplate"]] = attributes.classes()
data: PrefixAccessor["TagTemplate"] = PrefixAccessor("data")
aria: PrefixAccessor["TagTemplate"] = PrefixAccessor("aria")
hx: PrefixAccessor["TagTemplate"] = PrefixAccessor("hx")
def __init__(
self, tag: type[H], attributes: Mapping[str, str | bool] | None = None, classes: Iterable[str] | None = None
) -> None:
self.tag = tag
if attributes is not None:
self.attributes.update(attributes)
if classes is not None:
self.classes.add(*classes)
def __repr__(self) -> str:
parts = [repr(self.tag)]
if len(self.attributes):
parts.append(f"{len(self.attributes)} attributes")
if len(self.classes):
parts.append(f"{len(self.classes)} classes")
return f"<{self.__class__.__name__} {' '.join(parts)}>"
def __eq__(self, other: object) -> bool:
if isinstance(other, dom_tag):
return self.tag is type(other) and self.attributes == other.attributes
if isinstance(other, TagTemplate):
return self.tag is other.tag and self.attributes == other.attributes
return NotImplemented
def __tag__(self) -> H:
"""Create a tag from the attributes and classes."""
tag = self.tag(**self.attributes)
tag.classes.add(*self.classes)
return tag
[docs]
def __call__(self, *args: Any, **kwds: Any) -> H:
"""Create a tag from the attributes and classes.
This method is a convenience wrapper around :meth:`__tag__` that allows
the tag to be created with additional arguments and keyword arguments passed
to the tag constructor.
"""
tag = self.tag(*args, **{**self.attributes, **kwds})
tag.classes.add(*self.classes)
return tag
def __setitem__(self, name: str, value: str) -> None:
self.attributes[name] = value
def __getitem__(self, name: str) -> str | bool:
return self.attributes[name]
[docs]
def update(self, tag: H) -> H:
"""Update the tag with the attributes and classes."""
tag.classes.add(*self.classes)
tag.attributes.update(self.attributes)
return tag