Skip to content

Commit 53bcbf8

Browse files
adjust how attrs/props with True/False are rendered (#58)
1 parent 0c4a379 commit 53bcbf8

File tree

5 files changed

+50
-11
lines changed

5 files changed

+50
-11
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/
1818

1919
## [Unreleased]
2020

21+
### Changed
22+
23+
- Improved handling of boolean attributes to support all forms of Django template syntax and string values. The attribute name alone (`disabled`), explicit booleans (`disabled=True`), or string values (`disabled="True"`) all work as expected - rendering just the attribute name when true and omitting it when false.
24+
2125
## [0.3.0]
2226

2327
### Added

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,27 +68,30 @@ templates/
6868
└── button.html
6969
```
7070

71-
In `button.html`, create a simple HTML button. Use `{{ slot }}` to indicate where the main content will go.
71+
In `button.html`, create a simple HTML button. Use `{{ slot }}` to indicate where the main content will go. We will also define a component property via the `{% bird:prop %}` templatetag and add `{{ attrs }}` for passing in arbitrary HTML attributes.
7272

7373
```htmldjango
7474
{# templates/bird/button.html #}
75-
<button>
75+
{% bird:prop class="btn" %}
76+
{% bird:prop data_attr="button" %}
77+
78+
<button class="{{ props.class }}" data-attr="{{ props.data_attr }}" {{ attrs }}>
7679
{{ slot }}
7780
</button>
7881
```
7982

80-
To use your component in a Django template, use the `{% bird %}` templatetag. The content between `{% bird %}` and `{% endbird %}` becomes the `{{ slot }}` content.
83+
To use your component in a Django template, use the `{% bird %}` templatetag. The content between `{% bird %}` and `{% endbird %}` becomes the `{{ slot }}` content. Properties and attributes are set as parameters on the `{% bird %}` tag itself.
8184

8285
```htmldjango
83-
{% bird button %}
86+
{% bird button class="btn-primary" disabled=True %}
8487
Click me!
8588
{% endbird %}
8689
```
8790

8891
django-bird automatically recognizes components in the bird directory, so no manual registration is needed. When Django processes the template, django-bird replaces the `{% bird %}` tag with the component's HTML, inserting the provided content into the slot, resulting in:
8992
9093
```html
91-
<button>
94+
<button class="btn-primary" data-attr="button" disabled>
9295
Click me!
9396
</button>
9497
```
@@ -100,9 +103,10 @@ You now have a button component that can be easily reused across your Django pro
100103
101104
django-bird offers features for creating flexible components, such as:
102105
103-
- Passing attributes to components
104-
- Named slots for organizing content within components
105-
- Subcomponents for building complex component structures
106+
- [Defining and registering components](https://django-bird.readthedocs.io/en/latest/naming.html) entirely within Django templates, without writing a custom templatetag
107+
- Passing [attributes and properties](https://django-bird.readthedocs.io/en/latest/params.html) to components
108+
- [Named slots](https://django-bird.readthedocs.io/en/latest/slots.html#named-slots) for organizing content within components
109+
- [Subcomponents](https://django-bird.readthedocs.io/en/latest/organization.html) for building complex component structures
106110
107111
For a full overview of the features and configuration options, please refer to the [documentation](https://django-bird.readthedocs.io).
108112

docs/params.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Note that these parameters are distinct from [Slots](slots.md) - they are used t
99
For example, a button component might use properties to control its styling and attributes to set HTML attributes, while using slots to define its content:
1010

1111
```htmldjango
12-
{% bird button variant="primary" data-analytics="signup" %}
12+
{% bird button variant="primary" data_analytics="signup" %}
1313
Click here {# This content will go in the default slot #}
1414
{% endbird %}
1515
```
@@ -81,6 +81,7 @@ Here's a simple example of a button component that uses props:
8181
:caption: templates/bird/button.html
8282
8383
{% bird:prop variant='primary' %}
84+
8485
<button class="btn btn-{{ props.variant }}" {{ attrs }}>
8586
{{ slot }}
8687
</button>
@@ -120,6 +121,7 @@ Components often need multiple props to control different aspects of their behav
120121
121122
{% bird:prop variant='primary' %}
122123
{% bird:prop size='md' %}
124+
123125
<button
124126
class="btn btn-{{ props.variant }} btn-{{ props.size }}"
125127
{{ attrs }}
@@ -153,6 +155,7 @@ Props can be defined with or without default values:
153155
```htmldjango
154156
{% bird:prop id %} {# No default value #}
155157
{% bird:prop variant='primary' %} {# With default value #}
158+
156159
<button
157160
id="{{ props.id }}"
158161
class="btn btn-{{ props.variant }}"

src/django_bird/components/params.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ class Param:
1818
value: str | bool | None
1919

2020
def render(self, context: Context) -> str:
21-
if self.value is None:
21+
if self.value is None or (
22+
isinstance(self.value, str) and self.value == "False"
23+
):
2224
return ""
23-
if isinstance(self.value, bool) and self.value:
25+
if (isinstance(self.value, bool) and self.value) or (
26+
isinstance(self.value, str) and self.value == "True"
27+
):
2428
return self.name
2529
try:
2630
value = template.Variable(str(self.value)).resolve(context)

tests/templatetags/test_bird.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,24 @@ def test_rendered_name(
127127
{},
128128
'<button class="btn">Click me</button>',
129129
),
130+
(
131+
"<button {{ attrs }}>Click me</button>",
132+
"{% bird button disabled %}Click me{% endbird %}",
133+
{},
134+
"<button disabled>Click me</button>",
135+
),
136+
(
137+
"<button {{ attrs }}>Click me</button>",
138+
"{% bird button disabled=True %}Click me{% endbird %}",
139+
{},
140+
"<button disabled>Click me</button>",
141+
),
142+
(
143+
"<button {{ attrs }}>Click me</button>",
144+
"{% bird button disabled=False %}Click me{% endbird %}",
145+
{},
146+
"<button>Click me</button>",
147+
),
130148
(
131149
"<button {{ attrs }}>Click me</button>",
132150
"{% bird button class='btn' id='my-btn' disabled %}Click me{% endbird %}",
@@ -281,6 +299,12 @@ def get_template_libraries(self, libraries):
281299
{},
282300
'<button id="default" class="btn" data-test="value">Click me</button>',
283301
),
302+
(
303+
'{% bird:prop class="btn" %}{% bird:prop data_attr="button" %}<button class="{{ props.class }}" data-attr="{{ props.data_attr }}" {{ attrs }}>{{ slot }}</button>',
304+
'{% bird button class="btn-primary" disabled=True %}Click me{% endbird %}',
305+
{},
306+
'<button class="btn-primary" data-attr="button" disabled>Click me</button>',
307+
),
284308
],
285309
)
286310
def test_with_props(

0 commit comments

Comments
 (0)