Skip to content

Commit 0c4d7ab

Browse files
Refine Attribute Resolution (#97)
* Wrap up low level placeholder handling into PlaceholderConfig helper class. * Draft version of special class handling with merging and distinct sequence vs dict typing. * Use True instead of None since we only init from literal. * Add style equivalent to class merging. * Remove old style processing code. * Add mixed class types back in but without sequence nesting. * Allow attributes created via aria dict to clear literal attributes. * Allow attributes created via data dict to clear literal attributes. * Move special class and style handling state and logic into helper classes. * Expand style testing. * Sp. * Try to uniform design with prior processor. * Make things *right. * Rename to expander to accommodate allocator, pull up into main resolution. * Re-format. * Remove excess docstrings. * Adjust docs, drop classnames helper. * Ignore None to easily support passing through a kwarg with a None default. * Allow special attributes to be None to allow pass-through from components or template functions. * Try to add all forms to class attr smoketest. * Restrict each class attr to either toggle or add list for now. * Drop support for booleans in interpolated class attributes. * Add space separated classes to smoketest.
1 parent ccf05aa commit 0c4d7ab

File tree

6 files changed

+342
-246
lines changed

6 files changed

+342
-246
lines changed

README.md

Lines changed: 24 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -130,23 +130,29 @@ button = html(t'<button class="{classes}">Click me</button>')
130130
# <button class="btn btn-primary active">Click me</button>
131131
```
132132

133-
For flexibility, you can also provide a list of strings, dictionaries, or a mix
134-
of both:
133+
The `class` attribute can also be a dictionary to toggle classes on or off:
135134

136135
```python
137-
classes = ["btn", "btn-primary", {"active": True}, None, False and "disabled"]
138-
button = html(t'<button class="{classes}">Click me</button>')
136+
classes = {"active": True, "btn-primary": True}
137+
button = html(t'<button class={classes}>Click me</button>')
139138
# <button class="btn btn-primary active">Click me</button>
140139
```
141140

142-
See the
143-
[`classnames()`](https://github.com/t-strings/tdom/blob/main/tdom/classnames_test.py)
144-
helper function for more information on how class names are combined.
141+
The `class` attribute can be specified more than once. The values are merged
142+
from left to right. A common use case would be to update and/or extend default
143+
classes:
144+
145+
```python
146+
classes = {"btn-primary": True, "btn-secondary": False}
147+
button = html(t'<button class="btn btn-secondary" class={classes}>Click me</button>')
148+
assert str(button) == '<button class="btn btn-primary">Click me</button>'
149+
```
145150

146151
#### The `style` Attribute
147152

148-
In addition to strings, you can also provide a dictionary of CSS properties and
149-
values for the `style` attribute:
153+
The `style` attribute has special handling to make it easy to combine multiple
154+
styles from different sources. The simplest way is to provide a dictionary of
155+
CSS properties and values for the `style` attribute:
150156

151157
```python
152158
# Style attributes from dictionaries
@@ -155,6 +161,14 @@ styled = html(t"<p style={styles}>Important text</p>")
155161
# <p style="color: red; font-weight: bold; margin: 10px">Important text</p>
156162
```
157163

164+
Style attributes can also be merged to extend a base style:
165+
166+
```python
167+
add_styles = {"font-weight": "bold"}
168+
para = html(t'<p style="color: red" style={add_styles}>Important text</p>')
169+
assert str(para) == '<p style="color: red; font-weight: bold">Important text</p>'
170+
```
171+
158172
#### The `data` and `aria` Attributes
159173

160174
The `data` and `aria` attributes also have special handling to convert
@@ -195,7 +209,7 @@ Special attributes likes `class` behave as expected when combined with
195209
spreading:
196210

197211
```python
198-
classes = ["btn", {"active": True}]
212+
classes = {"btn": True, "active": True}
199213
attrs = {"class": classes, "id": "act_now", "data": {"wow": "such-attr"}}
200214
button = html(t'<button {attrs}>Click me</button>')
201215
# <button class="btn active" id="act_now" data-wow="such-attr">Click me</button>
@@ -539,42 +553,6 @@ anywhere that expects an object with HTML representation. Converting a node to a
539553
string (via `str()` or `print()`) automatically renders it as HTML with proper
540554
escaping.
541555

542-
#### The `classnames()` Helper
543-
544-
The `classnames()` function provides a flexible way to build class name strings
545-
from various input types. It's particularly useful when you need to
546-
conditionally include classes:
547-
548-
```python
549-
from tdom import classnames
550-
551-
# Combine strings
552-
assert classnames("btn", "btn-primary") == "btn btn-primary"
553-
554-
# Use dictionaries for conditional classes
555-
is_active = True
556-
is_disabled = False
557-
assert classnames("btn", {
558-
"btn-active": is_active,
559-
"btn-disabled": is_disabled
560-
}) == "btn btn-active"
561-
562-
# Mix lists, dicts, and strings
563-
assert classnames(
564-
"btn",
565-
["btn-large", "rounded"],
566-
{"btn-primary": True, "btn-secondary": False},
567-
None, # Ignored
568-
False # Ignored
569-
) == "btn btn-large rounded btn-primary"
570-
571-
# Nested lists are flattened
572-
assert classnames(["btn", ["btn-primary", ["active"]]]) == "btn btn-primary active"
573-
```
574-
575-
This function is automatically used when processing `class` attributes in
576-
templates, so you can pass any of these input types directly in your t-strings.
577-
578556
#### Utilities
579557

580558
The `tdom` package includes several utility functions for working with

tdom/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
from markupsafe import Markup, escape
22

3-
from .classnames import classnames
43
from .nodes import Comment, DocumentType, Element, Fragment, Node, Text
54
from .processor import html
65

76
# We consider `Markup` and `escape` to be part of this module's public API
87

98
__all__ = [
10-
"classnames",
119
"Comment",
1210
"DocumentType",
1311
"Element",

tdom/classnames.py

Lines changed: 0 additions & 50 deletions
This file was deleted.

tdom/classnames_test.py

Lines changed: 0 additions & 78 deletions
This file was deleted.

0 commit comments

Comments
 (0)