Skip to content

Base Component

components.base

Component

Unified DOM-like base class for all UI elements.

The component class represents a node in the UI tree. It can be instantiated and manipulated dynamically before being rendered into HTML.

Attributes:

Name Type Description
uid str

Uniquely identifies the element. Essential for HTMX targeting.

classes str

Tailwind utility classes applied to the component.

role List[str]

Access control roles. Components automatically prune if the current user lacks the required role.

children List[Component]

Nested child UI components.

key str

Binds the component to a context dictionary key or model field.

static_value Any

Bypasses context value lookup to force a static render value.

url Callable | str

An explicit URL, or a callable resolving to a URL.

Source code in components/base.py
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
class Component:
    """
    Unified DOM-like base class for all UI elements.

    The component class represents a node in the UI tree. It can be instantiated 
    and manipulated dynamically before being rendered into HTML.

    Attributes:
        uid (str): Uniquely identifies the element. Essential for HTMX targeting.
        classes (str): Tailwind utility classes applied to the component.
        role (List[str]): Access control roles. Components automatically prune if 
                          the current user lacks the required role.
        children (List[Component]): Nested child UI components.
        key (str): Binds the component to a context dictionary key or model field.
        static_value (Any): Bypasses context value lookup to force a static render value.
        url (Callable | str): An explicit URL, or a callable resolving to a URL.
    """

    def __init__(
        self,
        uid: str = "",
        classes: str = "",
        role: List[str] = None,
        children: List["Component"] = None,
        key: str | None = None,
        static_value: Any = None,
        url: Callable | str | None = None,
    ):
        self.uid = uid
        self.classes = classes
        self.role = role or []
        # Making children a standard attribute makes DOM operations universally safe
        self.children = children or []
        self.key = key
        self.static_value = static_value
        self.url = url

    # --- Security & Authorization ---
    def check(self, request=None, **kwargs) -> bool:
        """
        Evaluate if the current request satisfies the component's `role` requirements.
        If this returns False, the component and all descendants are excluded from rendering.
        """
        if not request or not self.role:
            return True
        user = request.user
        if not user.is_authenticated:
            return False
        if user.is_superuser:
            return True
        return user.role.name in self.role

    # --- HTML Rendering ---
    def render_html(self, **kwargs) -> str:
        tree = self.build()
        if tree is not self:
            return tree.render(**kwargs)
        return ""

    def render(self, **kwargs) -> str:
        """
        The primary entry point for converting the component tree into an HTML string.
        Safely enforces role checks before delegating to `render_html`.
        """
        request = kwargs.get("request")
        if not self.check(request=request):
            return ""
        return self.render_html(**kwargs)

    def get_children(self) -> List["Component"]:
        return self.children

    def render_partial(self, target_uid: str, **kwargs) -> Optional[str]:
        """
        Recursively scans the tree for a node matching the `target_uid`.
        If found, performs an isolated render of only that node and its children.
        """
        if self.uid == target_uid:
            return self.render(**kwargs)
        for child in self.get_children():
            result = child.render_partial(target_uid, **kwargs)
            if result is not None:
                return result
        return None

    # --- DOM-style Traversal & Mutation ---
    def find(self, target_uid: str) -> Optional["Component"]:
        """Search this node and all descendants for a UID."""
        if not target_uid:
            return None
        if self.uid == target_uid:
            return self
        for child in self.get_children():
            found = child.find(target_uid)
            if found:
                return found
        return None

    def find_parent(self, target_uid: str) -> Optional["Component"]:
        """Find the immediate parent of a specific UID."""
        for child in self.get_children():
            if child.uid == target_uid:
                return self
            found = child.find_parent(target_uid)
            if found:
                return found
        return None

    def insert_before(self, target_uid: str, new_component: "Component") -> bool:
        target_parent = self.find_parent(target_uid)
        if not target_parent:
            raise ValueError("Parent not found")
        idx = None
        for i, child in enumerate(target_parent.get_children()):
            if child.uid == target_uid:
                idx = i
                break
        if idx is None:
            raise ValueError("Why do dis")
        target_parent.children.insert(idx, new_component)
        return True

    def insert_after(self, target_uid: str, new_component: "Component") -> bool:
        target_parent = self.find_parent(target_uid)
        if not target_parent:
            raise ValueError("Target Parent not found")
        idx = None
        for i, child in enumerate(target_parent.get_children()):
            if child.uid == target_uid:
                idx = i
                break
        if idx is None:
            raise ValueError("Sibling not found")
        target_parent.children.insert(idx + 1, new_component)
        return True

    def append(self, target_uid: str, new_component: "Component") -> bool:
        """Find a target node in the tree and append a child to it."""
        target = self.find(target_uid)
        if target is not None and hasattr(target, "children"):
            target.children.append(new_component)
            return True
        return False

    def remove(self, target_uid: str) -> bool:
        """Find the parent of a target node and remove the target from its children."""
        parent = self.find_parent(target_uid)
        if parent is not None and hasattr(parent, "children"):
            parent.children = [c for c in parent.children if c.uid != target_uid]
            return True
        return False

    def replace(self, target_uid: str, new_component: "Component") -> bool:
        """Find a target node and replace it completely in its parent's list."""
        parent = self.find_parent(target_uid)
        if parent is not None and hasattr(parent, "children"):
            for index, child in enumerate(parent.children):
                if child.uid == target_uid:
                    parent.children[index] = new_component
                    return True
        return False

    def build(self) -> "Component":
        """
        Hook for dynamic structures (like Layouts or Forms) to construct their 
        internal node hierarchy immediately before rendering.
        Returns the root component of the built tree (usually `self`).
        """
        return self

    def get_root_value(self, key: str, **kwargs):
        path: list[str] = key.split(".")
        if not (len(path) > 0):
            return None

        path.reverse()
        return kwargs.get(path.pop(), None)

    def get_value(self, **kwargs):
        if self.static_value is not None:
            return self.static_value
        key = self.key
        if self.key is None:
            key = "object"

        value = self.get_root_value(key, **kwargs)
        if value is None:
            key = f"object.{key}"
            value = self.get_root_value(key, **kwargs)

        path = key.split(".")
        for key in path[1:]:
            if isinstance(value, dict):
                value = value.get(key, None)
            else:
                value = getattr(value, key, None)
            if isinstance(value, models.Manager):
                value = list(value.all())
            elif callable(value):
                value = value()

        return value

    def get_url(self, **kwargs):
        if self.url is None:
            return None
        if hasattr(self.url, "__call__"):
            obj = self.get_value(**kwargs)
            if obj is not None:
                return self.url(obj)
            else:
                return self.url()
        return self.url

append(target_uid, new_component)

Find a target node in the tree and append a child to it.

Source code in components/base.py
141
142
143
144
145
146
147
def append(self, target_uid: str, new_component: "Component") -> bool:
    """Find a target node in the tree and append a child to it."""
    target = self.find(target_uid)
    if target is not None and hasattr(target, "children"):
        target.children.append(new_component)
        return True
    return False

build()

Hook for dynamic structures (like Layouts or Forms) to construct their internal node hierarchy immediately before rendering. Returns the root component of the built tree (usually self).

Source code in components/base.py
167
168
169
170
171
172
173
def build(self) -> "Component":
    """
    Hook for dynamic structures (like Layouts or Forms) to construct their 
    internal node hierarchy immediately before rendering.
    Returns the root component of the built tree (usually `self`).
    """
    return self

check(request=None, **kwargs)

Evaluate if the current request satisfies the component's role requirements. If this returns False, the component and all descendants are excluded from rendering.

Source code in components/base.py
43
44
45
46
47
48
49
50
51
52
53
54
55
def check(self, request=None, **kwargs) -> bool:
    """
    Evaluate if the current request satisfies the component's `role` requirements.
    If this returns False, the component and all descendants are excluded from rendering.
    """
    if not request or not self.role:
        return True
    user = request.user
    if not user.is_authenticated:
        return False
    if user.is_superuser:
        return True
    return user.role.name in self.role

find(target_uid)

Search this node and all descendants for a UID.

Source code in components/base.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def find(self, target_uid: str) -> Optional["Component"]:
    """Search this node and all descendants for a UID."""
    if not target_uid:
        return None
    if self.uid == target_uid:
        return self
    for child in self.get_children():
        found = child.find(target_uid)
        if found:
            return found
    return None

find_parent(target_uid)

Find the immediate parent of a specific UID.

Source code in components/base.py
103
104
105
106
107
108
109
110
111
def find_parent(self, target_uid: str) -> Optional["Component"]:
    """Find the immediate parent of a specific UID."""
    for child in self.get_children():
        if child.uid == target_uid:
            return self
        found = child.find_parent(target_uid)
        if found:
            return found
    return None

remove(target_uid)

Find the parent of a target node and remove the target from its children.

Source code in components/base.py
149
150
151
152
153
154
155
def remove(self, target_uid: str) -> bool:
    """Find the parent of a target node and remove the target from its children."""
    parent = self.find_parent(target_uid)
    if parent is not None and hasattr(parent, "children"):
        parent.children = [c for c in parent.children if c.uid != target_uid]
        return True
    return False

render(**kwargs)

The primary entry point for converting the component tree into an HTML string. Safely enforces role checks before delegating to render_html.

Source code in components/base.py
64
65
66
67
68
69
70
71
72
def render(self, **kwargs) -> str:
    """
    The primary entry point for converting the component tree into an HTML string.
    Safely enforces role checks before delegating to `render_html`.
    """
    request = kwargs.get("request")
    if not self.check(request=request):
        return ""
    return self.render_html(**kwargs)

render_partial(target_uid, **kwargs)

Recursively scans the tree for a node matching the target_uid. If found, performs an isolated render of only that node and its children.

Source code in components/base.py
77
78
79
80
81
82
83
84
85
86
87
88
def render_partial(self, target_uid: str, **kwargs) -> Optional[str]:
    """
    Recursively scans the tree for a node matching the `target_uid`.
    If found, performs an isolated render of only that node and its children.
    """
    if self.uid == target_uid:
        return self.render(**kwargs)
    for child in self.get_children():
        result = child.render_partial(target_uid, **kwargs)
        if result is not None:
            return result
    return None

replace(target_uid, new_component)

Find a target node and replace it completely in its parent's list.

Source code in components/base.py
157
158
159
160
161
162
163
164
165
def replace(self, target_uid: str, new_component: "Component") -> bool:
    """Find a target node and replace it completely in its parent's list."""
    parent = self.find_parent(target_uid)
    if parent is not None and hasattr(parent, "children"):
        for index, child in enumerate(parent.children):
            if child.uid == target_uid:
                parent.children[index] = new_component
                return True
    return False