From 0ab66c17a6ed4df0ef2bf3eb52aa2aaadf5185f5 Mon Sep 17 00:00:00 2001 From: Ronan Berder Date: Tue, 29 Apr 2025 19:14:31 +0800 Subject: [PATCH] Most docs are complete --- dist/basecoat.css | 105 ++---- dist/basecoat.tailwind.css | 15 +- .../components/dropdown-menu-script.njk | 6 +- docs/_includes/components/tabs.njk | 4 +- .../partials/kitchen-sink/dialog.njk | 2 +- .../partials/kitchen-sink/dropdown-menu.njk | 178 +++++++++- docs/components/alert-dialog.njk | 57 ++- docs/components/breadcrumb.njk | 31 +- docs/components/combobox.njk | 54 +-- docs/components/dialog.njk | 88 +++-- docs/components/dropdown-menu.njk | 325 ++++++++++++++++-- docs/components/form.njk | 79 +++++ docs/components/input.njk | 2 - docs/components/label.njk | 19 +- docs/components/popover.njk | 109 +++--- docs/components/select.njk | 95 ++--- docs/components/tabs.njk | 115 ++++++- docs/components/textarea.njk | 2 - 18 files changed, 933 insertions(+), 353 deletions(-) create mode 100644 docs/components/form.njk diff --git a/dist/basecoat.css b/dist/basecoat.css index 5915cc4..274c121 100644 --- a/dist/basecoat.css +++ b/dist/basecoat.css @@ -69,8 +69,6 @@ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); - --ease-in: cubic-bezier(0.4, 0, 1, 1); - --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --animate-spin: spin 1s linear infinite; --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; @@ -255,6 +253,9 @@ .pointer-events-none { pointer-events: none; } + .invisible { + visibility: hidden; + } .sr-only { position: absolute; width: 1px; @@ -383,6 +384,10 @@ .aspect-video { aspect-ratio: var(--aspect-video); } + .size-2 { + width: calc(var(--spacing) * 2); + height: calc(var(--spacing) * 2); + } .size-3\.5 { width: calc(var(--spacing) * 3.5); height: calc(var(--spacing) * 3.5); @@ -533,21 +538,10 @@ --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } - .translate-y-0 { - --tw-translate-y: calc(var(--spacing) * 0); - translate: var(--tw-translate-x) var(--tw-translate-y); - } .translate-y-0\.5 { --tw-translate-y: calc(var(--spacing) * 0.5); translate: var(--tw-translate-x) var(--tw-translate-y); } - .translate-y-2 { - --tw-translate-y: calc(var(--spacing) * 2); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .transform { - transform: var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y); - } .animate-pulse { animation: var(--animate-pulse); } @@ -720,6 +714,9 @@ .bg-background { background-color: var(--color-background); } + .bg-foreground { + background-color: var(--color-foreground); + } .bg-muted { background-color: var(--color-muted); } @@ -890,9 +887,6 @@ .text-sidebar-primary-foreground { color: var(--color-sidebar-primary-foreground); } - .text-transparent { - color: transparent; - } .text-zinc-50 { color: var(--color-zinc-50); } @@ -906,18 +900,12 @@ .underline-offset-4 { text-underline-offset: 4px; } - .opacity-0 { - opacity: 0%; - } .opacity-50 { opacity: 50%; } .opacity-60 { opacity: 60%; } - .opacity-100 { - opacity: 100%; - } .shadow-none { --tw-shadow: 0 0 #0000; box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); @@ -947,11 +935,6 @@ .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } - .transition { - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - } .transition-\[margin-left\] { transition-property: margin-left; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -981,22 +964,10 @@ --tw-duration: 200ms; transition-duration: 200ms; } - .duration-300 { - --tw-duration: 300ms; - transition-duration: 300ms; - } - .ease-in { - --tw-ease: var(--ease-in); - transition-timing-function: var(--ease-in); - } .ease-in-out { --tw-ease: var(--ease-in-out); transition-timing-function: var(--ease-in-out); } - .ease-out { - --tw-ease: var(--ease-out); - transition-timing-function: var(--ease-out); - } .outline-none { --tw-outline-style: none; outline-style: none; @@ -1010,6 +981,11 @@ rotate: 180deg; } } + .group-aria-checked\:visible { + &:is(:where(.group)[aria-checked="true"] *) { + visibility: visible; + } + } .peer-aria-hidden\:ml-0 { &:is(:where(.peer)[aria-hidden="true"] ~ *) { margin-left: calc(var(--spacing) * 0); @@ -1564,16 +1540,6 @@ height: calc(var(--spacing) * 4); } } - .\[\&\>\[role\=img\]\>svg\]\:w-full { - &>[role=img]>svg { - width: 100%; - } - } - .\[\&\>\[role\=img\]\>svg\]\:shrink-0 { - &>[role=img]>svg { - flex-shrink: 0; - } - } .\[\&\>h2\]\:mt-16 { &>h2 { margin-top: calc(var(--spacing) * 16); @@ -2780,7 +2746,7 @@ translate: var(--tw-translate-x) var(--tw-translate-y); } } - [role='menuitem'], [role='option'] { + [role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio'], [role='option'] { position: relative; display: flex; width: 100%; @@ -2829,7 +2795,7 @@ color: var(--color-muted-foreground); } } - [role='menuitem'] { + [role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio'] { &:hover { @media (hover: hover) { background-color: var(--color-accent); @@ -3676,6 +3642,7 @@ [data-tooltip] { position: relative; &:before { + pointer-events: none; visibility: hidden; position: absolute; z-index: 50; @@ -3710,6 +3677,9 @@ scale: var(--tw-scale-x) var(--tw-scale-y); opacity: 100%; } + &:focus-visible:not(:hover):before { + display: none; + } &:not([data-side]), &[data-side='top'] { &::before { content: var(--tw-content); @@ -3930,6 +3900,9 @@ li { margin-bottom: calc(var(--spacing) * 2); } + ul, ol { + margin-block: calc(var(--spacing) * 2); + } } .prose > *:first-child { margin-top: calc(var(--spacing) * 0) !important; @@ -3983,31 +3956,6 @@ inherits: false; initial-value: 0; } -@property --tw-rotate-x { - syntax: "*"; - inherits: false; - initial-value: rotateX(0); -} -@property --tw-rotate-y { - syntax: "*"; - inherits: false; - initial-value: rotateY(0); -} -@property --tw-rotate-z { - syntax: "*"; - inherits: false; - initial-value: rotateZ(0); -} -@property --tw-skew-x { - syntax: "*"; - inherits: false; - initial-value: skewX(0); -} -@property --tw-skew-y { - syntax: "*"; - inherits: false; - initial-value: skewY(0); -} @property --tw-space-y-reverse { syntax: "*"; inherits: false; @@ -4222,11 +4170,6 @@ --tw-translate-x: 0; --tw-translate-y: 0; --tw-translate-z: 0; - --tw-rotate-x: rotateX(0); - --tw-rotate-y: rotateY(0); - --tw-rotate-z: rotateZ(0); - --tw-skew-x: skewX(0); - --tw-skew-y: skewY(0); --tw-space-y-reverse: 0; --tw-space-x-reverse: 0; --tw-border-style: solid; diff --git a/dist/basecoat.tailwind.css b/dist/basecoat.tailwind.css index f79a2db..9420de0 100644 --- a/dist/basecoat.tailwind.css +++ b/dist/basecoat.tailwind.css @@ -627,10 +627,14 @@ } } [role='menuitem'], + [role='menuitemcheckbox'], + [role='menuitemradio'], [role='option'] { @apply aria-hidden:hidden [&_svg]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none [&_svg]:shrink-0 [&_svg]:size-4 aria-disabled:opacity-50 aria-disabled:pointer-events-none disabled:opacity-50 disabled:pointer-events-none w-full truncate; } - [role='menuitem'] { + [role='menuitem'], + [role='menuitemcheckbox'], + [role='menuitemradio'] { @apply focus-visible:bg-accent focus-visible:text-accent-foreground hover:bg-accent hover:text-accent-foreground; } [role='option'] { @@ -860,11 +864,14 @@ @apply relative; &:before { - @apply absolute content-[attr(data-tooltip)] bg-primary text-primary-foreground z-50 truncate max-w-xs w-fit rounded-md px-3 py-1.5 text-xs invisible opacity-0 scale-95 transition-all; + @apply absolute content-[attr(data-tooltip)] bg-primary text-primary-foreground z-50 truncate max-w-xs w-fit rounded-md px-3 py-1.5 text-xs invisible opacity-0 scale-95 transition-all pointer-events-none; } &:hover:before { @apply visible opacity-100 scale-100; } + &:focus-visible:not(:hover):before { + @apply hidden; + } &:not([data-side]), &[data-side='top'] { @apply before:bottom-full before:mb-1.5 before:translate-y-2 hover:before:translate-y-0 ; @@ -979,6 +986,10 @@ li { @apply mb-2; } + ul, + ol { + @apply my-2; + } } .prose > *:first-child { @apply !mt-0; diff --git a/docs/_includes/components/dropdown-menu-script.njk b/docs/_includes/components/dropdown-menu-script.njk index eb6c707..3bc772c 100644 --- a/docs/_includes/components/dropdown-menu-script.njk +++ b/docs/_includes/components/dropdown-menu-script.njk @@ -10,7 +10,7 @@ init() { this.$nextTick(() => { - this.menuItems = Array.from(this.$el.querySelectorAll('[role=menuitem]:not([disabled])')); + this.menuItems = Array.from(this.$el.querySelectorAll('[role=menuitem]:not([disabled]),[role=menuitemcheckbox]:not([disabled]),[role=menuitemradio]:not([disabled])')); }); }, focusMenuitem() { @@ -44,7 +44,7 @@ } }, handleMenuitemClick(event) { - const menuitem = event.target.closest('[role=menuitem]'); + const menuitem = event.target.closest('[role=menuitem],[role=menuitemcheckbox],[role=menuitemradio]'); if (menuitem && menuitem.getAttribute('aria-disabled') !== 'true' && !menuitem.disabled) { this.$nextTick(() => { this.$refs.trigger.focus(); @@ -53,7 +53,7 @@ } }, handleMenuitemMousemove(event) { - const menuitem = event.target.closest('[role=menuitem]'); + const menuitem = event.target.closest('[role=menuitem],[role=menuitemcheckbox],[role=menuitemradio]'); if (menuitem && menuitem.getAttribute('aria-disabled') !== 'true' && !menuitem.disabled) { this.focusedIndex = this.menuItems.indexOf(menuitem); this.focusMenuitem(); diff --git a/docs/_includes/components/tabs.njk b/docs/_includes/components/tabs.njk index 8a0d43f..7135365 100644 --- a/docs/_includes/components/tabs.njk +++ b/docs/_includes/components/tabs.njk @@ -20,7 +20,7 @@ {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %} {% endfor %} > -
{% endfor %} -
+ {% for tabset in tabsets %} {% if tabset.panel %} diff --git a/docs/_includes/partials/kitchen-sink/dialog.njk b/docs/_includes/partials/kitchen-sink/dialog.njk index eb8b98f..21965fa 100644 --- a/docs/_includes/partials/kitchen-sink/dialog.njk +++ b/docs/_includes/partials/kitchen-sink/dialog.njk @@ -66,7 +66,7 @@ type="button" class="btn-outline" > - Trigger dialog:control + Trigger dialog:open diff --git a/docs/_includes/partials/kitchen-sink/dropdown-menu.njk b/docs/_includes/partials/kitchen-sink/dropdown-menu.njk index 5b5cd47..b9a481f 100644 --- a/docs/_includes/partials/kitchen-sink/dropdown-menu.njk +++ b/docs/_includes/partials/kitchen-sink/dropdown-menu.njk @@ -8,12 +8,12 @@
{% call dropdown_menu( id="dropdown-menu", - trigger="Open Menu", + trigger="Open", trigger_attrs={"class": "btn-outline"}, content_attrs={"class": "min-w-56"} ) %}
- Account Options + My Account {% endcall %} + {% call dropdown_menu( + id="dropdown-menu-checkboxes", + trigger="Checkboxes", + trigger_attrs={"class": "btn-outline"}, + content_attrs={"class": "min-w-56"}, + register_on=["alpine:init", "htmx:afterSwap"] + ) %} +
+ Account Options + + + +
+
+
+ Appearance + + + +
+
+ + {% endcall %} + + + {% set profile_menu %}
@hunvreus @@ -69,28 +160,79 @@ Notifications
-
- Theme - - - -
-
{% endset %} + {% call dropdown_menu( + id="dropdown-menu-radio-group", + trigger="Radio Group", + trigger_attrs={"class": "btn-outline"}, + content_attrs={"class": "min-w-56"}, + register_on=["alpine:init", "htmx:afterSwap"] + ) %} +
+ Panel Position +
+ + + +
+ {% endcall %} + {% set trigger %} @hunvreus
diff --git a/docs/components/alert-dialog.njk b/docs/components/alert-dialog.njk index 440daee..56d8059 100644 --- a/docs/components/alert-dialog.njk +++ b/docs/components/alert-dialog.njk @@ -6,6 +6,8 @@ toc: - label: Usage id: usage children: + - label: HTML + Javascript + id: usage-default - label: Jinja or Nunjucks id: usage-jinja --- @@ -14,7 +16,8 @@ toc: {% from "macros/code_block.njk" import code_block %} {% from "components/dialog.njk" import dialog %} -{% set code %}{% set footer %} +{% set code_html %} +{% set footer %} {% endset %} @@ -28,39 +31,35 @@ toc: close_button=false, close_on_overlay_click=false, register_on=["alpine:init", "htmx:afterSwap"] -) }}{% endset %} -{{ code_preview("alert-dialog", code | prettyHtml) }} +) }} +{% endset %} + +{% set code_script %} +{% include "components/dialog-script.njk" %} +{% endset %} + +{{ code_preview("alert-dialog", code_script | prettyHtml ~ code_html | prettyHtml) }}

Usage

+

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
+

The Alert Dialog component uses the same Alpine.js code as the Dialog component with one small difference: we set initialCloseOnOverlayClick to false to prevent the dialog from closing when the overlay is clicked.

-

HTML

- -
-{% set code_html %}{% set footer %} - - -{% endset %} -{{ dialog( - id="alert-dialog", - title="Are you absolutely sure?", - description="This action cannot be undone. This will permanently delete your account and remove your data from our servers.", - trigger="Open alert dialog", - trigger_attrs={"class": "btn-outline"}, - footer=footer, - close_button=false, - close_on_overlay_click=false - ) }}{% endset %} - {{ code_block(code_html | prettyHtml) }} -
- -

Javascript (Alpine.js)

- -
- {% set code_script %}{% include "components/dialog-script.njk" %}{% endset %} - {{ code_block(code_script | prettyHtml) }} -
+{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="alert-dialog", tabsets=tabsets) }}

Jinja or Nunjucks

diff --git a/docs/components/breadcrumb.njk b/docs/components/breadcrumb.njk index 5ab0767..fa2dd17 100644 --- a/docs/components/breadcrumb.njk +++ b/docs/components/breadcrumb.njk @@ -16,8 +16,12 @@ toc:

There is no dedicated breadcrumb component in Basecoat.

-{% set code_script %}{% include "components/dropdown-menu-script.njk" %}{% endset %} -{% set code_html %}
    +{% set code_script %} +{% include "components/dropdown-menu-script.njk" %} +{% endset %} + +{% set code_html %} +
    1. Home
    2. @@ -47,8 +51,10 @@ toc:
    3. Breadcrumb
    4. -
    {% endset %} -{{ code_preview("dropdown-menu", code_script ~ code_html | prettyHtml) }} +
+{% endset %} + +{{ code_preview("dropdown-menu", code_script | prettyHtml ~ code_html | prettyHtml) }}

Usage

@@ -56,14 +62,9 @@ toc:

The example above uses some simple Tailwind CSS along with the Dropdown Menu.

-

HTML

- -
- {{ code_block(code_html | prettyHtml) }} -
- -

Javascript (Alpine.js) for the Dropdown Menu

- -
- {{ code_block(code_script | prettyHtml) }} -
\ No newline at end of file +{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="alert-dialog", tabsets=tabsets) }} \ No newline at end of file diff --git a/docs/components/combobox.njk b/docs/components/combobox.njk index c2cb280..5dda31c 100644 --- a/docs/components/combobox.njk +++ b/docs/components/combobox.njk @@ -6,6 +6,8 @@ toc: - label: Usage id: usage children: + - label: HTML + Javascript + id: usage-default - label: Jinja or Nunjucks id: usage-jinja - label: Examples @@ -22,7 +24,7 @@ toc: {% from "components/select.njk" import select %} {% set options_frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"] %} -{% set code %} +{% set code_html %} {% call select( trigger_attrs={"class": "w-[200px]"}, listbox_attrs={"data-empty": "No framework found."}, @@ -33,11 +35,27 @@ toc: {% for framework in options_frameworks %}
{{ framework }}
{% endfor %} -{% endcall %}{% endset %} -{{ code_preview("combobox", code | prettyHtml) }} +{% endcall %} +{% endset %} + +{% set code_script %} +{% include "components/select-script.njk" %} +{% endset %} + +{{ code_preview("combobox", code_script | prettyHtml ~ code_html | prettyHtml) }}

Usage

+

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
+

Combobox uses the same Alpine.js code and markup as the Select component, the only difference being the search box at the top of the listbox.

You can set up a few additional options on the <div data-popover> element:

@@ -48,30 +66,12 @@ toc:
-

HTML

- -
- {% set code_html %} - {% call select( - trigger_attrs={"class": "w-[200px]"}, - listbox_attrs={"data-empty": "No framework found."}, - is_combobox=true, - search_placeholder="Search framework...", - register_on=["alpine:init", "htmx:afterSwap"] - ) %} - {% for framework in options_frameworks %} -
{{ framework }}
- {% endfor %} - {% endcall %}{% endset %} - {{ code_block(code_html | prettyHtml) }} -
- -

Javascript (Alpine.js)

- -
- {% set code_script %}{% include "components/select-script.njk" %}{% endset %} - {{ code_block(code_script | prettyHtml) }} -
+{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="combobox", tabsets=tabsets) }}

Jinja or Nunjucks

diff --git a/docs/components/dialog.njk b/docs/components/dialog.njk index e348af5..e8e3edc 100644 --- a/docs/components/dialog.njk +++ b/docs/components/dialog.njk @@ -6,7 +6,7 @@ toc: - label: Usage id: usage children: - - label: Default + - label: HTML + Javascript id: usage-default - label: Jinja or Nunjucks id: usage-jinja @@ -21,7 +21,7 @@ toc: {% from "macros/code_preview.njk" import code_preview %} {% from "components/dialog.njk" import dialog %} -{% set code %} +{% set code_html %} {% set footer %} @@ -49,47 +49,79 @@ toc: {% endcall %} {% endset %} -{{ code_preview("dialog", code | prettyHtml) }} + +{% set code_script %} +{% include "components/dialog-script.njk" %} +{% endset %} + +{{ code_preview("dialog", code_script | prettyHtml ~ code_html | prettyHtml) }}

Usage

-

Default

+

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
-

-
- -{{ code_block(code | prettyHtml) }} - -

Jinja or Nunjucks

- -
-

If you use Jinja (or Nunjucks), you can use the dialog() macro directly, making sure to set close_on_overlay_click to False (or false for Nunjucks).

+

The component is structured as such:

    -
  • - Read more about using Basecoat with Jinja or Nunjucks -
  • -
  • - Read more about the Dialog component +
  • A <div class="dialog"> which wraps around the entire component and holds it state (e.g. open/close).
  • +
  • A <button> that acts as the trigger to open or close the popover.
  • +
  • A <div role="dialog"> that holds the dialog itself. It also acts as the backdrop for the dialog.
  • +
  • Inside of it, we have: +
      +
    • A <header> that contains the title (<h2>) and description (<p>) of the dialog.
    • +
    • A <section> for the content.
    • +
    • A <footer> that usually contains actions.
    • +
    • A close <button>.
    • +
+{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="combobox", tabsets=tabsets) }} + +

Jinja or Nunjucks

+ +

If you use Jinja (or Nunjucks), you can use the dialog() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

+ {% set raw_code %}{% raw %}{% set footer %} - + {% endset %} -{{ dialog( - id="demo-alert-dialog", - title="Are you absolutely sure?", - description="This action cannot be undone. This will permanently delete your account and remove your data from our servers.", - trigger="Open Alert Dialog", +{% call dialog( + id="demo-dialog-edit-profile", + title="Edit profile", + description="Make changes to your profile here. Click save when you're done.", + main_attrs={"x-ref": "myDialog"}, + trigger="Edit Profile", trigger_attrs={"class": "btn-outline"}, + content_attrs={"class": "w-full sm:max-w-[425px] max-h-[612px]"}, footer=footer, - close_button=False, - close_on_overlay_click=False -) }}{% endraw %} -{% endset%} + register_on=["alpine:init", "htmx:afterSwap"] +) %} +
+
+ + +
+
+ + +
+
+{% endcall %}{% endraw %}{% endset%} {{ code_block(raw_code, "jinja") }}

Examples

diff --git a/docs/components/dropdown-menu.njk b/docs/components/dropdown-menu.njk index 0cfbeeb..75ad49f 100644 --- a/docs/components/dropdown-menu.njk +++ b/docs/components/dropdown-menu.njk @@ -2,19 +2,179 @@ layout: layouts/component.njk title: Dropdown Menu description: Displays a menu to the user — such as a set of actions or functions — triggered by a button. +toc: + - label: Usage + id: usage + children: + - label: HTML + Javascript + id: usage-default + - label: Jinja or Nunjucks + id: usage-jinja + - label: Examples + id: examples + children: + - label: Checkboxes + id: example-checkboxes + - label: Radio Group + id: example-radio-group --- {% from "macros/code_block.njk" import code_block %} {% from "macros/code_preview.njk" import code_preview %} {% from "components/dropdown-menu.njk" import dropdown_menu %} -{% set code %}{% call dropdown_menu( +{% set code_html %} +{% call dropdown_menu( id="dropdown-menu", trigger="Open", trigger_attrs={"class": "btn-outline"}, content_attrs={"class": "min-w-56"}, register_on=["alpine:init", "htmx:afterSwap"] ) %} +
+ My Account + + + + +
+
+ + + +
+ +{% endcall %} +{% endset %} + +{% set code_script %} +{% include "components/dropdown-menu-script.njk" %} +{% endset %} + +{{ code_preview("dropdown-menu", code_script | prettyHtml ~ code_html | prettyHtml) }} + +

Usage

+ +

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
+ +
+

The component is structured as such:

+
    +
  • A <div class="popover"> which wraps around the entire component and holds it state (e.g. open/close).
  • +
  • A <button> that acts as the trigger to open or close the popover.
  • +
  • A <div data-popover> that holds the content of the popover.
  • +
  • Inside of the <div data-popover> is a <nav role="menu"> that contains a combination of: +
      +
    • <button role="menuitem"> for menu items.
    • +
    • <button role="menuitemcheckbox"> for menu items with checkboxes.
    • +
    • <button role="menuitemradio"> for menu items with radio buttons.
    • +
    • <hr role="separator"> to display a horizontal separator.
    • +
    • <div role="group"> to group options.
    • +
    • <span role="heading"> for group headings.
    • +
    +
+

As with the Popover component, you can set up a few additional options on the <div data-popover> element:

+
    +
  • data-side can be set to top, bottom, left, or right to change the side of the popover.
  • +
  • data-align can be set to start, center, or end to change the alignment of the popover.
  • +
+
+ +{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="dropdown-menu", tabsets=tabsets) }} + +

Jinja or Nunjucks

+ +

If you use Jinja (or Nunjucks), you can use the dropdown_menu() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

+ +{% set raw_code %}{% raw %}{% call dropdown_menu( + id="dropdown-menu", + trigger="Open", + trigger_attrs={"class": "btn-outline"}, + content_attrs={"class": "min-w-56"}, + register_on=["alpine:init", "htmx:afterSwap"] +) %} +
+ My Account + + + + +
+
+ + + +
+ +{% endcall %}{% endraw %}{% endset%} +{{ code_block(raw_code, "jinja") }} + +

Examples

+ +

Checkboxes

+ +{% set code %}{% call dropdown_menu( + id="dropdown-menu-checkboxes", + trigger="Open", + trigger_attrs={"class": "btn-outline"}, + content_attrs={"class": "min-w-56"}, + register_on=["alpine:init", "htmx:afterSwap"] +) %}
Account Options -

- - - +
+ Appearance + + + +

{% endcall %}{% endset %} -{{ code_preview("dropdown-menu", code | prettyHtml) }} + +{% endcall %}{% endset %} +{{ code_preview("dropdown-menu-checkboxes", code | prettyHtml) }} -

Usage

+

Radio Group

-
-

You can use one of the btn classes to style any element as a button:

- -
    -
  • - Variants: btn or btn-primary for primary - buttons, then btn-secondary, btn-destructive, btn-outline, - btn-ghost, btn-link. You can also use btn-icon to - style an icon as a button, along with all of its variants (e.g. btn-icon-destructive). -
  • -
  • - Sizes: btn-sm for small and btn-lg for large. - You can combine this with other attributes, for example btn-lg-destructive - or btn-icon-sm-secondary. -
  • -
-
\ No newline at end of file +{% set code %}{% call dropdown_menu( + id="dropdown-menu-radio-group", + trigger="Open", + trigger_attrs={"class": "btn-outline"}, + content_attrs={"class": "min-w-56"}, + register_on=["alpine:init", "htmx:afterSwap"] +) %} +
+ Panel Position +
+ + + +
+{% endcall %}{% endset %} +{{ code_preview("dropdown-menu", code | prettyHtml) }} \ No newline at end of file diff --git a/docs/components/form.njk b/docs/components/form.njk new file mode 100644 index 0000000..e911e73 --- /dev/null +++ b/docs/components/form.njk @@ -0,0 +1,79 @@ +--- +layout: layouts/component.njk +title: Input +description: Displays a form input field or a component that looks like an input field. +toc: + - label: Usage + id: usage +--- + +{% from "macros/code_preview.njk" import code_preview %} +{% from "macros/code_block.njk" import code_block %} + +{% set code %}
+
+ + +

This is your public display name.

+
+ +
+ + +

You can manage email addresses in your email settings.

+
+ +
+ + +

You can @mention other users and organizations.

+
+ +
+ + +

Your date of birth is used to calculate your age.

+
+ +
+ +
+ + + +
+
+ +
+

Email Notifications

+
+
+ +

Receive emails about new products, features, and more.

+
+ +
+
+
+ +

Receive emails about your account security.

+
+ +
+
+ + +
{% endset %} +{{ code_preview("input", code, "w-full max-w-sm") }} + +

Usage

+ +
+

Adding the form class to the parent of any form element (<label>, <input>, <textarea>, <select>) will automatically apply the style you would get from adding label, input, textarea, or select classes. Read more about Label, Input, Textarea, and Select.

+
+ +{{ code_block(code) }} \ No newline at end of file diff --git a/docs/components/input.njk b/docs/components/input.njk index c54d19a..9e8d0a3 100644 --- a/docs/components/input.njk +++ b/docs/components/input.njk @@ -40,8 +40,6 @@ toc:

Examples

-

Default

- {{ code_preview("input-default", code) }}

Invalid

diff --git a/docs/components/label.njk b/docs/components/label.njk index d9b95ae..773aa71 100644 --- a/docs/components/label.njk +++ b/docs/components/label.njk @@ -5,6 +5,11 @@ description: Renders an accessible label associated with controls. toc: - label: Usage id: usage + - label: Examples + id: examples + children: + - label: Disabled + id: example-disabled --- {% from "macros/code_preview.njk" import code_preview %} @@ -19,8 +24,18 @@ toc:

Usage

-

Simply add the label class to your <label> element or have a parent with the form class (read more about form). Labels will be styled accordingly if a peer or child element is disabled.

+

Simply add the label class to your <label> element or have a parent with the form class (read more about form). Labels' style may be affected by the presence of a disabled peer or child element.

{% set code %}{% endset %} -{{ code_block(code) }} \ No newline at end of file +{{ code_block(code) }} + +

Examples

+ +

Disabled

+ +{% set code %}
+ + +
{% endset %} +{{ code_preview("label-disabled", code) }} \ No newline at end of file diff --git a/docs/components/popover.njk b/docs/components/popover.njk index 645b33c..cdb1176 100644 --- a/docs/components/popover.njk +++ b/docs/components/popover.njk @@ -6,7 +6,7 @@ toc: - label: Usage id: usage children: - - label: Default + - label: HTML + Javascript id: usage-default - label: Jinja or Nunjucks id: usage-jinja @@ -16,7 +16,7 @@ toc: {% from "macros/code_block.njk" import code_block %} {% from "components/popover.njk" import popover %} -{% set code %} +{% set code_html %} {% call popover( id="demo-popover", trigger="Open popover", @@ -32,13 +32,7 @@ toc:
- +
@@ -56,61 +50,82 @@ toc:
{% endcall %} {% endset %} -{{ code_preview("popover", code | prettyHtml ) }} + +{% set code_script %} +{% include "components/popover-script.njk" %} +{% endset %} + +{{ code_preview("combobox", code_script | prettyHtml ~ code_html | prettyHtml) }}

Usage

-

Default

+

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
-

If you need to do more than what <select> allows (e.g. HTML options), you can use the code below which uses the Popover component. Make sure to include the hidden input with the name you want to use for that field.

+

The component is structured as such:

+
    +
  • A <div class="popover"> which wraps around the entire component and holds it state (e.g. open/close).
  • +
  • A <button> that acts as the trigger to open or close the popover.
  • +
  • A <div data-popover> that holds the content of the popover.
  • +
+

You can set up a few additional options on the <div data-popover> element:

+
    +
  • data-side can be set to top, bottom, left, or right to change the side of the popover.
  • +
  • data-align can be set to start, center, or end to change the alignment of the popover.
  • +
-{{ code_block(code | prettyHtml) }} +{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="popover", tabsets=tabsets) }}

Jinja or Nunjucks

-

If you use Jinja (or Nunjucks), you can use the popover() macro directly.

- +

If you use Jinja (or Nunjucks), you can use the popover() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

{% set raw_code %}{% raw %}{% call popover( id="demo-popover", trigger="Open popover", trigger_attrs={"class": "btn-outline"}, - content_attrs={"class": "w-80 p-4"} + content_attrs={"class": "w-80 p-4"}, + register_on=["alpine:init", "htmx:afterSwap"] ) %} -
-
-

Dimensions

-

Set the dimensions for the layer.

-
- -
- - -
-
- - -
-
- - -
-
- - -
- -
+
+
+

Dimensions

+

Set the dimensions for the layer.

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
{% endcall %}{% endraw %}{% endset %} {{ code_block(raw_code, "jinja") }} \ No newline at end of file diff --git a/docs/components/select.njk b/docs/components/select.njk index 71eb12e..f7f0059 100644 --- a/docs/components/select.njk +++ b/docs/components/select.njk @@ -6,8 +6,10 @@ toc: - label: Usage id: usage children: - - label: Default - id: usage-default + - label: HTML + id: usage-html + - label: HTML + Javascript + id: usage-js - label: Jinja or Nunjucks id: usage-jinja - label: Examples @@ -35,7 +37,7 @@ toc: {% endset %} {{ code_preview("select-native", code_native) }} -{% set code_alpine %} +{% set code_html %} {% call select( name="select-js", trigger_attrs={"class": "w-[180px]"}, @@ -51,11 +53,16 @@ toc:
{% endcall %} {% endset %} -{{ code_preview("select", code_alpine | prettyHtml) }} + +{% set code_script %} +{% include "components/select-script.njk" %} +{% endset %} + +{{ code_preview("combobox", code_script | prettyHtml ~ code_html | prettyHtml) }}

Usage

-

Pure HTML

+

HTML

If you use a <select> element, just add the select class to it or have a parent with the form class (read more about form).

@@ -63,55 +70,49 @@ toc: {{ code_block(code_native) }} -

With Javascript

+

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
-

If you need to do more than what <select> allows (e.g. HTML options), you can use the code below which uses the Popover component. Make sure to include the hidden input with the name you want to use for that field.

+

If you need to do more than what <select> allows (e.g. HTML options), you can use this component. It is structured as such:

+
    +
  • A <div class="popover"> which wraps around the entire component and holds it state (e.g. open/close).
  • +
  • A <button> that acts as the trigger to open or close the popover.
  • +
  • A <div data-popover> that holds the content of the popover.
  • +
  • Inside of the <div data-popover> is a <nav role="listbox"> that contains a combination of: +
      +
    • <div role="option"> for the options with a data-value attribute.
    • +
    • <hr role="separator"> to display a horizontal separator.
    • +
    • <div role="group"> to group options.
    • +
    • <span role="heading"> for group headings.
    • +
    +
  • +
  • An <input type="hidden"> to hold the value of the field (if needed).
  • +
+

As with the Popover component, you can set up a few additional options on the <div data-popover> element:

+
    +
  • data-side can be set to top, bottom, left, or right to change the side of the popover.
  • +
  • data-align can be set to start, center, or end to change the alignment of the popover.
  • +
-

HTML

- -
- {% set code_html %} - {% call select( - name="select-js", - trigger_attrs={"class": "w-[180px]"}, - register_on=["alpine:init", "htmx:afterSwap"], - include_script=false - ) %} -
- Fruits -
Apple
-
Banana
-
Blueberry
-
Grapes
-
Pineapple
-
- {% endcall %} - {% endset %} - {{ code_block(code_html | prettyHtml) }} -
- -

Javascript

- -
- {% set code_script %}{% include "components/select-script.njk" %}{% endset %} - {{ code_block(code_script | prettyHtml, "html") }} -
+{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="select", tabsets=tabsets) }}

Jinja or Nunjucks

-
-

If you use Jinja (or Nunjucks), you can use the select() macro directly.

- -
+

If you use Jinja (or Nunjucks), you can use the dropdown_menu() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

{% set raw_code %}{% raw %}{% call select(name="select-js") %}
diff --git a/docs/components/tabs.njk b/docs/components/tabs.njk index ee06670..b7d1501 100644 --- a/docs/components/tabs.njk +++ b/docs/components/tabs.njk @@ -5,12 +5,18 @@ description: A set of layered sections of content—known as tab panels—that a toc: - label: Usage id: usage + children: + - label: HTML + Javascript + id: usage-default + - label: Jinja or Nunjucks + id: usage-jinja --- {% from "macros/code_preview.njk" import code_preview %} {% from "macros/code_block.njk" import code_block %} {% from "components/tabs.njk" import tabs %} -{% set code %} + +{% set code_html %} {% set account_panel %}
@@ -62,19 +68,110 @@ toc: { tab: "Password", panel: password_panel } ] %} {{ tabs( -id='demo-tabs-with-panels', -tabsets=tabsets_demo, -main_attrs={ "class": "w-full" }, -tablist_attrs={ "class": "w-full" }, -register_on=["alpine:init", "htmx:afterSwap"] + id='demo-tabs-with-panels', + tabsets=tabsets_demo, + main_attrs={ "class": "w-full" }, + tablist_attrs={ "class": "w-full" }, + register_on=["alpine:init", "htmx:afterSwap"] ) }} {% endset %} -{{ code_preview("tabs", code | prettyHtml, "max-w-[300px] w-full") }} + +{% set code_script %} +{% include "components/tabs-script.njk" %} +{% endset %} + +{{ code_preview("tabs", code_script | prettyHtml ~ code_html | prettyHtml, "max-w-[300px] w-full") }}

Usage

+

HTML + Javascript

+ +
+ {% lucide "circle-alert" %} +

This component requires Javascript.

+
+

You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. x-bind, x-data, @click).

+
+
+
-

You can style an <input type="range"> element by either adding the input class or having a parent with the form class (read more about form). However, the range input also requries some Javacript code to be able to paint the left side of the slider.

+

The component is structured as such:

+
    +
  • A <div class="tabs"> which wraps around the entire component and holds it state (e.g. open/close).
  • +
  • A <nav role="tablist"> that holds the tab buttons (<button role="tab">).
  • +
  • A series of <div role="tabpanel"> that holds the tab panels corresponding to each tab button.
  • +
-{{ code_block(code) }} \ No newline at end of file +{% from "components/tabs.njk" import tabs %} +{% set tabsets = [ + { tab: "HTML", panel: code_block(code_html | prettyHtml) }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } +] %} +{{ tabs(id="combobox", tabsets=tabsets) }} + +

Jinja or Nunjucks

+ +

If you use Jinja (or Nunjucks), you can use the tabs() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

+ +{% set raw_code %}{% raw %}{% set account_panel %} +
+
+

Account

+

Make changes to your account here. Click save when you're done.

+
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+
+{% endset %} + +{% set password_panel %} +
+
+

Password

+

Change your password here. After saving, you'll be logged out.

+
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+
+{% endset %} + +{% set tabsets_demo = [ +{ tab: "Account", panel: account_panel }, +{ tab: "Password", panel: password_panel } +] %} + +{{ tabs( + id='demo-tabs-with-panels', + tabsets=tabsets_demo, + main_attrs={ "class": "w-full" }, + tablist_attrs={ "class": "w-full" }, + register_on=["alpine:init", "htmx:afterSwap"] +) }}{% endraw %}{% endset%} +{{ code_block(raw_code, "jinja") }} \ No newline at end of file diff --git a/docs/components/textarea.njk b/docs/components/textarea.njk index fe51fb0..d220ee1 100644 --- a/docs/components/textarea.njk +++ b/docs/components/textarea.njk @@ -40,8 +40,6 @@ toc:

Examples

-

Default

- {{ code_preview("textarea-default", code, "w-full") }}

Invalid