mirror of
https://github.com/django-components/django-components.git
synced 2025-10-04 11:14:39 +00:00
docs: add Form and Tabs examples (#1411)
This commit is contained in:
parent
b3ea50572d
commit
9afc89ead1
24 changed files with 1237 additions and 7 deletions
126
sampleproject/examples/components/form/form.py
Normal file
126
sampleproject/examples/components/form/form.py
Normal file
|
@ -0,0 +1,126 @@
|
|||
from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple
|
||||
|
||||
from django_components import Component, Slot, register, types
|
||||
|
||||
|
||||
@register("form")
|
||||
class Form(Component):
|
||||
template_file = "form.html"
|
||||
|
||||
class Kwargs(NamedTuple):
|
||||
editable: bool = True
|
||||
method: str = "post"
|
||||
form_content_attrs: Optional[dict] = None
|
||||
attrs: Optional[dict] = None
|
||||
|
||||
def get_template_data(self, args, kwargs: Kwargs, slots: Dict[str, Slot], context):
|
||||
fields = prepare_form_grid(slots)
|
||||
|
||||
return {
|
||||
"form_content_attrs": kwargs.form_content_attrs,
|
||||
"method": kwargs.method,
|
||||
"editable": kwargs.editable,
|
||||
"attrs": kwargs.attrs,
|
||||
"fields": fields,
|
||||
}
|
||||
|
||||
|
||||
# Users of this component can define form fields as slots.
|
||||
#
|
||||
# For example:
|
||||
# ```django
|
||||
# {% component "form" %}
|
||||
# {% fill "field:field_1" / %}
|
||||
# <textarea name="field_1" />
|
||||
# {% endfill %}
|
||||
# {% fill "field:field_2" / %}
|
||||
# <select name="field_2">
|
||||
# <option value="1">Option 1</option>
|
||||
# <option value="2">Option 2</option>
|
||||
# </select>
|
||||
# {% endfill %}
|
||||
# {% endcomponent %}
|
||||
# ```
|
||||
#
|
||||
# The above will automatically generate labels for the fields,
|
||||
# and the form will be aligned with a grid.
|
||||
#
|
||||
# To explicitly define a label, use `label:<field_name>` slot name.
|
||||
#
|
||||
# For example:
|
||||
# ```django
|
||||
# {% component "form" %}
|
||||
# {% fill "label:field_1" / %}
|
||||
# <label for="field_1">Label 1</label>
|
||||
# {% endfill %}
|
||||
# {% fill "field:field_1" / %}
|
||||
# <textarea name="field_1" />
|
||||
# {% endfill %}
|
||||
# {% endcomponent %}
|
||||
# ```
|
||||
def prepare_form_grid(slots: Dict[str, Slot]):
|
||||
used_labels: Set[str] = set()
|
||||
unused_labels: Set[str] = set()
|
||||
fields: List[Tuple[str, str]] = []
|
||||
|
||||
for slot_name in slots:
|
||||
# Case: Label slot
|
||||
is_label = slot_name.startswith("label:")
|
||||
if is_label and slot_name not in used_labels:
|
||||
unused_labels.add(slot_name)
|
||||
continue
|
||||
|
||||
# Case: non-field, non-label slot
|
||||
is_field = slot_name.startswith("field:")
|
||||
if not is_field:
|
||||
continue
|
||||
|
||||
# Case: Field slot
|
||||
field_name = slot_name.split(":", 1)[1]
|
||||
label_slot_name = f"label:{field_name}"
|
||||
label = None
|
||||
if label_slot_name in slots:
|
||||
# Case: Component user explicitly defined how to render the label
|
||||
label_slot: Slot[Any] = slots[label_slot_name]
|
||||
label = label_slot()
|
||||
|
||||
unused_labels.discard(label_slot_name)
|
||||
used_labels.add(slot_name)
|
||||
else:
|
||||
# Case: Component user didn't explicitly define how to render the label
|
||||
# We will create the label for the field automatically
|
||||
label = FormLabel.render(
|
||||
kwargs=FormLabel.Kwargs(field_name=field_name),
|
||||
deps_strategy="ignore",
|
||||
)
|
||||
|
||||
fields.append((slot_name, label))
|
||||
|
||||
if unused_labels:
|
||||
raise ValueError(f"Unused labels: {unused_labels}")
|
||||
|
||||
return fields
|
||||
|
||||
|
||||
@register("form_label")
|
||||
class FormLabel(Component):
|
||||
template: types.django_html = """
|
||||
<label for="{{ field_name }}" class="font-semibold text-gray-700">
|
||||
{{ title }}
|
||||
</label>
|
||||
"""
|
||||
|
||||
class Kwargs(NamedTuple):
|
||||
field_name: str
|
||||
title: Optional[str] = None
|
||||
|
||||
def get_template_data(self, args, kwargs: Kwargs, slots, context):
|
||||
if kwargs.title:
|
||||
title = kwargs.title
|
||||
else:
|
||||
title = kwargs.field_name.replace("_", " ").replace("-", " ").title()
|
||||
|
||||
return {
|
||||
"field_name": kwargs.field_name,
|
||||
"title": title,
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue