diff --git a/django_cotton/templatetags/_component.py b/django_cotton/templatetags/_component.py index a24810a..3dcf130 100644 --- a/django_cotton/templatetags/_component.py +++ b/django_cotton/templatetags/_component.py @@ -40,6 +40,10 @@ def render(self, context): value = self._strip_quotes_safely(value) if value is True: # Boolean attribute component_data["attrs"][key] = True + elif key.startswith("::"): # Escaping 1 colon e.g for shorthand alpine + key = key[1:] + # component_data["slots"][key] = value + component_data["attrs"][key] = value elif key.startswith(":"): key = key[1:] try: diff --git a/django_cotton/tests/test_attributes.py b/django_cotton/tests/test_attributes.py index e8a9f75..1f7aca3 100644 --- a/django_cotton/tests/test_attributes.py +++ b/django_cotton/tests/test_attributes.py @@ -483,3 +483,31 @@ def test_attributes_remain_unordered(self): self.assertTrue( "in default slot: " in compiled ) + + def test_colon_escaping(self): + self.create_template( + "cotton/colon_escaping.html", + """ + attrs: '{{ attrs }}' + """, + ) + + self.create_template( + "colon_escaping_view.html", + """ + + """, + "view/", + context={"variable": "Ive been resolved!"}, + ) + with self.settings(ROOT_URLCONF=self.url_conf()): + response = self.client.get("/view/") + + self.assertContains( + response, + """attrs: ':string="variable" dynamic="Ive been resolved!" :complex-string="{'something': 1}" complex-dynamic="{'something': 1}"'""", + ) diff --git a/docs/docs_project/docs_project/templates/alpine_js.html b/docs/docs_project/docs_project/templates/alpine_js.html index 7a5697b..b479d0d 100644 --- a/docs/docs_project/docs_project/templates/alpine_js.html +++ b/docs/docs_project/docs_project/templates/alpine_js.html @@ -14,6 +14,10 @@

Re-usable tabs with alpine.js

+ + Be sure to checkout the notes on alpine.js support here. + +

Let's tackle together a common UI requirement - tabs.

We'll start by defining some goals:

@@ -69,7 +73,7 @@

Preparing cotton components

Now we have the design right, let's chop it up into components.

-

Tabs component

+

{{ ''|force_escape }} component

{% cotton_verbatim %}{% verbatim %}
@@ -85,7 +89,7 @@

Tabs component

{% endcotton_verbatim %}{% endverbatim %} -

Tab component

+

{{ ''|force_escape }} component

{% cotton_verbatim %}{% verbatim %}
@@ -194,13 +198,13 @@

Usage and example

- - - Form Inputs - - - Layouts - - + + + Form Inputs + + + Layouts + + \ No newline at end of file diff --git a/docs/docs_project/docs_project/templates/components.html b/docs/docs_project/docs_project/templates/components.html index 1aa2db1..89fcb0b 100644 --- a/docs/docs_project/docs_project/templates/components.html +++ b/docs/docs_project/docs_project/templates/components.html @@ -11,6 +11,7 @@

Components

Boolean Attributes Dynamic Components Context Isolation + Alpine.js Support Summary of concepts @@ -330,6 +331,21 @@

9. Context Isolation with `only`

+

10. Alpine.js support

+ +

The following key features allow you to build re-usable components with alpine.js:

+ + +
  • + x-data is accessible as {% verbatim %}{{ x_data }}{% endverbatim %} inside the component as cotton makes available snake_case versions of all kebab-cased attributes. (If you use {% verbatim %}{{ attrs }}{% endverbatim %} then the output will already be in the correct case). +
  • +
  • Shorthand x-bind support (:example). Because single : attribute prefixing is reserved for cotton's dynamic attributes, + we can escape the first colon using ::. This will ensure the attribute maintains a single : inside {% verbatim %}{{ attrs }}{% endverbatim %} +
  • +
    + + +

    Summary of Concepts

    • {% verbatim %}{{ slot }}{% endverbatim %} - Default content injection.
    • diff --git a/pyproject.toml b/pyproject.toml index c4334eb..4ab94d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "django-cotton" -version = "1.4.0" +version = "1.5.0" description = "Bringing component based design to Django templates." authors = [ "Will Abbott ",] license = "MIT"