Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B5 Responsive Forms #35519

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
1 change: 0 additions & 1 deletion corehq/apps/app_execution/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def __init__(self, request, *args, **kwargs):
if self.instance.id:
self.fields["username"].initial = self.instance.django_user.username
self.helper = hqcrispy.HQFormHelper()
self.helper.form_class = "form-horizontal"

fields = [
"name",
Expand Down
1 change: 0 additions & 1 deletion corehq/apps/domain/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,6 @@ def __init__(self, domain, can_edit_eula, *args, user, **kwargs):
)

self.helper = hqcrispy.HQFormHelper()
self.helper.form_class = "form-horizontal"
self.helper.layout = crispy.Layout(
crispy.Fieldset(
_("Basic Information"),
Expand Down
29 changes: 5 additions & 24 deletions corehq/apps/hqwebapp/crispy.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import re
from contextlib import contextmanager
from django.forms.widgets import DateTimeInput
from django.template.loader import render_to_string
Expand All @@ -13,11 +12,9 @@
from crispy_forms.layout import LayoutObject
from crispy_forms.utils import flatatt, get_template_pack, render_field

CSS_LABEL_CLASS = 'col-xs-12 col-sm-4 col-md-4 col-lg-2'
CSS_LABEL_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-4 col-md-4 col-lg-3'
CSS_FIELD_CLASS = 'col-xs-12 col-sm-8 col-md-8 col-lg-6'
CSS_FIELD_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-8 col-md-8 col-lg-9'
CSS_ACTION_CLASS = CSS_FIELD_CLASS + ' col-sm-offset-4 col-md-offset-4 col-lg-offset-2'
CSS_LABEL_CLASS = 'field-label'
CSS_FIELD_CLASS = 'field-control'
CSS_ACTION_CLASS = CSS_FIELD_CLASS


class HQFormHelper(FormHelper):
Expand All @@ -28,13 +25,7 @@ class HQFormHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(HQFormHelper, self).__init__(*args, **kwargs)
from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version, BOOTSTRAP_5
bootstrap_version = get_bootstrap_version()
use_bootstrap5 = bootstrap_version == BOOTSTRAP_5
if use_bootstrap5:
self.label_class = CSS_LABEL_CLASS_BOOTSTRAP5
self.field_class = CSS_FIELD_CLASS_BOOTSTRAP5
self.use_bootstrap5 = use_bootstrap5
self.form_class = 'form'
self.use_bootstrap5 = get_bootstrap_version() == BOOTSTRAP_5

if 'autocomplete' not in self.attrs:
self.attrs.update({
Expand Down Expand Up @@ -76,15 +67,7 @@ class ErrorsOnlyField(Field):


def get_form_action_class():
"""This is only valid for bootstrap 5"""
return CSS_LABEL_CLASS_BOOTSTRAP5.replace('col', 'offset') + ' ' + CSS_FIELD_CLASS_BOOTSTRAP5


def _get_offsets(context):
label_class = context.get('label_class', '')
use_bootstrap5 = context.get('use_bootstrap5')
return (label_class.replace('col', 'offset') if use_bootstrap5
else re.sub(r'(xs|sm|md|lg)-', r'\g<1>-offset-', label_class))
return CSS_FIELD_CLASS


class FormActions(OriginalFormActions):
Expand All @@ -102,11 +85,9 @@ def render(self, form, context, template_pack=None, **kwargs):
template_pack=template_pack,
)
fields_html = mark_safe(fields_html) # nosec: just concatenated safe fields
offsets = _get_offsets(context)
context.update({
'formactions': self,
'fields_output': fields_html,
'offsets': offsets,
'field_class': context.get('field_class', '')
})
return render_to_string(self.template, context.flatten())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.field-label {
&:extend(.col-xs-12, .col-sm-4, .col-md-4, .col-lg-2);
}

.field-label + .field-control {
&:extend(.col-xs-12, .col-sm-8, .col-md-8, .col-lg-6);
}

:not(.field-label) + .field-control,
.form-actions > .field-control:first-child,
.form-group > .field-control:first-child {
&:extend(
.col-sm-offset-4, .col-md-offset-4, .col-lg-offset-2,
.col-xs-12, .col-sm-8, .col-md-8, .col-lg-6
);
}
1 change: 1 addition & 0 deletions corehq/apps/hqwebapp/static/hqwebapp/less/bootstrap.less
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// Core variables and mixins
@import "_hq/includes/variables.less";
@import "_hq/includes/mixins.less";
@import "_hq/includes/extensions.less";

// Reset and dependencies
@import "../../../../../../node_modules/bootstrap/less/normalize.less";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
.field-label {
@extend .col-form-label, .col-12, .col-sm-4, .col-md-3, .col-lg-2;
}

.field-label + .field-control {
@extend .col-12, .col-sm-8, .col-md-9, .col-lg-10;
}

:not(.field-label) + .field-control,
.row > .field-control:first-child {
@extend .offset-sm-4, .offset-md-3, .offset-lg-2;
}

.row > div > .form-check:first-child,
.row > div > .input-group > .form-check:first-child {
padding-top: add($input-padding-y, $input-border-width);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div {% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %} class="form-actions">
<div class="{{ offsets }} controls {{ field_class }}">
<div class="controls {{ field_class }}">
{{ fields_output }}
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="form-actions{% if 'form-horizontal' in form_class %} row{% endif %}" {% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %}>
<div class="{{ offsets }} {{ field_class }}">
<div class="{{ field_class }}">
{{ fields_output }}
</div>
</div>
10 changes: 2 additions & 8 deletions corehq/apps/hqwebapp/templatetags/hq_shared_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,19 +246,13 @@ def can_use_restore_as(request):

@register.simple_tag
def css_label_class():
from corehq.apps.hqwebapp.crispy import CSS_LABEL_CLASS, CSS_LABEL_CLASS_BOOTSTRAP5
from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version, BOOTSTRAP_5
if get_bootstrap_version() == BOOTSTRAP_5:
return CSS_LABEL_CLASS_BOOTSTRAP5
from corehq.apps.hqwebapp.crispy import CSS_LABEL_CLASS
return CSS_LABEL_CLASS


@register.simple_tag
def css_field_class():
from corehq.apps.hqwebapp.crispy import CSS_FIELD_CLASS, CSS_FIELD_CLASS_BOOTSTRAP5
from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version, BOOTSTRAP_5
if get_bootstrap_version() == BOOTSTRAP_5:
return CSS_FIELD_CLASS_BOOTSTRAP5
from corehq.apps.hqwebapp.crispy import CSS_FIELD_CLASS
return CSS_FIELD_CLASS


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
+++
@@ -1,5 +1,5 @@
-<div {% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %} class="form-actions">
- <div class="{{ offsets }} controls {{ field_class }}">
- <div class="controls {{ field_class }}">
- {{ fields_output }}
- </div>
+<div class="form-actions{% if 'form-horizontal' in form_class %} row{% endif %}" {% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %}>
+ <div class="{{ offsets }} {{ field_class }}">
+ <div class="{{ field_class }}">
+ {{ fields_output }}
+ </div>
</div>
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
---
+++
@@ -1,356 +1,7 @@
@@ -1,356 +1,20 @@
-// FORM ACTIONS from TWBS 2
-// ------------
-
-[ng\:cloak],[ng-cloak],.ng-cloak{
- display:none !important
-}
-
+.field-label {
+ @extend .col-form-label, .col-12, .col-sm-4, .col-md-3, .col-lg-2;
}

-.form-actions {
- padding: (@line-height-base * @font-size-base - 1px) 0px @line-height-base * @font-size-base;
- margin-top: @line-height-base * 1em;
+.row > div > .form-check:first-child,
+.row > div > .input-group > .form-check:first-child {
+ padding-top: add($input-padding-y, $input-border-width);
margin-bottom: 0;
- margin-bottom: 0;
- background-color: @navbar-default-bg;
- border-top: 1px solid @legend-border-color;
- .border-bottom-radius(@border-radius-base);
Expand All @@ -31,12 +30,17 @@
- margin-left: 0;
- }
- }
-}
-
+.field-label + .field-control {
+ @extend .col-12, .col-sm-8, .col-md-9, .col-lg-10;
}

-.form-horizontal .control-label {
- text-align: left; // override bootstrap
-}
-
+:not(.field-label) + .field-control,
+.row > .field-control:first-child {
+ @extend .offset-sm-4, .offset-md-3, .offset-lg-2;
}

-legend .subtext {
- font-size: .8em;
- color: lighten(@cc-text, 40%);
Expand Down Expand Up @@ -357,10 +361,14 @@
-
-.controls-text {
- padding-top: 7px;
+.row > div > .form-check:first-child,
+.row > div > .input-group > .form-check:first-child {
+ padding-top: add($input-padding-y, $input-border-width);
+ margin-bottom: 0;
}

.form-hide-actions .form-actions {
@@ -361,21 +12,34 @@
@@ -361,21 +25,34 @@
.validationMessage {
display: block;
padding-top: 8px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ section</a> of the style guide.

A few useful things to know about crispy forms in Bootstrap 5:

* Checkboxes, typically based on a `BooleanField`, need to be updated to use the `BootstrapCheckboxInput` as their
`widget`, as shown in <a href="https://www.commcarehq.org/styleguide/b5/organisms/forms/#crispy-forms-simple"
target="_blank">this style guide example</a>.
* As described in <a href="https://www.commcarehq.org/styleguide/b5/organisms/forms/#crispy-forms-simple"
target="_blank">this section of the style guide</a>, best practice is to use one of HQ's standard helper classes
for layout. Doing so means you can delete <code>form_class</code>, <code>label_class</code>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
`form-group` has been dropped. Use grid utilities instead.

Since we are opting for vertical forms (where the label is directly above the field), take the following actions:
Take the following actions:
* Remove the `div` wrapper from the `form-group`'s first child, which contains the field's label.
* Remove the column classes (`col-lg-2`, etc.) from the `form-group`'s first child, usually a `<label>`,
which contains the field's label. Most often, this will leave the label with just the `form-label` class.
* Remove the column classes (`col-lg-2`, etc.) from the `form-group`'s second child, which contains the field
control (the actual input, which will often use the `form-control` class). Frequently, this will leave the `<div>`
without any other classes. If so, and if it has no other attributes, it can be removed.
* Replace `form-group` with `mb-3`.
* Replace the column classes (`col-lg-2`, etc.) from the `form-group`'s first child, usually a `<label>`,
with the `field-label` class. If the first child is a control container such as form actions, do not add
`field-label`, and instead apply the next step to the first child.
* Replace the column classes (`col-lg-2`, etc.) of the `form-group`'s second child with `field-control`.
This `div` should contain the field control (the actual input, which will often use the `form-control` class).
* Replace `form-group` with `row mb-3`.
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ Previously:
Now:
```
<div class="row mb-3">
<label for="id_error_input" class="form-label">
<label for="id_error_input" class="form-label field-label">
Error Input
</label>
<input type="text" name="error_input" class="form-control is-invalid" id="id_error_input" />
<div class='invalid-feedback'>This is an error message.</div>
<div class="field-control">
<input type="text" name="error_input" class="form-control is-invalid" id="id_error_input" />
<div class='invalid-feedback'>This is an error message.</div>
</div>
</div>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ Previously:
Now:
```
<div class="row mb-3">
<label for="id_happy_input" class="form-label">
<label for="id_happy_input" class="form-label field-label">
Happy Input
</label>
<input type="text" name="happy_input" class="form-control is-valid" id="id_happy_input" />
<div class='valid-feedback'>Look at what a good job you did.</div>
<div class="field-control">
<input type="text" name="happy_input" class="form-control is-valid" id="id_happy_input" />
<div class='valid-feedback'>Look at what a good job you did.</div>
</div>
</div>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
<fieldset>
<legend>Basic Information</legend>
<div class="row mb-3">
<!-- Generally, it is best practice to use the {% css_label_class %}
template tag below instead of the col-* classes -->
<label for="id_first_name"
class="col-form-label col-xs-12 col-sm-4 col-md-4 col-lg-3">
<label for="id_first_name" class="field-label">
First Name
</label>
<!-- Generally, it is best practice to use the {% css_field_class %}
template tag below instead of the col-* classes -->
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-9">
<div class="field-control">
<input type="text"
name="first_name"
class="form-control"
Expand All @@ -21,11 +16,10 @@
</div>
</div>
<div class="row mb-3">
<label for="id_favorite_color"
class="col-form-label col-xs-12 col-sm-4 col-md-4 col-lg-3">
<label for="id_favorite_color" class="field-label">
Favorite Color
</label>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-9">
<div class="field-control">
<select name="favorite_color"
class="form-select hqwebapp-select2"
id="id_favorite_color">
Expand All @@ -36,21 +30,18 @@
</div>
</div>
<div class="row mb-3">
<label for="id_hopes"
class="col-form-label col-xs-12 col-sm-4 col-md-4 col-lg-3">
<label for="id_hopes" class="field-label">
Hopes and Dreams
</label>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-9">
<div class="field-control">
<textarea name="hopes"
class="form-control vertical-resize"
id="id_hopes"></textarea>
</div>
</div>
</fieldset>
<div class="form-actions row">
<!-- Generally, it is best practice to use the {% css_action_class %}
template tag below instead of offset-* and col-* -->
<div class="offset-xs-12 offset-sm-4 offset-md-4 offset-lg-3 col-xs-12 col-sm-8 col-md-8 col-lg-9">
<div class="field-control">
<button class="btn btn btn-primary" type="submit">Save</button>
<a href="#" class="btn btn-outline-primary">Cancel</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<form>
<div class="mb-3 row">
<label for="height-input" class="col-sm-3 col-form-label">
<label for="height-input" class="field-label">
Height (cm)
</label>
<div class="col-sm-9">
<div class="field-control">
<input type="text" id="height-input" name="height" class="form-control" />
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-3 col-form-label">
<label class="field-label">
Smoking status
</label>
<div class="col-sm-9">
<div class="field-control">
<div class="form-check">
<input class="form-check-input"
type="checkbox"
Expand All @@ -26,10 +26,10 @@
</div>
</div>
<div class="mb-3 row">
<label for="heartRate-input" class="col-sm-3 col-form-label">
<label for="heartRate-input" class="field-label">
Heart Rate (bpm)
</label>
<div class="col-sm-9">
<div class="field-control">
<input type="text" id="heartRate-input" name="heartRate" class="form-control" />
</div>
</div>
Expand Down
Loading
Loading