# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['tbxforms', 'tbxforms.layout', 'tbxforms.templatetags']

package_data = \
{'': ['*'],
 'tbxforms': ['static/js/*',
              'static/sass/*',
              'static/sass/abstracts/*',
              'static/sass/components/*',
              'static/sass/helpers/*',
              'static/sass/utilities/*',
              'templates/tbx/*',
              'templates/tbx/layout/*',
              'templates/tbx/widgets/*']}

install_requires = \
['Django>=2.2,<=4.0', 'django-crispy-forms==1.13.0']

setup_kwargs = {
    'name': 'tbxforms',
    'version': '1.0.13',
    'description': 'A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds',
    'long_description': '[![PyPI](https://img.shields.io/pypi/v/tbxforms.svg)](https://pypi.org/project/tbxforms/)\n[![npm](https://img.shields.io/npm/v/tbxforms.svg)](https://www.npmjs.com/package/tbxforms) [![PyPI downloads](https://img.shields.io/pypi/dm/tbxforms.svg)](https://pypi.org/project/tbxforms/) [![CI](https://github.com/torchbox/tbxforms/actions/workflows/test.yml/badge.svg)](https://github.com/torchbox/tbxforms/actions/workflows/test.yml) [![LGTM](https://img.shields.io/lgtm/alerts/g/torchbox/tbxforms.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/torchbox/tbxforms/alerts/)\n\n# Torchbox Forms\n\nA Torchbox-flavoured template pack for [django-crispy-forms](https://github.com/django-crispy-forms/django-crispy-forms), adapted from [crispy-forms-gds](https://github.com/wildfish/crispy-forms-gds).\n\nOut of the box, forms created with `tbxforms` will look like the\n[GOV.UK Design System](https://design-system.service.gov.uk/), though many\nvariables can be customised.\n\n## Installation\n\nYou must install both the Python package and the NPM package.\n\n### Install the Python package\n\n#### Install using pip\n\n```bash\npip install tbxforms\n```\n\n#### Update/define settings\n\nAdd `django-crispy-forms` and `tbxforms` to your installed apps:\n\n```python\nINSTALLED_APPS = [\n  ...\n  \'crispy_forms\',  # django-crispy-forms\n  \'tbxforms\', # must appear after `wagtail.contrib.forms` if you are using Wagtail forms.\n]\n```\n\nNow add the following settings to tell `django-crispy-forms` to use `tbxforms`:\n\n```python\nCRISPY_ALLOWED_TEMPLATE_PACKS = ["tbx"]\nCRISPY_TEMPLATE_PACK = "tbx"\n```\n\nThere are two optional settings which will control whether HTML is rendered for\na field\'s `label` and `help_text`. The defaults are set to `False`\n(which escapes the HTML and prevents it from being rendered):\n\n```python\nTBXFORMS_ALLOW_HTML_LABEL = False\nTBXFORMS_ALLOW_HTML_HELP_TEXT = False\n```\n\n### Install the NPM package\n\n#### Install using NPM\n\n```bash\nnpm install tbxforms\n```\n\nThis package uses the `Element.closest`, `NodeList.forEach`, and `Array.includes` APIs. You will additionally need to install and configure polyfills for legacy browser support.\n\n#### Instantiate your forms\n\n```javascript\nimport TbxForms from \'tbxforms\';\n\ndocument.addEventListener(\'DOMContentLoaded\', () => {\n    for (const form of document.querySelectorAll(TbxForms.selector())) {\n        new TbxForms(form);\n    }\n});\n```\n\n#### Import the styles into your project\n\n...Either as CSS without any customisations:\n\n```scss\n@use \'node_modules/tbxforms/style.css\';\n```\n\n...Or as Sass to customise variables:\n\n```scss\n@use \'node_modules/tbxforms/tbxforms.scss\' with (\n    $tbxforms-error-colour: #f00,\n    $tbxforms-text-colour: #000,\n);\n```\n\nAlternatively, variables can be defined in a centralised variables SCSS\nsuch as [tbxforms/static/sass/abstracts/\\_variables.scss](https://github.com/torchbox/tbxforms/blob/main/tbxforms/static/sass/abstracts/_variables.scss).\n\n#### Add button styles\n\n`tbxforms` provides out-of-the-box GOV.UK Design System styles for everything\nexcept buttons, as styles for these probably exist in your project.\n\nYou will need to write button styles for the following classes:\n\n1. `.tbxforms-button`\n2. `.tbxforms-button.tbxforms-button--primary`\n3. `.tbxforms-button.tbxforms-button--secondary`\n4. `.tbxforms-button.tbxforms-button--warning`\n\n## Usage\n\n`tbxforms` supports Django (`>=2.2,<=4.0`) and Wagtail (`>=2.15`) forms.\n\n### Django forms\n\n`django>=2.2,<=4.0` is supported.\n\nAll forms must inherit from `TbxFormsBaseForm` and whichever Django base form class.\n\n```python\nfrom django import forms\nfrom tbxforms.forms import BaseForm as TbxFormsBaseForm\n\nclass ExampleForm(TbxFormsBaseForm, forms.Form):\n    # < Your field definitions and helper property >\n\n\nclass ExampleModelForm(TbxFormsBaseForm, forms.ModelForm):\n    # < Your field definitions, ModelForm config, and helper property >\n\n```\n\n### Wagtail forms\n\n`wagtail>=2.15` is supported.\n\n#### Create or update a Wagtail form\n\nWagtail forms must inheirt from `TbxFormsBaseForm` and `WagtailBaseForm`.\n\n```python\nfrom wagtail.contrib.forms.forms import BaseForm as WagtailBaseForm\nfrom tbxforms.forms import BaseForm as TbxFormsBaseForm\n\nclass ExampleWagtailForm(TbxFormsBaseForm, WagtailBaseForm):\n    # < Your helper property >\n\n```\n\n#### Instruct a Wagtail Page model to use your form\n\n**In your form definitions** (e.g. forms.py):\n\n```python\nfrom tbxforms.forms import BaseWagtailFormBuilder as TbxFormsBaseWagtailFormBuilder\nfrom path.to.your.forms import ExampleWagtailForm\n\nclass WagtailFormBuilder(TbxFormsBaseWagtailFormBuilder):\n    def get_form_class(self):\n        return type(str("WagtailForm"), (ExampleWagtailForm,), self.formfields)\n```\n\n**And in your form page models** (e.g. models.py):\n\n```python\nfrom path.to.your.forms import WagtailFormBuilder\n\nclass ExampleFormPage(...):\n    ...\n    form_builder = WagtailFormBuilder\n    ...\n```\n\n### Render a form\n\nJust like Django Crispy Forms, you need to pass your form object to the\n`{% crispy ... %}` template tag, e.g.:\n\n```html\n{% load crispy_forms_tags %}\n<html>\n    <body>\n        {% crispy your_form %}\n    </body>\n</html>\n```\n\n### Add a submit button and customise the form via the `helper` property\n\nSubmit buttons are not automatically added - you will need to do this by\nextending the form helper\'s `layout` (example below).\n\nEvery form that inherits from `TbxFormsBaseForm` will have the following\nattributes set:\n\n-   `html5_required = True`\n-   `label_size = Size.MEDIUM`\n-   `legend_size = Size.MEDIUM`\n-   `form_error_title = _("There is a problem with your submission")`\n-   Plus everything from [django-crispy-forms\' default attributes](https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html).\n\nThese can be overridden (and/or additional attributes from the above list defined)\njust like you would do with any other inherited class, e.g.:\n\n```python\nfrom django import forms\nfrom wagtail.contrib.forms.forms import BaseForm as WagtailBaseForm\nfrom tbxforms.forms import BaseForm as TbxFormsBaseForm\nfrom tbxforms.layout import Button, Size\n\nclass YourSexyForm(TbxFormsBaseForm, forms.Form):\n\n    @property\n    def helper(self):\n        fh = super().helper\n\n        # Override some settings\n        fh.html5_required = False\n        fh.label_size = Size.SMALL\n        fh.form_error_title = _("Something\'s wrong, yo.")\n\n        # Add a submit button\n        fh.layout.extend([\n            Button.primary(\n                name="submit",\n                type="submit",\n                value="Submit",\n            )\n        ])\n        return fh\n\n```\n\n#### Change the label and legend classes\n\nPossible values for the `label_size` and `legend_size`:\n\n1. `SMALL`\n2. `MEDIUM` (default)\n3. `LARGE`\n4. `EXTRA_LARGE`\n\n### Conditionally-required fields\n\n`tbxforms` can show/hide parts of the `layout` depending on a given value. For\nexample, you could show (and require) an email address field only when the user\nchooses to sign up to a newsletter (examples below).\n\nYou can apply this logic to `field`, `div`, and `fieldset` elements.\n\nNote: any field names included within the\n`conditional_fields_to_show_as_required()` method will appear on the frontend\nas required, though will technically be `required=False`.\n\n**Field example:**\n\n```python\nfrom django import forms\nfrom tbxforms.choices import Choice\nfrom tbxforms.forms import BaseForm as TbxFormsBaseForm\nfrom tbxforms.layout import Field, Layout\n\nclass ExampleForm(TbxFormsBaseForm, forms.Form):\n    NEWSLETTER_CHOICES = (\n        Choice("yes", "Yes please", hint="Receive occasional email newsletters."),\n        Choice("no", "No thanks"),\n    )\n\n    newsletter_signup = forms.ChoiceField(\n        choices=NEWSLETTER_CHOICES\n    )\n\n    email = forms.EmailField(\n        widget=forms.EmailInput(required=False)\n    )\n\n    @staticmethod\n    def conditional_fields_to_show_as_required() -> [str]:\n        # Non-required fields that should show as required to the user.\n        return [\n            "email",\n        ]\n\n    @property\n    def helper(self):\n        fh = super().helper\n\n        # Override what is rendered for this form.\n        fh.layout = Layout(\n\n            # Add our newsletter sign-up field.\n            Field("newsletter_signup"),\n\n            # Add our email field and define the conditional logic.\n            Field(\n                "email",\n                data_conditional={\n                    "field_name": "newsletter_signup", # Field to inspect.\n                    "values": ["yes"], # Value(s) to cause this field to show.\n                },\n            ),\n\n        )\n\n        return fh\n\n\n    def clean(self):\n        cleaned_data = super().clean()\n        newsletter_signup = cleaned_data.get("newsletter_signup")\n        email = cleaned_data.get("email")\n\n        # Fields included within `conditional_fields_to_show_as_required()` will\n        # be shown as required but not enforced - i.e. they will not have the\n        # HTML5 `required` attribute set.\n        # Thus we need to write our own check to enforce the value exists.\n        if newsletter_signup == "yes" and not email:\n            raise ValidationError(\n                {\n                    "email": _("This field is required."),\n                }\n            )\n        # The tbxforms JS will attempt to clear any redundant data upon submission,\n        # though it is recommended to also handle this in your clean() method.\n        elif newsletter_signup == "no" and email:\n            del cleaned_data[\'email\']\n\n        return cleaned_data\n\n```\n\n**Container example:**\n\nWhen you have multiple fields/elements that you want to show/hide together, you\ncan use the exact same `data_conditional` definition as above but on a `div` or\n`fieldset` element, e.g.:\n\n```python\nfrom tbxforms.layout import HTML, Div, Field\n\nLayout(\n    Div(\n        HTML("<p>Some relevant text.</p>"),\n        Field("some_other_field"),\n        Field("email"),\n        data_conditional={\n            "field_name": "newsletter_signup",\n            "values": ["yes"],\n        },\n    ),\n)\n```\n\n# Further reading\n\n-   Download the [PyPI package](http://pypi.python.org/pypi/tbxforms)\n-   Download the [NPM package](https://www.npmjs.com/package/tbxforms)\n-   Learn more about [Django Crispy Forms](https://django-crispy-forms.readthedocs.io/en/latest/)\n-   Learn more about [Crispy Forms GDS](https://github.com/wildfish/crispy-forms-gds)\n-   Learn more about [GOV.UK Design System](https://design-system.service.gov.uk/)\n',
    'author': 'Kyle Bayliss',
    'author_email': 'kyle.bayliss@torchbox.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/torchbox/tbxforms/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.8,<3.11',
}


setup(**setup_kwargs)
