Metadata-Version: 2.1
Name: django-component-tags
Version: 0.0.4
Summary: Create advanced HTML components using Django Tags.
Home-page: https://github.com/syse-i/django-component-tags
Author: David Sosa Valdes
Author-email: david.sosa.valdes@gmail.com
License: MIT
Project-URL: Documentation, https://github.com/syse-i/django-component-tags#django---component-tags
Project-URL: Source, https://github.com/syse-i/django-component-tags
Project-URL: Changelog, https://github.com/syse-i/django-component-tags/blob/main/CHANGELOG.rst
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Framework :: Django
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Classifier: Framework :: Django
Description-Content-Type: text/x-rst; charset=UTF-8
Requires-Dist: django
Requires-Dist: importlib-metadata ; python_version < "3.8"
Provides-Extra: testing
Requires-Dist: setuptools ; extra == 'testing'
Requires-Dist: pytest ; extra == 'testing'
Requires-Dist: pytest-cov ; extra == 'testing'
Requires-Dist: pytest-django ; extra == 'testing'

=======================
Django - Component Tags
=======================

:Test Status:
    .. image:: https://img.shields.io/github/workflow/status/syse-i/django-component-tags/Run%20tests
        :alt: GitHub Workflow Status

:Version Info:
    .. image:: https://img.shields.io/pypi/v/django-component-tags?label=PyPi
        :alt: PyPI

    .. image:: https://img.shields.io/pypi/dm/django-component-tags?label=Downloads&style=flat-square   :alt: PyPI - Downloads

:Compatibility:
    .. image:: https://img.shields.io/pypi/pyversions/django-component-tags?style=flat-square&label=Python%20Versions
        :target: https://pypi.org/project/coveralls/

    .. image:: https://img.shields.io/pypi/djversions/django-component-tags?label=Django%20Versions&style=flat-square
        :alt: PyPI - Django Version


Create advanced HTML components using Django Tags.


Description
===========

The goal of this project is to use
`Django Template Tags <https://docs.djangoproject.com/en/3.1/ref/templates/builtins/>`_ and create a new way of
writing **reusable html components** compatible with the current template infrastructure. This new way should
fit the Django standards of creating classes, like ``Models`` and ``Forms``, also it should require as little boilerplate
code and be simple to write.

Some features:

* Class based template tags.
* Template tag argument parser.
* Declarative component attributes.
* Extendable components.
* Slot components.

.. note::

    **django-component-tags** implements a simple content distribution API inspired by the
    `Web Components spec draft <https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md>`_,
    using the ``{% slot %}`` component inside another component to serve as distribution outlets for content.

Requirements
============

Requires Django 2.2 or newer, and is tested against Python 3.7 and PyPy.


Quick Start
===========

First, install the library:

.. code-block::

    pip3 install django-component-tags

Add it to ``INSTALLED_APPS``.

.. code-block::

    INSTALLED_APPS = [
        ...
        'component_tags',
        ...
    ]

Assuming that we already have an `application <https://docs.djangoproject.com/en/3.1/intro/tutorial01/>`_
called **foo**, lets create a new component tag:

.. code-block:: python

    # foo/templatetags/foo_tags.py
    from component_tags import template

    register = template.Library()

    @register.tag
    class Link(template.Component):
        href = template.Attribute(default='#')

        class Meta:
            template_name = 'tags/link.html'



.. note::

    **django-component-tags** extends the default django template library, because it wraps component classes with a parser
    function and extracts template tag arguments, everything else is left in the same way.

    Please check out `the repository <https://github.com/syse-i/django-component-tags/blob/main/src/component_tags/template/library.py>`_
    if you want to know more about this process.

Next step, creating the component template:

.. code-block::

    # foo/templates/foo/tags/link.html

    <a {{ attributes }}>
        {{ nodelist }}
    </a>

Here we defined a couple of variables that we can use inside a component template:

* **attributes**: component template/class attributes (formatted).
* **nodelist**: the content created between ``{% link %}`` and ``{% endlink %}`` will be rendered here.

Finally, we can use it as follows:

.. code-block::

    # foo/templates/foo/index.html
    {% load foo_tags %}

    {% link %}
        Link 1
    {% endlink %}

Output:

.. code-block::

    # foo/templates/foo/index.html

    <a href="#">
        Link 1
    </a>

This is the simplest way to start, there is a lot of different settings that you can combine to create complex
html components.


Examples
========

Adding css classes
------------------

Lets create a html component using the `bootstrap framework <https://getbootstrap.com>`_

.. code-block:: python

    # foo/templatetags/foo_tags.py
    from component_tags import template

    register = template.Library()

    @register.tag
    class Link(template.Component):
        class ColorChoices(template.AttributeChoices):
            primary = 'btn btn-primary'
            secondary = 'btn btn-secondary'
            success = 'btn btn-success'
            danger = 'btn btn-danger'
            warning = 'btn btn-warning'
            info = 'btn btn-info'

        color = template.Attribute(choices=TypeChoices, default=TypeChoices.submit, as_class=True)
        href = template.Attribute(default='#')

        class Meta:
            template_name = 'tags/link.html'

Rendering the component:

.. code-block::

    # foo/templates/foo/index.html
    {% load foo_tags %}

    {% link color="primary" class="foo-bar" %}
        Link 1
    {% endlink %}

Also we added the ``class`` argument to the component tag, so even if the components strictly have class attributes,
you will always have a flexible way to customize your components any time in different scenarios.

Output:

.. code-block::

    # foo/templates/foo/index.html

    <a class="btn btn-primary foo-bar" href="#">
        Link 1
    </a>

Note that it was merged with all attribute classes previously declared.


Using slot components
---------------------

Lets make another html component using the `bootstrap framework <https://getbootstrap.com>`_,
this one is going to be a ``Card`` component.

.. code-block:: python

    # foo/templatetags/foo_tags.py
    from component_tags import template

    register = template.Library()

    @register.tag
    class Card(template.Component):
        title = template.Attribute(as_context=True)

        class Meta:
            template_name = 'tags/card.html'

Create the component template:

.. code-block::

    # foo/templates/foo/tags/card.html

    <div class="card" style="width: 18rem;">
      <img src="..." class="card-img-top" alt="...">
      <div class="card-body">
        <h5 class="card-title">{{ title }}</h5>
        <div class="card-text">
            {{ nodelist }}
        </div>
        {% if slot_footer %}
            <div class="card-footer">
                {{ slot_footer }}
            </div>
        {% endif %}
      </div>
    </div>

Rendering the component:

.. code-block::

    # foo/templates/foo/index.html
    {% load foo_tags %}

    {% card title='foo' %}
        Some quick example text to build on the card title and make up the bulk of the card's content.
        {% slot 'footer' %}
            <a href="#" class="btn btn-primary">Go somewhere</a>
        {% endslot %}
    {% endcard %}

Output:

.. code-block::

    # foo/templates/foo/index.html

    <div class="card" style="width: 18rem;">
        <img src="..." class="card-img-top" alt="...">
        <div class="card-body">
            <h5 class="card-title">foo</h5>
            <div class="card-text">
                Some quick example text to build on the card title and make up the bulk of the card's content.
            </div>
            <div class="card-footer">
                <a href="#" class="btn btn-primary">Go somewhere</a>
            </div>
        </div>
    </div>


Adding extra context
--------------------

By default, all components used isolated context to work with. If you want to pass global context to the component tag
it is required to use the ``with`` argument.

.. code-block:: python

    # foo/views.py
    def foo(request, object_id=None):
        return render(request, 'foo/index.html', {
            'object_id': object_id
        })

.. code-block::

    # foo/templates/foo/index.html
    {% load foo_tags %}

    {% link color="primary" with id=object_id %}
        Link {{ id }}
    {% endlink %}

Assuming that the request of the page will be something like ``http://localhost:8000/foo/1/``, the output will be:

.. code-block::

    # foo/templates/foo/index.html

    <a class="btn btn-primary" href="#">
        Link 1
    </a>

.. note::

    ``Slot`` components doesn't need to specify global context, they always use the parent context as default.

.. _pyscaffold-notes:

Note
====

This project has been set up using PyScaffold 4.0rc2. For details and usage
information on PyScaffold see https://pyscaffold.org/.


