angular-tailwind-components 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -118,7 +118,7 @@ Some components (for example `tailwind-card`, `tailwind-modal`, `tailwind-toolba
118
118
  - **Accordion** (`tailwind-accordion`): Expandable sections
119
119
  - **Tooltip** (`tailwind-tooltip`): Hover tooltip
120
120
  - **Form** (`tailwind-form`): Form wrapper
121
- - **Table** (`tailwind-table`): Data table with sorting
121
+ - **Table** (`tailwind-table`): Data table with projected header/rows, client-side sort and pagination
122
122
 
123
123
  ## Design System
124
124
 
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, Directive, signal, inject, NgZone, ElementRef, viewChild, computed, Component, ViewContainerRef, HostListener, Input, output, InjectionToken, model, forwardRef, viewChildren, effect, contentChildren, ApplicationRef, EnvironmentInjector, Injector, createComponent, Injectable, booleanAttribute } from '@angular/core';
2
+ import { input, Directive, signal, inject, NgZone, ElementRef, viewChild, computed, Component, ViewContainerRef, HostListener, Input, TemplateRef, Renderer2, effect, output, InjectionToken, model, forwardRef, viewChildren, contentChildren, contentChild, ApplicationRef, EnvironmentInjector, Injector, createComponent, Injectable, booleanAttribute } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { DOCUMENT, NgClass, NgTemplateOutlet, formatDate, CommonModule } from '@angular/common';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
@@ -1465,6 +1465,120 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
1465
1465
  args: ['focusout']
1466
1466
  }] } });
1467
1467
 
1468
+ /**
1469
+ * Row definition for `TailwindTable`. Prefer structural syntax on `<tbody>`:
1470
+ * `<tbody *tailwindTableRow="let row">...</tbody>` — each rendered fragment is one `<tbody>` per data row.
1471
+ *
1472
+ * Legacy: `<ng-template tailwindTableRow let-row>` with only `<td>` cells still works.
1473
+ */
1474
+ class TailwindTableRowDirective {
1475
+ templateRef = inject((TemplateRef));
1476
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindTableRowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1477
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.12", type: TailwindTableRowDirective, isStandalone: true, selector: "[tailwindTableRow]", ngImport: i0 });
1478
+ }
1479
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindTableRowDirective, decorators: [{
1480
+ type: Directive,
1481
+ args: [{
1482
+ selector: '[tailwindTableRow]',
1483
+ standalone: true
1484
+ }]
1485
+ }] });
1486
+
1487
+ /** Host attributes on `<tailwind-table>`; kept in sync for sort-header observers. */
1488
+ const TW_TABLE_SORT_KEY_ATTR = 'data-tw-sort-key';
1489
+ const TW_TABLE_SORT_DIR_ATTR = 'data-tw-sort-dir';
1490
+ /**
1491
+ * Sortable column header: put on `<th>` (plain header text + directive). Not sortable columns omit this directive.
1492
+ * Sorting is handled by the nearest `tailwind-table` host (event delegation); do not pass a table reference.
1493
+ */
1494
+ class TailwindSortHeaderDirective {
1495
+ /** Property key on each row used for sorting. */
1496
+ sortKey = input.required(...(ngDevMode ? [{ debugName: "sortKey" }] : /* istanbul ignore next */ []));
1497
+ host = inject((ElementRef));
1498
+ renderer = inject(Renderer2);
1499
+ svg;
1500
+ constructor() {
1501
+ effect(onCleanup => {
1502
+ const key = this.sortKey();
1503
+ const tableEl = this.host.nativeElement.closest('tailwind-table');
1504
+ if (!tableEl)
1505
+ return;
1506
+ const sync = () => {
1507
+ const activeKey = tableEl.getAttribute(TW_TABLE_SORT_KEY_ATTR) ?? '';
1508
+ const dirRaw = tableEl.getAttribute(TW_TABLE_SORT_DIR_ATTR) ?? 'asc';
1509
+ const asc = dirRaw === 'asc';
1510
+ const active = activeKey === key;
1511
+ if (!this.svg) {
1512
+ this.svg = this.createSvg();
1513
+ this.renderer.appendChild(this.host.nativeElement, this.svg);
1514
+ }
1515
+ this.updateSvg(active, asc);
1516
+ this.renderer.setAttribute(this.host.nativeElement, 'aria-label', active ? `Sorted ${asc ? 'ascending' : 'descending'}, activate to reverse` : `Sort by ${key}`);
1517
+ };
1518
+ sync();
1519
+ const mo = new MutationObserver(() => sync());
1520
+ mo.observe(tableEl, {
1521
+ attributes: true,
1522
+ attributeFilter: [TW_TABLE_SORT_KEY_ATTR, TW_TABLE_SORT_DIR_ATTR]
1523
+ });
1524
+ onCleanup(() => mo.disconnect());
1525
+ });
1526
+ }
1527
+ createSvg() {
1528
+ const svg = this.renderer.createElement('svg', 'svg');
1529
+ this.renderer.setAttribute(svg, 'xmlns', 'http://www.w3.org/2000/svg');
1530
+ this.renderer.setAttribute(svg, 'viewBox', '0 0 20 20');
1531
+ this.renderer.setAttribute(svg, 'fill', 'currentColor');
1532
+ this.renderer.setAttribute(svg, 'aria-hidden', 'true');
1533
+ const ascPath = this.renderer.createElement('path', 'svg');
1534
+ this.renderer.setAttribute(ascPath, 'fill-rule', 'evenodd');
1535
+ this.renderer.setAttribute(ascPath, 'd', 'M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z');
1536
+ this.renderer.setAttribute(ascPath, 'clip-rule', 'evenodd');
1537
+ this.renderer.addClass(ascPath, 'tailwind-sort-header__asc');
1538
+ const descPath = this.renderer.createElement('path', 'svg');
1539
+ this.renderer.setAttribute(descPath, 'fill-rule', 'evenodd');
1540
+ this.renderer.setAttribute(descPath, 'd', 'M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z');
1541
+ this.renderer.setAttribute(descPath, 'clip-rule', 'evenodd');
1542
+ this.renderer.addClass(descPath, 'tailwind-sort-header__desc');
1543
+ this.renderer.appendChild(svg, ascPath);
1544
+ this.renderer.appendChild(svg, descPath);
1545
+ return svg;
1546
+ }
1547
+ updateSvg(active, asc) {
1548
+ if (!this.svg)
1549
+ return;
1550
+ this.renderer.setAttribute(this.svg, 'class', `inline-block align-middle ml-1 w-3.5 h-3.5 shrink-0 ${active ? 'text-primary-600' : 'text-surface-400'}`);
1551
+ const ascPath = this.svg.querySelector('.tailwind-sort-header__asc');
1552
+ const descPath = this.svg.querySelector('.tailwind-sort-header__desc');
1553
+ const showAsc = active && asc;
1554
+ const showDesc = active ? !asc : true;
1555
+ this.setPathHidden(ascPath, !showAsc);
1556
+ this.setPathHidden(descPath, !showDesc);
1557
+ }
1558
+ setPathHidden(el, hidden) {
1559
+ if (!el)
1560
+ return;
1561
+ if (hidden)
1562
+ this.renderer.addClass(el, 'hidden');
1563
+ else
1564
+ this.renderer.removeClass(el, 'hidden');
1565
+ }
1566
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindSortHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1567
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.12", type: TailwindSortHeaderDirective, isStandalone: true, selector: "[tailwindSortHeader]", inputs: { sortKey: { classPropertyName: "sortKey", publicName: "sortKey", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.tabindex": "0", "attr.data-sort-key": "sortKey()" }, classAttribute: "cursor-pointer hover:text-surface-900 select-none table-cell align-middle whitespace-nowrap text-left" }, ngImport: i0 });
1568
+ }
1569
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindSortHeaderDirective, decorators: [{
1570
+ type: Directive,
1571
+ args: [{
1572
+ selector: '[tailwindSortHeader]',
1573
+ standalone: true,
1574
+ host: {
1575
+ class: 'cursor-pointer hover:text-surface-900 select-none table-cell align-middle whitespace-nowrap text-left',
1576
+ '[attr.tabindex]': '0',
1577
+ '[attr.data-sort-key]': 'sortKey()'
1578
+ }
1579
+ }]
1580
+ }], ctorParameters: () => [], propDecorators: { sortKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortKey", required: true }] }] } });
1581
+
1468
1582
  class TailwindButton extends TailwindComponent {
1469
1583
  /** Visual color */
1470
1584
  color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
@@ -2874,8 +2988,6 @@ class TailwindAlert extends TailwindComponent {
2874
2988
  severity = input('info', ...(ngDevMode ? [{ debugName: "severity" }] : /* istanbul ignore next */ []));
2875
2989
  /** Alert title */
2876
2990
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
2877
- /** Alert message */
2878
- message = input('', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
2879
2991
  /** Whether the alert can be dismissed */
2880
2992
  dismissible = input(false, ...(ngDevMode ? [{ debugName: "dismissible" }] : /* istanbul ignore next */ []));
2881
2993
  /** Whether to show a border on the left */
@@ -2900,12 +3012,12 @@ class TailwindAlert extends TailwindComponent {
2900
3012
  this.onDismiss.emit();
2901
3013
  }
2902
3014
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAlert, deps: null, target: i0.ɵɵFactoryTarget.Component });
2903
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindAlert, isStandalone: true, selector: "tailwind-alert", inputs: { severity: { classPropertyName: "severity", publicName: "severity", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onDismiss: "onDismiss" }, usesInheritance: true, ngImport: i0, template: "@if (!dismissed()) {\n <div [class]=\"computedClasses()\" role=\"alert\" [attr.aria-live]=\"severity() === 'danger' ? 'assertive' : 'polite'\">\n <!-- Icon -->\n <div class=\"shrink-0 mt-0.5\">\n @switch (severity()) {\n @case ('success') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n @case ('warning') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n @case ('danger') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n @case ('info') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n }\n </div>\n\n <!-- Content -->\n <div class=\"flex-1 min-w-0\">\n @if (title()) {\n <h3 class=\"text-sm font-semibold mb-0.5\">{{ title() }}</h3>\n }\n <div class=\"text-sm\">\n {{ message() }}\n </div>\n </div>\n\n <!-- Dismiss button -->\n @if (dismissible()) {\n <button\n type=\"button\"\n class=\"shrink-0 -m-1 p-1 rounded-md opacity-70 hover:opacity-100 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 cursor-pointer\"\n [attr.aria-label]=\"'Dismiss alert'\"\n (click)=\"dismiss()\">\n <svg class=\"w-4 h-4\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\n </svg>\n </button>\n }\n </div>\n}\n", styles: [":host{display:block}\n"] });
3015
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindAlert, isStandalone: true, selector: "tailwind-alert", inputs: { severity: { classPropertyName: "severity", publicName: "severity", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onDismiss: "onDismiss" }, usesInheritance: true, ngImport: i0, template: "@if (!dismissed()) {\r\n <div [class]=\"computedClasses()\" role=\"alert\" [attr.aria-live]=\"severity() === 'danger' ? 'assertive' : 'polite'\">\r\n <!-- Icon -->\r\n <div class=\"shrink-0 mt-0.5\">\r\n @switch (severity()) {\r\n @case ('success') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n @case ('warning') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n @case ('danger') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n @case ('info') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Content -->\r\n <div class=\"flex-1 min-w-0\">\r\n @if (title()) {\r\n <h3 class=\"text-sm font-semibold mb-0.5\">{{ title() }}</h3>\r\n }\r\n <div class=\"text-sm\">\r\n <ng-content />\r\n </div>\r\n </div>\r\n\r\n <!-- Dismiss button -->\r\n @if (dismissible()) {\r\n <button\r\n type=\"button\"\r\n class=\"shrink-0 -m-1 p-1 rounded-md opacity-70 hover:opacity-100 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 cursor-pointer\"\r\n [attr.aria-label]=\"'Dismiss alert'\"\r\n (click)=\"dismiss()\">\r\n <svg class=\"w-4 h-4\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block}\n"] });
2904
3016
  }
2905
3017
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAlert, decorators: [{
2906
3018
  type: Component,
2907
- args: [{ selector: 'tailwind-alert', template: "@if (!dismissed()) {\n <div [class]=\"computedClasses()\" role=\"alert\" [attr.aria-live]=\"severity() === 'danger' ? 'assertive' : 'polite'\">\n <!-- Icon -->\n <div class=\"shrink-0 mt-0.5\">\n @switch (severity()) {\n @case ('success') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n @case ('warning') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n @case ('danger') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n @case ('info') {\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n }\n }\n </div>\n\n <!-- Content -->\n <div class=\"flex-1 min-w-0\">\n @if (title()) {\n <h3 class=\"text-sm font-semibold mb-0.5\">{{ title() }}</h3>\n }\n <div class=\"text-sm\">\n {{ message() }}\n </div>\n </div>\n\n <!-- Dismiss button -->\n @if (dismissible()) {\n <button\n type=\"button\"\n class=\"shrink-0 -m-1 p-1 rounded-md opacity-70 hover:opacity-100 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 cursor-pointer\"\n [attr.aria-label]=\"'Dismiss alert'\"\n (click)=\"dismiss()\">\n <svg class=\"w-4 h-4\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\n </svg>\n </button>\n }\n </div>\n}\n", styles: [":host{display:block}\n"] }]
2908
- }], propDecorators: { severity: [{ type: i0.Input, args: [{ isSignal: true, alias: "severity", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], onDismiss: [{ type: i0.Output, args: ["onDismiss"] }] } });
3019
+ args: [{ selector: 'tailwind-alert', template: "@if (!dismissed()) {\r\n <div [class]=\"computedClasses()\" role=\"alert\" [attr.aria-live]=\"severity() === 'danger' ? 'assertive' : 'polite'\">\r\n <!-- Icon -->\r\n <div class=\"shrink-0 mt-0.5\">\r\n @switch (severity()) {\r\n @case ('success') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n @case ('warning') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n @case ('danger') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n @case ('info') {\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z\"\r\n clip-rule=\"evenodd\" />\r\n </svg>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Content -->\r\n <div class=\"flex-1 min-w-0\">\r\n @if (title()) {\r\n <h3 class=\"text-sm font-semibold mb-0.5\">{{ title() }}</h3>\r\n }\r\n <div class=\"text-sm\">\r\n <ng-content />\r\n </div>\r\n </div>\r\n\r\n <!-- Dismiss button -->\r\n @if (dismissible()) {\r\n <button\r\n type=\"button\"\r\n class=\"shrink-0 -m-1 p-1 rounded-md opacity-70 hover:opacity-100 transition-opacity focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 cursor-pointer\"\r\n [attr.aria-label]=\"'Dismiss alert'\"\r\n (click)=\"dismiss()\">\r\n <svg class=\"w-4 h-4\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block}\n"] }]
3020
+ }], propDecorators: { severity: [{ type: i0.Input, args: [{ isSignal: true, alias: "severity", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], onDismiss: [{ type: i0.Output, args: ["onDismiss"] }] } });
2909
3021
 
2910
3022
  class TailwindSpinner extends TailwindComponent {
2911
3023
  /** Size variant */
@@ -3011,11 +3123,11 @@ class TailwindModal extends TailwindComponent {
3011
3123
  }, 200);
3012
3124
  }
3013
3125
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindModal, deps: [], target: i0.ɵɵFactoryTarget.Component });
3014
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindModal, isStandalone: true, selector: "tailwind-modal", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClose: "onClose" }, viewQueries: [{ propertyName: "modalPanel", first: true, predicate: ["modalPanel"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (isOpen()) {\r\n <!-- Backdrop -->\r\n <div\r\n class=\"fixed inset-0 bg-black/50 backdrop-blur-sm z-1040 transition-opacity duration-200\"\r\n [class.opacity-100]=\"isVisible()\"\r\n [class.opacity-0]=\"!isVisible()\"\r\n (click)=\"closeOnBackdrop() && close()\"\r\n aria-hidden=\"true\"></div>\r\n\r\n <!-- Modal -->\r\n <div\r\n class=\"fixed inset-0 z-1050 overflow-y-auto\"\r\n role=\"dialog\"\r\n [attr.aria-modal]=\"true\"\r\n (keydown.escape)=\"closeOnEscape() && close()\">\r\n <div class=\"flex min-h-full items-center justify-center p-4\">\r\n <div #modalPanel [class]=\"panelClasses()\" tabindex=\"-1\">\r\n\r\n <!-- Header -->\r\n <div class=\"flex items-center justify-between px-6 py-4 border-b border-surface-200\">\r\n <h2 class=\"text-lg font-semibold text-surface-900 pr-2\">\r\n <ng-content />\r\n </h2>\r\n @if (showCloseButton()) {\r\n <button\r\n type=\"button\"\r\n class=\"p-1.5 -m-1.5 shrink-0 rounded-lg text-surface-400 hover:text-surface-600 hover:bg-surface-100 transition-colors cursor-pointer\"\r\n aria-label=\"Close\"\r\n (click)=\"close()\">\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Body -->\r\n <ng-content select=\"[tailwind-modal-content]\" />\r\n\r\n <!-- Footer -->\r\n <ng-content select=\"[tailwind-modal-footer]\" />\r\n\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", styles: [":host{display:contents}\n"] });
3126
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindModal, isStandalone: true, selector: "tailwind-modal", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClose: "onClose" }, viewQueries: [{ propertyName: "modalPanel", first: true, predicate: ["modalPanel"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (isOpen()) {\r\n <!-- Backdrop -->\r\n <div\r\n class=\"fixed inset-0 bg-black/50 backdrop-blur-sm z-1040 transition-opacity duration-200\"\r\n [class.opacity-100]=\"isVisible()\"\r\n [class.opacity-0]=\"!isVisible()\"\r\n (click)=\"closeOnBackdrop() && close()\"\r\n aria-hidden=\"true\"></div>\r\n\r\n <!-- Modal -->\r\n <div\r\n role=\"dialog\"\r\n class=\"fixed inset-0 z-1050 overflow-y-auto\"\r\n [attr.aria-modal]=\"true\"\r\n (keydown.escape)=\"closeOnEscape() && close()\">\r\n <div class=\"flex min-h-full items-center justify-center p-4\">\r\n <div #modalPanel [class]=\"panelClasses()\" tabindex=\"-1\">\r\n <!-- Header -->\r\n <div class=\"flex items-center justify-between px-6 py-4 border-b border-surface-200\">\r\n <h2 class=\"text-lg font-semibold text-surface-900 pr-2\">\r\n <ng-content />\r\n </h2>\r\n @if (showCloseButton()) {\r\n <button\r\n type=\"button\"\r\n class=\"p-1.5 -m-1.5 shrink-0 rounded-lg text-surface-400 hover:text-surface-600 hover:bg-surface-100 transition-colors cursor-pointer\"\r\n aria-label=\"Close\"\r\n (click)=\"close()\">\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Body -->\r\n <div class=\"px-6 py-5\">\r\n <ng-content select=\"[tailwind-modal-content]\" />\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"border-t border-surface-200 px-6 py-4\">\r\n <ng-content select=\"[tailwind-modal-footer]\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", styles: [":host{display:contents}\n"] });
3015
3127
  }
3016
3128
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindModal, decorators: [{
3017
3129
  type: Component,
3018
- args: [{ selector: 'tailwind-modal', template: "@if (isOpen()) {\r\n <!-- Backdrop -->\r\n <div\r\n class=\"fixed inset-0 bg-black/50 backdrop-blur-sm z-1040 transition-opacity duration-200\"\r\n [class.opacity-100]=\"isVisible()\"\r\n [class.opacity-0]=\"!isVisible()\"\r\n (click)=\"closeOnBackdrop() && close()\"\r\n aria-hidden=\"true\"></div>\r\n\r\n <!-- Modal -->\r\n <div\r\n class=\"fixed inset-0 z-1050 overflow-y-auto\"\r\n role=\"dialog\"\r\n [attr.aria-modal]=\"true\"\r\n (keydown.escape)=\"closeOnEscape() && close()\">\r\n <div class=\"flex min-h-full items-center justify-center p-4\">\r\n <div #modalPanel [class]=\"panelClasses()\" tabindex=\"-1\">\r\n\r\n <!-- Header -->\r\n <div class=\"flex items-center justify-between px-6 py-4 border-b border-surface-200\">\r\n <h2 class=\"text-lg font-semibold text-surface-900 pr-2\">\r\n <ng-content />\r\n </h2>\r\n @if (showCloseButton()) {\r\n <button\r\n type=\"button\"\r\n class=\"p-1.5 -m-1.5 shrink-0 rounded-lg text-surface-400 hover:text-surface-600 hover:bg-surface-100 transition-colors cursor-pointer\"\r\n aria-label=\"Close\"\r\n (click)=\"close()\">\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Body -->\r\n <ng-content select=\"[tailwind-modal-content]\" />\r\n\r\n <!-- Footer -->\r\n <ng-content select=\"[tailwind-modal-footer]\" />\r\n\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", styles: [":host{display:contents}\n"] }]
3130
+ args: [{ selector: 'tailwind-modal', template: "@if (isOpen()) {\r\n <!-- Backdrop -->\r\n <div\r\n class=\"fixed inset-0 bg-black/50 backdrop-blur-sm z-1040 transition-opacity duration-200\"\r\n [class.opacity-100]=\"isVisible()\"\r\n [class.opacity-0]=\"!isVisible()\"\r\n (click)=\"closeOnBackdrop() && close()\"\r\n aria-hidden=\"true\"></div>\r\n\r\n <!-- Modal -->\r\n <div\r\n role=\"dialog\"\r\n class=\"fixed inset-0 z-1050 overflow-y-auto\"\r\n [attr.aria-modal]=\"true\"\r\n (keydown.escape)=\"closeOnEscape() && close()\">\r\n <div class=\"flex min-h-full items-center justify-center p-4\">\r\n <div #modalPanel [class]=\"panelClasses()\" tabindex=\"-1\">\r\n <!-- Header -->\r\n <div class=\"flex items-center justify-between px-6 py-4 border-b border-surface-200\">\r\n <h2 class=\"text-lg font-semibold text-surface-900 pr-2\">\r\n <ng-content />\r\n </h2>\r\n @if (showCloseButton()) {\r\n <button\r\n type=\"button\"\r\n class=\"p-1.5 -m-1.5 shrink-0 rounded-lg text-surface-400 hover:text-surface-600 hover:bg-surface-100 transition-colors cursor-pointer\"\r\n aria-label=\"Close\"\r\n (click)=\"close()\">\r\n <svg class=\"w-5 h-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\r\n <path\r\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Body -->\r\n <div class=\"px-6 py-5\">\r\n <ng-content select=\"[tailwind-modal-content]\" />\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"border-t border-surface-200 px-6 py-4\">\r\n <ng-content select=\"[tailwind-modal-footer]\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", styles: [":host{display:contents}\n"] }]
3019
3131
  }], ctorParameters: () => [], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], closeOnBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], onClose: [{ type: i0.Output, args: ["onClose"] }], modalPanel: [{ type: i0.ViewChild, args: ['modalPanel', { isSignal: true }] }] } });
3020
3132
 
3021
3133
  class TailwindTab extends TailwindComponent {
@@ -3362,14 +3474,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
3362
3474
 
3363
3475
  class TailwindBreadcrumb extends TailwindComponent {
3364
3476
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
3477
+ separator = input('>', ...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
3365
3478
  ariaLabel = input('Breadcrumb', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
3366
3479
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindBreadcrumb, deps: null, target: i0.ɵɵFactoryTarget.Component });
3367
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindBreadcrumb, isStandalone: true, selector: "tailwind-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel()\" class=\"flex\">\n <ol class=\"inline-flex items-center gap-1.5 text-sm\">\n @for (item of items(); track item.label; let last = $last; let first = $first) {\n <li class=\"inline-flex items-center\">\n @if (!first) {\n <span class=\"mx-1.5 text-surface-400\" aria-hidden=\"true\">\n <svg class=\"w-3.5 h-3.5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clip-rule=\"evenodd\" />\n </svg>\n </span>\n }\n @if (item.link && !last) {\n <a\n [routerLink]=\"item.link\"\n class=\"inline-flex items-center gap-1 text-surface-500 hover:text-primary-600 transition-colors font-medium\">\n @if (item.icon) {\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\n }\n {{ item.label }}\n </a>\n } @else {\n <span\n class=\"inline-flex items-center gap-1 font-medium\"\n [class.text-surface-900]=\"last\"\n [class.text-surface-500]=\"!last\"\n [attr.aria-current]=\"last ? 'page' : null\">\n @if (item.icon) {\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\n }\n {{ item.label }}\n </span>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: TailwindIcon, selector: "tailwind-icon", inputs: ["icon", "size"] }] });
3480
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindBreadcrumb, isStandalone: true, selector: "tailwind-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel()\" class=\"flex\">\r\n <ol class=\"inline-flex items-center text-sm\">\r\n @for (item of items(); track item.label; let last = $last; let first = $first) {\r\n <li class=\"inline-flex items-center\">\r\n @if (!first) {\r\n <span class=\"mx-2 text-surface-400\" aria-hidden=\"true\">\r\n {{ separator() }}\r\n </span>\r\n }\r\n @if (item.link && !last) {\r\n <a\r\n [routerLink]=\"item.link\"\r\n class=\"inline-flex items-center gap-1 text-surface-500 hover:text-primary-600 transition-colors font-medium\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\r\n }\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center gap-1 font-medium\"\r\n [class.text-surface-900]=\"last\"\r\n [class.text-surface-500]=\"!last\"\r\n [attr.aria-current]=\"last ? 'page' : null\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\r\n }\r\n {{ item.label }}\r\n </span>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n</nav>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: TailwindIcon, selector: "tailwind-icon", inputs: ["icon", "size"] }] });
3368
3481
  }
3369
3482
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindBreadcrumb, decorators: [{
3370
3483
  type: Component,
3371
- args: [{ imports: [RouterLink, TailwindIcon], selector: 'tailwind-breadcrumb', template: "<nav [attr.aria-label]=\"ariaLabel()\" class=\"flex\">\n <ol class=\"inline-flex items-center gap-1.5 text-sm\">\n @for (item of items(); track item.label; let last = $last; let first = $first) {\n <li class=\"inline-flex items-center\">\n @if (!first) {\n <span class=\"mx-1.5 text-surface-400\" aria-hidden=\"true\">\n <svg class=\"w-3.5 h-3.5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fill-rule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clip-rule=\"evenodd\" />\n </svg>\n </span>\n }\n @if (item.link && !last) {\n <a\n [routerLink]=\"item.link\"\n class=\"inline-flex items-center gap-1 text-surface-500 hover:text-primary-600 transition-colors font-medium\">\n @if (item.icon) {\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\n }\n {{ item.label }}\n </a>\n } @else {\n <span\n class=\"inline-flex items-center gap-1 font-medium\"\n [class.text-surface-900]=\"last\"\n [class.text-surface-500]=\"!last\"\n [attr.aria-current]=\"last ? 'page' : null\">\n @if (item.icon) {\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\n }\n {{ item.label }}\n </span>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: [":host{display:block}\n"] }]
3372
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
3484
+ args: [{ imports: [RouterLink, TailwindIcon], selector: 'tailwind-breadcrumb', template: "<nav [attr.aria-label]=\"ariaLabel()\" class=\"flex\">\r\n <ol class=\"inline-flex items-center text-sm\">\r\n @for (item of items(); track item.label; let last = $last; let first = $first) {\r\n <li class=\"inline-flex items-center\">\r\n @if (!first) {\r\n <span class=\"mx-2 text-surface-400\" aria-hidden=\"true\">\r\n {{ separator() }}\r\n </span>\r\n }\r\n @if (item.link && !last) {\r\n <a\r\n [routerLink]=\"item.link\"\r\n class=\"inline-flex items-center gap-1 text-surface-500 hover:text-primary-600 transition-colors font-medium\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\r\n }\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center gap-1 font-medium\"\r\n [class.text-surface-900]=\"last\"\r\n [class.text-surface-500]=\"!last\"\r\n [attr.aria-current]=\"last ? 'page' : null\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"16\" />\r\n }\r\n {{ item.label }}\r\n </span>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n</nav>\r\n", styles: [":host{display:block}\n"] }]
3485
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
3373
3486
 
3374
3487
  class TailwindPagination extends TailwindComponent {
3375
3488
  totalItems = input.required(...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
@@ -3430,19 +3543,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
3430
3543
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
3431
3544
 
3432
3545
  class TailwindTable extends TailwindComponent {
3433
- columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
3434
3546
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
3435
3547
  selectable = input(false, ...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
3436
3548
  striped = input(false, ...(ngDevMode ? [{ debugName: "striped" }] : /* istanbul ignore next */ []));
3437
3549
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
3438
3550
  emptyMessage = input('No data available', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
3439
- // --- Pagination Inputs ---
3551
+ /** Match your column count so the empty state spans the full table width. */
3552
+ emptyColspan = input(1, ...(ngDevMode ? [{ debugName: "emptyColspan" }] : /* istanbul ignore next */ []));
3440
3553
  paginated = input(true, ...(ngDevMode ? [{ debugName: "paginated" }] : /* istanbul ignore next */ []));
3441
3554
  pagination = input(...(ngDevMode ? [undefined, { debugName: "pagination" }] : /* istanbul ignore next */ []));
3442
- // --- Outputs ---
3443
3555
  onSortChange = output();
3444
3556
  onSelectionChange = output();
3445
- // --- Internal State ---
3557
+ rowTemplate = contentChild.required(TailwindTableRowDirective);
3558
+ rowContext(row, index) {
3559
+ return {
3560
+ $implicit: row,
3561
+ index,
3562
+ stripedRow: this.striped() && index % 2 === 1,
3563
+ selected: this.selectedRows().has(index),
3564
+ selectable: this.selectable(),
3565
+ toggleRow: () => {
3566
+ if (!this.selectable())
3567
+ return;
3568
+ this.toggleSelection(index);
3569
+ }
3570
+ };
3571
+ }
3446
3572
  sortKey = signal('', ...(ngDevMode ? [{ debugName: "sortKey" }] : /* istanbul ignore next */ []));
3447
3573
  sortDir = signal('asc', ...(ngDevMode ? [{ debugName: "sortDir" }] : /* istanbul ignore next */ []));
3448
3574
  selectedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedRows" }] : /* istanbul ignore next */ []));
@@ -3456,7 +3582,6 @@ class TailwindTable extends TailwindComponent {
3456
3582
  }
3457
3583
  });
3458
3584
  }
3459
- // --- Computed ---
3460
3585
  sortedData = computed(() => {
3461
3586
  let rows = [...this.data()];
3462
3587
  const key = this.sortKey();
@@ -3464,11 +3589,10 @@ class TailwindTable extends TailwindComponent {
3464
3589
  const dir = this.sortDir() === 'asc' ? 1 : -1;
3465
3590
  rows.sort((a, b) => {
3466
3591
  const va = a[key], vb = b[key];
3467
- if (va < vb)
3468
- return -dir;
3469
- if (va > vb)
3470
- return dir;
3471
- return 0;
3592
+ const sa = va == null ? '' : String(va);
3593
+ const sb = vb == null ? '' : String(vb);
3594
+ const cmp = sa.localeCompare(sb, undefined, { numeric: true, sensitivity: 'base' });
3595
+ return dir * cmp;
3472
3596
  });
3473
3597
  }
3474
3598
  return rows;
@@ -3481,7 +3605,6 @@ class TailwindTable extends TailwindComponent {
3481
3605
  const page = this.currentPage();
3482
3606
  return rows.slice((page - 1) * size, page * size);
3483
3607
  }, ...(ngDevMode ? [{ debugName: "displayedData" }] : /* istanbul ignore next */ []));
3484
- // --- Methods ---
3485
3608
  sort(key) {
3486
3609
  if (this.sortKey() === key) {
3487
3610
  this.sortDir.update(d => (d === 'asc' ? 'desc' : 'asc'));
@@ -3490,7 +3613,7 @@ class TailwindTable extends TailwindComponent {
3490
3613
  this.sortKey.set(key);
3491
3614
  this.sortDir.set('asc');
3492
3615
  }
3493
- this.currentPage.set(1); // Reset to first page on sort
3616
+ this.currentPage.set(1);
3494
3617
  this.onSortChange.emit({ key: this.sortKey(), direction: this.sortDir() });
3495
3618
  }
3496
3619
  toggleSelection(index) {
@@ -3504,13 +3627,47 @@ class TailwindTable extends TailwindComponent {
3504
3627
  });
3505
3628
  this.onSelectionChange.emit(this.selectedRows());
3506
3629
  }
3630
+ onSortZoneClick(ev) {
3631
+ this.delegateSortFromEvent(ev);
3632
+ }
3633
+ onSortZoneKeydown(ev) {
3634
+ if (ev.key !== 'Enter' && ev.key !== ' ')
3635
+ return;
3636
+ const target = ev.target;
3637
+ if (!target?.closest?.('[tailwindSortHeader]'))
3638
+ return;
3639
+ if (ev.key === ' ')
3640
+ ev.preventDefault();
3641
+ this.delegateSortFromEvent(ev);
3642
+ }
3643
+ delegateSortFromEvent(ev) {
3644
+ const host = ev.currentTarget;
3645
+ const target = ev.target;
3646
+ const header = target?.closest?.('[tailwindSortHeader]');
3647
+ if (!header || !host.contains(header))
3648
+ return;
3649
+ if (header.closest('tailwind-table') !== host)
3650
+ return;
3651
+ const key = header.getAttribute('data-sort-key');
3652
+ if (key)
3653
+ this.sort(key);
3654
+ }
3507
3655
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
3508
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindTable, isStandalone: true, selector: "tailwind-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, paginated: { classPropertyName: "paginated", publicName: "paginated", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSortChange: "onSortChange", onSelectionChange: "onSelectionChange" }, usesInheritance: true, ngImport: i0, template: "<div class=\"w-full overflow-x-auto rounded-xl border border-surface-200\">\n <!-- Loading overlay -->\n @if (loading()) {\n <div class=\"flex items-center justify-center py-16 text-surface-400\">\n <svg class=\"animate-spin w-6 h-6 mr-2\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v8z\" />\n </svg>\n Loading...\n </div>\n } @else {\n <table class=\"w-full text-sm text-left\">\n <thead class=\"bg-surface-50 border-b border-surface-200\">\n <tr>\n @for (col of columns(); track col.key) {\n <th\n scope=\"col\"\n class=\"px-4 py-3 font-semibold text-surface-700 whitespace-nowrap\"\n [class.text-center]=\"col.align === 'center'\"\n [class.text-right]=\"col.align === 'right'\"\n [style.width]=\"col.width || 'auto'\">\n @if (col.sortable) {\n <button\n type=\"button\"\n (click)=\"sort(col.key)\"\n class=\"inline-flex items-center gap-1 cursor-pointer hover:text-surface-900 transition-colors\">\n {{ col.label }}\n <svg\n class=\"w-3.5 h-3.5 text-surface-400\"\n [class.text-primary-600]=\"sortKey() === col.key\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\">\n @if (sortKey() === col.key && sortDir() === 'asc') {\n <path\n fill-rule=\"evenodd\"\n d=\"M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z\"\n clip-rule=\"evenodd\" />\n } @else {\n <path\n fill-rule=\"evenodd\"\n d=\"M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z\"\n clip-rule=\"evenodd\" />\n }\n </svg>\n </button>\n } @else {\n {{ col.label }}\n }\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"divide-y divide-surface-100\">\n @for (row of displayedData(); track $index) {\n <tr\n class=\"hover:bg-surface-50/50 transition-colors\"\n [class.bg-surface-50]=\"striped() && $index % 2 === 1\"\n [class.bg-primary-50/30]=\"selectedRows().has($index)\"\n [class.cursor-pointer]=\"selectable()\"\n (click)=\"selectable() && toggleSelection($index)\">\n @for (col of columns(); track col.key) {\n <td\n class=\"px-4 py-3 text-surface-700\"\n [class.text-center]=\"col.align === 'center'\"\n [class.text-right]=\"col.align === 'right'\">\n {{ row[col.key] }}\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"columns().length\" class=\"px-4 py-8 text-center text-surface-400\">\n {{ emptyMessage() }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n\n @if (paginated() && data().length > 0) {\n <div class=\"px-4 py-3 border-t border-surface-200 bg-white\">\n <tailwind-pagination\n [totalItems]=\"pagination()?.totalItems ?? data().length\"\n [pageSize]=\"pagination()?.pageSize ?? 10\"\n [currentPage]=\"currentPage()\"\n (onPageChange)=\"currentPage.set($event)\"\n [ariaLabel]=\"pagination()?.ariaLabel ?? 'Pagination'\"\n [summary]=\"pagination()?.summary ?? 'Showing {start}-{end} of {total}'\">\n </tailwind-pagination>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: TailwindPagination, selector: "tailwind-pagination", inputs: ["totalItems", "pageSize", "currentPage", "ariaLabel", "summary"], outputs: ["currentPageChange", "onPageChange"] }] });
3656
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindTable, isStandalone: true, selector: "tailwind-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, emptyColspan: { classPropertyName: "emptyColspan", publicName: "emptyColspan", isSignal: true, isRequired: false, transformFunction: null }, paginated: { classPropertyName: "paginated", publicName: "paginated", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSortChange: "onSortChange", onSelectionChange: "onSelectionChange" }, host: { listeners: { "click": "onSortZoneClick($event)", "keydown": "onSortZoneKeydown($event)" }, properties: { "attr.data-tw-sort-key": "sortKey()", "attr.data-tw-sort-dir": "sortDir()" } }, queries: [{ propertyName: "rowTemplate", first: true, predicate: TailwindTableRowDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"w-full overflow-x-auto rounded-lg border border-surface-200\">\n @if (loading()) {\n <div class=\"flex items-center justify-center py-16 text-surface-400\">\n <svg class=\"animate-spin w-6 h-6 mr-2\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v8z\" />\n </svg>\n Loading...\n </div>\n } @else {\n <table class=\"w-full text-sm text-left divide-y divide-surface-100\">\n <ng-content select=\"thead\" />\n @for (row of displayedData(); track row; let i = $index) {\n <ng-container\n *ngTemplateOutlet=\"rowTemplate().templateRef; context: rowContext(row, i)\" />\n } @empty {\n <tbody>\n <tr>\n <td [attr.colspan]=\"emptyColspan()\">\n {{ emptyMessage() }}\n </td>\n </tr>\n </tbody>\n }\n </table>\n\n @if (paginated() && data().length > 0) {\n <div class=\"px-4 py-3 border-t border-surface-200 bg-white\">\n <tailwind-pagination\n [totalItems]=\"pagination()?.totalItems ?? data().length\"\n [pageSize]=\"pagination()?.pageSize ?? 10\"\n [currentPage]=\"currentPage()\"\n (onPageChange)=\"currentPage.set($event)\"\n [ariaLabel]=\"pagination()?.ariaLabel ?? 'Pagination'\"\n [summary]=\"pagination()?.summary ?? 'Showing {start}-{end} of {total}'\">\n </tailwind-pagination>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block}:host ::ng-deep thead{background-color:var(--color-surface-50);border-bottom:1px solid var(--color-surface-200)}:host ::ng-deep thead th{padding:.75rem 1rem;font-weight:600;color:var(--color-surface-700);text-align:left;white-space:nowrap;vertical-align:middle}:host ::ng-deep tbody td{padding:.75rem 1rem;color:var(--color-surface-700)}:host ::ng-deep tbody td[colspan]{padding:2rem 1rem;text-align:center;color:var(--color-surface-400)}:host ::ng-deep tbody tr{transition-property:background-color,color,border-color;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}:host ::ng-deep tbody tr:hover{background-color:color-mix(in oklch,var(--color-surface-50) 50%,transparent)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TailwindPagination, selector: "tailwind-pagination", inputs: ["totalItems", "pageSize", "currentPage", "ariaLabel", "summary"], outputs: ["currentPageChange", "onPageChange"] }] });
3509
3657
  }
3510
3658
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindTable, decorators: [{
3511
3659
  type: Component,
3512
- args: [{ selector: 'tailwind-table', imports: [TailwindPagination], template: "<div class=\"w-full overflow-x-auto rounded-xl border border-surface-200\">\n <!-- Loading overlay -->\n @if (loading()) {\n <div class=\"flex items-center justify-center py-16 text-surface-400\">\n <svg class=\"animate-spin w-6 h-6 mr-2\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v8z\" />\n </svg>\n Loading...\n </div>\n } @else {\n <table class=\"w-full text-sm text-left\">\n <thead class=\"bg-surface-50 border-b border-surface-200\">\n <tr>\n @for (col of columns(); track col.key) {\n <th\n scope=\"col\"\n class=\"px-4 py-3 font-semibold text-surface-700 whitespace-nowrap\"\n [class.text-center]=\"col.align === 'center'\"\n [class.text-right]=\"col.align === 'right'\"\n [style.width]=\"col.width || 'auto'\">\n @if (col.sortable) {\n <button\n type=\"button\"\n (click)=\"sort(col.key)\"\n class=\"inline-flex items-center gap-1 cursor-pointer hover:text-surface-900 transition-colors\">\n {{ col.label }}\n <svg\n class=\"w-3.5 h-3.5 text-surface-400\"\n [class.text-primary-600]=\"sortKey() === col.key\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\">\n @if (sortKey() === col.key && sortDir() === 'asc') {\n <path\n fill-rule=\"evenodd\"\n d=\"M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z\"\n clip-rule=\"evenodd\" />\n } @else {\n <path\n fill-rule=\"evenodd\"\n d=\"M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z\"\n clip-rule=\"evenodd\" />\n }\n </svg>\n </button>\n } @else {\n {{ col.label }}\n }\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"divide-y divide-surface-100\">\n @for (row of displayedData(); track $index) {\n <tr\n class=\"hover:bg-surface-50/50 transition-colors\"\n [class.bg-surface-50]=\"striped() && $index % 2 === 1\"\n [class.bg-primary-50/30]=\"selectedRows().has($index)\"\n [class.cursor-pointer]=\"selectable()\"\n (click)=\"selectable() && toggleSelection($index)\">\n @for (col of columns(); track col.key) {\n <td\n class=\"px-4 py-3 text-surface-700\"\n [class.text-center]=\"col.align === 'center'\"\n [class.text-right]=\"col.align === 'right'\">\n {{ row[col.key] }}\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"columns().length\" class=\"px-4 py-8 text-center text-surface-400\">\n {{ emptyMessage() }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n\n @if (paginated() && data().length > 0) {\n <div class=\"px-4 py-3 border-t border-surface-200 bg-white\">\n <tailwind-pagination\n [totalItems]=\"pagination()?.totalItems ?? data().length\"\n [pageSize]=\"pagination()?.pageSize ?? 10\"\n [currentPage]=\"currentPage()\"\n (onPageChange)=\"currentPage.set($event)\"\n [ariaLabel]=\"pagination()?.ariaLabel ?? 'Pagination'\"\n [summary]=\"pagination()?.summary ?? 'Showing {start}-{end} of {total}'\">\n </tailwind-pagination>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block}\n"] }]
3513
- }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], paginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginated", required: false }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: false }] }], onSortChange: [{ type: i0.Output, args: ["onSortChange"] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }] } });
3660
+ args: [{ selector: 'tailwind-table', imports: [NgTemplateOutlet, TailwindPagination], host: {
3661
+ '[attr.data-tw-sort-key]': 'sortKey()',
3662
+ '[attr.data-tw-sort-dir]': 'sortDir()'
3663
+ }, template: "<div class=\"w-full overflow-x-auto rounded-lg border border-surface-200\">\n @if (loading()) {\n <div class=\"flex items-center justify-center py-16 text-surface-400\">\n <svg class=\"animate-spin w-6 h-6 mr-2\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v8z\" />\n </svg>\n Loading...\n </div>\n } @else {\n <table class=\"w-full text-sm text-left divide-y divide-surface-100\">\n <ng-content select=\"thead\" />\n @for (row of displayedData(); track row; let i = $index) {\n <ng-container\n *ngTemplateOutlet=\"rowTemplate().templateRef; context: rowContext(row, i)\" />\n } @empty {\n <tbody>\n <tr>\n <td [attr.colspan]=\"emptyColspan()\">\n {{ emptyMessage() }}\n </td>\n </tr>\n </tbody>\n }\n </table>\n\n @if (paginated() && data().length > 0) {\n <div class=\"px-4 py-3 border-t border-surface-200 bg-white\">\n <tailwind-pagination\n [totalItems]=\"pagination()?.totalItems ?? data().length\"\n [pageSize]=\"pagination()?.pageSize ?? 10\"\n [currentPage]=\"currentPage()\"\n (onPageChange)=\"currentPage.set($event)\"\n [ariaLabel]=\"pagination()?.ariaLabel ?? 'Pagination'\"\n [summary]=\"pagination()?.summary ?? 'Showing {start}-{end} of {total}'\">\n </tailwind-pagination>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block}:host ::ng-deep thead{background-color:var(--color-surface-50);border-bottom:1px solid var(--color-surface-200)}:host ::ng-deep thead th{padding:.75rem 1rem;font-weight:600;color:var(--color-surface-700);text-align:left;white-space:nowrap;vertical-align:middle}:host ::ng-deep tbody td{padding:.75rem 1rem;color:var(--color-surface-700)}:host ::ng-deep tbody td[colspan]{padding:2rem 1rem;text-align:center;color:var(--color-surface-400)}:host ::ng-deep tbody tr{transition-property:background-color,color,border-color;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}:host ::ng-deep tbody tr:hover{background-color:color-mix(in oklch,var(--color-surface-50) 50%,transparent)}\n"] }]
3664
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], emptyColspan: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyColspan", required: false }] }], paginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginated", required: false }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: false }] }], onSortChange: [{ type: i0.Output, args: ["onSortChange"] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }], rowTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TailwindTableRowDirective), { isSignal: true }] }], onSortZoneClick: [{
3665
+ type: HostListener,
3666
+ args: ['click', ['$event']]
3667
+ }], onSortZoneKeydown: [{
3668
+ type: HostListener,
3669
+ args: ['keydown', ['$event']]
3670
+ }] } });
3514
3671
 
3515
3672
  const I18N$2 = {
3516
3673
  it: {
@@ -4018,11 +4175,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
4018
4175
  class TailwindAccordion extends TailwindComponent {
4019
4176
  items = contentChildren(TailwindAccordionItem, ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
4020
4177
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAccordion, deps: null, target: i0.ɵɵFactoryTarget.Component });
4021
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.12", type: TailwindAccordion, isStandalone: true, selector: "tailwind-accordion", queries: [{ propertyName: "items", predicate: TailwindAccordionItem, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\r\n [id]=\"id()\"\r\n [ngClass]=\"class()\"\r\n class=\"border border-surface-200 rounded-xl overflow-hidden divide-y divide-surface-200\">\r\n <ng-content />\r\n</div>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
4178
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.12", type: TailwindAccordion, isStandalone: true, selector: "tailwind-accordion", queries: [{ propertyName: "items", predicate: TailwindAccordionItem, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\r\n [id]=\"id()\"\r\n [ngClass]=\"class()\"\r\n class=\"border border-surface-200 rounded-md overflow-hidden divide-y divide-surface-200\">\r\n <ng-content />\r\n</div>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
4022
4179
  }
4023
4180
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAccordion, decorators: [{
4024
4181
  type: Component,
4025
- args: [{ imports: [CommonModule], selector: 'tailwind-accordion', template: "<div\r\n [id]=\"id()\"\r\n [ngClass]=\"class()\"\r\n class=\"border border-surface-200 rounded-xl overflow-hidden divide-y divide-surface-200\">\r\n <ng-content />\r\n</div>\r\n", styles: [":host{display:block}\n"] }]
4182
+ args: [{ imports: [CommonModule], selector: 'tailwind-accordion', template: "<div\r\n [id]=\"id()\"\r\n [ngClass]=\"class()\"\r\n class=\"border border-surface-200 rounded-md overflow-hidden divide-y divide-surface-200\">\r\n <ng-content />\r\n</div>\r\n", styles: [":host{display:block}\n"] }]
4026
4183
  }], propDecorators: { items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TailwindAccordionItem), { isSignal: true }] }] } });
4027
4184
 
4028
4185
  class TailwindModalRef {
@@ -4251,16 +4408,16 @@ class TailwindToolbar extends TailwindComponent {
4251
4408
  onMenuSelect = output();
4252
4409
  menuContainerClasses = computed(() => this.orientation() === 'horizontal'
4253
4410
  ? 'min-w-0 flex-1 flex flex-row flex-wrap items-center gap-1'
4254
- : 'min-w-0 flex-1 flex flex-col gap-1 overflow-y-auto min-h-0', ...(ngDevMode ? [{ debugName: "menuContainerClasses" }] : /* istanbul ignore next */ []));
4411
+ : 'min-w-0 flex-1 flex flex-col gap-1.5 overflow-y-auto min-h-0', ...(ngDevMode ? [{ debugName: "menuContainerClasses" }] : /* istanbul ignore next */ []));
4255
4412
  menuItemButtonClasses = computed(() => this.orientation() === 'horizontal'
4256
- ? 'shrink-0 rounded-md px-3 py-1.5 text-sm font-medium text-surface-700 hover:bg-surface-100 hover:text-surface-900 disabled:opacity-50 disabled:cursor-not-allowed transition-colors cursor-pointer border-0 bg-transparent'
4257
- : 'w-full text-left rounded-md px-2 py-2 text-sm font-medium text-surface-700 hover:bg-surface-100 hover:text-surface-900 disabled:opacity-50 disabled:cursor-not-allowed transition-colors cursor-pointer border-0 bg-transparent', ...(ngDevMode ? [{ debugName: "menuItemButtonClasses" }] : /* istanbul ignore next */ []));
4413
+ ? 'inline-flex shrink-0 items-center justify-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium text-surface-700 hover:bg-surface-100 hover:text-surface-900 disabled:opacity-50 disabled:cursor-not-allowed transition-colors cursor-pointer border-0 bg-transparent'
4414
+ : 'inline-flex w-full items-center gap-2 rounded-md px-3 py-3 text-left text-sm font-medium text-surface-700 hover:bg-surface-100 hover:text-surface-900 disabled:opacity-50 disabled:cursor-not-allowed transition-colors cursor-pointer border-0 bg-transparent', ...(ngDevMode ? [{ debugName: "menuItemButtonClasses" }] : /* istanbul ignore next */ []));
4258
4415
  rootClasses = computed(() => {
4259
4416
  const horizontal = this.orientation() === 'horizontal';
4260
4417
  const sizeClasses = horizontal
4261
4418
  ? this.width() === 'full'
4262
- ? 'w-full'
4263
- : 'w-[95%] md:w-[85%] lg:w-[75%] mx-auto'
4419
+ ? 'w-full h-16'
4420
+ : 'container mx-auto h-16'
4264
4421
  : 'h-full w-full';
4265
4422
  const base = [
4266
4423
  'bg-white border border-surface-200',
@@ -4283,15 +4440,28 @@ class TailwindToolbar extends TailwindComponent {
4283
4440
  }
4284
4441
  this.onMenuSelect.emit(item);
4285
4442
  }
4443
+ /** True when `label` is a non-empty string after trim (icon-only entries omit or blank `label`). */
4444
+ menuItemHasVisibleLabel(item) {
4445
+ const label = item.label;
4446
+ return typeof label === 'string' && label.trim().length > 0;
4447
+ }
4448
+ /** Accessible name when there is no visible label (`value`, trimmed). */
4449
+ menuItemAriaLabel(item) {
4450
+ if (this.menuItemHasVisibleLabel(item)) {
4451
+ return null;
4452
+ }
4453
+ const v = item.value;
4454
+ return v != null && String(v).trim().length > 0 ? String(v).trim() : null;
4455
+ }
4286
4456
  menuTrackKey(index, item) {
4287
4457
  return item.value ?? item.label ?? String(index);
4288
4458
  }
4289
4459
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindToolbar, deps: null, target: i0.ɵɵFactoryTarget.Component });
4290
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindToolbar, isStandalone: true, selector: "tailwind-toolbar", inputs: { rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, elevated: { classPropertyName: "elevated", publicName: "elevated", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, menu: { classPropertyName: "menu", publicName: "menu", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onMenuSelect: "onMenuSelect" }, usesInheritance: true, ngImport: i0, template: "<div [class]=\"rootClasses()\">\r\n <div class=\"shrink-0\">\r\n <ng-content select=\"[tailwind-toolbar-logo]\" />\r\n </div>\r\n <nav [class]=\"menuContainerClasses()\" [attr.aria-label]=\"'Toolbar menu'\">\r\n @for (item of menu(); track menuTrackKey($index, item)) {\r\n @if (item.divider) {\r\n @if (orientation() === 'horizontal') {\r\n <span class=\"mx-0.5 h-5 w-px shrink-0 self-center bg-surface-200\" aria-hidden=\"true\"></span>\r\n } @else {\r\n <hr class=\"my-1 w-full border-0 border-t border-surface-100\" />\r\n }\r\n } @else {\r\n <button\r\n type=\"button\"\r\n [disabled]=\"!!item.disabled\"\r\n [class]=\"menuItemButtonClasses()\"\r\n (click)=\"selectMenuItem(item)\">\r\n {{ item.label }}\r\n </button>\r\n }\r\n }\r\n </nav>\r\n <div\r\n class=\"flex flex-wrap items-center gap-2 shrink-0\"\r\n [class.justify-end]=\"orientation() === 'horizontal'\"\r\n [class.mt-auto]=\"orientation() === 'vertical'\">\r\n <ng-content select=\"[tailwind-toolbar-end]\" />\r\n </div>\r\n</div>\r\n", styles: [":host{display:block}\n"] });
4460
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TailwindToolbar, isStandalone: true, selector: "tailwind-toolbar", inputs: { rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, elevated: { classPropertyName: "elevated", publicName: "elevated", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, menu: { classPropertyName: "menu", publicName: "menu", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onMenuSelect: "onMenuSelect" }, usesInheritance: true, ngImport: i0, template: "<div [class]=\"rootClasses()\">\r\n <div class=\"shrink-0\">\r\n <ng-content select=\"[tailwind-toolbar-logo]\" />\r\n </div>\r\n @if (orientation() === 'horizontal') {\r\n <nav class=\"min-w-0 flex flex-1 flex-row flex-wrap items-center gap-1\" [attr.aria-label]=\"'Toolbar menu'\">\r\n @if (menu().length) {\r\n <div class=\"flex shrink-0 items-center md:hidden\">\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-2 text-surface-700 transition-colors hover:bg-surface-100 hover:text-surface-900\"\r\n [attr.aria-expanded]=\"mobileToolbarMenu.isOpen()\"\r\n aria-haspopup=\"menu\"\r\n aria-label=\"Open navigation menu\"\r\n (click)=\"mobileToolbarMenu.toggle($event)\">\r\n <tailwind-icon icon=\"hamburger-menu\" [size]=\"22\" />\r\n </button>\r\n <tailwind-menu\r\n #mobileToolbarMenu\r\n [items]=\"menu()\"\r\n align=\"left\"\r\n (onSelect)=\"selectMenuItem($event)\" />\r\n </div>\r\n }\r\n <div class=\"hidden min-w-0 flex-1 flex-row flex-wrap items-center gap-1 md:flex\">\r\n @for (item of menu(); track menuTrackKey($index, item)) {\r\n @if (item.divider) {\r\n <span class=\"mx-0.5 h-5 w-px shrink-0 self-center bg-surface-200\" aria-hidden=\"true\"></span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n [disabled]=\"!!item.disabled\"\r\n [class]=\"menuItemButtonClasses()\"\r\n [class.px-2]=\"!!item.icon && !menuItemHasVisibleLabel(item)\"\r\n [class.py-2]=\"!!item.icon && !menuItemHasVisibleLabel(item)\"\r\n [attr.aria-label]=\"menuItemAriaLabel(item)\"\r\n (click)=\"selectMenuItem(item)\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"20\" />\r\n }\r\n @if (menuItemHasVisibleLabel(item)) {\r\n {{ item.label }}\r\n }\r\n </button>\r\n }\r\n }\r\n </div>\r\n </nav>\r\n } @else {\r\n <nav [class]=\"menuContainerClasses()\" [attr.aria-label]=\"'Toolbar menu'\">\r\n @for (item of menu(); track menuTrackKey($index, item)) {\r\n @if (item.divider) {\r\n <hr class=\"my-1 w-full border-0 border-t border-surface-100\" />\r\n } @else {\r\n <button\r\n type=\"button\"\r\n [disabled]=\"!!item.disabled\"\r\n [class]=\"menuItemButtonClasses()\"\r\n [class.justify-center]=\"!menuItemHasVisibleLabel(item)\"\r\n [attr.aria-label]=\"menuItemAriaLabel(item)\"\r\n (click)=\"selectMenuItem(item)\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"22\" />\r\n }\r\n @if (menuItemHasVisibleLabel(item)) {\r\n {{ item.label }}\r\n }\r\n </button>\r\n }\r\n }\r\n </nav>\r\n }\r\n <div\r\n class=\"flex flex-wrap items-center gap-2 shrink-0\"\r\n [class.justify-end]=\"orientation() === 'horizontal'\"\r\n [class.mt-auto]=\"orientation() === 'vertical'\">\r\n <ng-content select=\"[tailwind-toolbar-end]\" />\r\n </div>\r\n</div>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: TailwindIcon, selector: "tailwind-icon", inputs: ["icon", "size"] }, { kind: "component", type: TailwindMenu, selector: "tailwind-menu", inputs: ["items", "align"], outputs: ["onSelect"] }] });
4291
4461
  }
4292
4462
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindToolbar, decorators: [{
4293
4463
  type: Component,
4294
- args: [{ selector: 'tailwind-toolbar', template: "<div [class]=\"rootClasses()\">\r\n <div class=\"shrink-0\">\r\n <ng-content select=\"[tailwind-toolbar-logo]\" />\r\n </div>\r\n <nav [class]=\"menuContainerClasses()\" [attr.aria-label]=\"'Toolbar menu'\">\r\n @for (item of menu(); track menuTrackKey($index, item)) {\r\n @if (item.divider) {\r\n @if (orientation() === 'horizontal') {\r\n <span class=\"mx-0.5 h-5 w-px shrink-0 self-center bg-surface-200\" aria-hidden=\"true\"></span>\r\n } @else {\r\n <hr class=\"my-1 w-full border-0 border-t border-surface-100\" />\r\n }\r\n } @else {\r\n <button\r\n type=\"button\"\r\n [disabled]=\"!!item.disabled\"\r\n [class]=\"menuItemButtonClasses()\"\r\n (click)=\"selectMenuItem(item)\">\r\n {{ item.label }}\r\n </button>\r\n }\r\n }\r\n </nav>\r\n <div\r\n class=\"flex flex-wrap items-center gap-2 shrink-0\"\r\n [class.justify-end]=\"orientation() === 'horizontal'\"\r\n [class.mt-auto]=\"orientation() === 'vertical'\">\r\n <ng-content select=\"[tailwind-toolbar-end]\" />\r\n </div>\r\n</div>\r\n", styles: [":host{display:block}\n"] }]
4464
+ args: [{ imports: [TailwindIcon, TailwindMenu], selector: 'tailwind-toolbar', template: "<div [class]=\"rootClasses()\">\r\n <div class=\"shrink-0\">\r\n <ng-content select=\"[tailwind-toolbar-logo]\" />\r\n </div>\r\n @if (orientation() === 'horizontal') {\r\n <nav class=\"min-w-0 flex flex-1 flex-row flex-wrap items-center gap-1\" [attr.aria-label]=\"'Toolbar menu'\">\r\n @if (menu().length) {\r\n <div class=\"flex shrink-0 items-center md:hidden\">\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-2 text-surface-700 transition-colors hover:bg-surface-100 hover:text-surface-900\"\r\n [attr.aria-expanded]=\"mobileToolbarMenu.isOpen()\"\r\n aria-haspopup=\"menu\"\r\n aria-label=\"Open navigation menu\"\r\n (click)=\"mobileToolbarMenu.toggle($event)\">\r\n <tailwind-icon icon=\"hamburger-menu\" [size]=\"22\" />\r\n </button>\r\n <tailwind-menu\r\n #mobileToolbarMenu\r\n [items]=\"menu()\"\r\n align=\"left\"\r\n (onSelect)=\"selectMenuItem($event)\" />\r\n </div>\r\n }\r\n <div class=\"hidden min-w-0 flex-1 flex-row flex-wrap items-center gap-1 md:flex\">\r\n @for (item of menu(); track menuTrackKey($index, item)) {\r\n @if (item.divider) {\r\n <span class=\"mx-0.5 h-5 w-px shrink-0 self-center bg-surface-200\" aria-hidden=\"true\"></span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n [disabled]=\"!!item.disabled\"\r\n [class]=\"menuItemButtonClasses()\"\r\n [class.px-2]=\"!!item.icon && !menuItemHasVisibleLabel(item)\"\r\n [class.py-2]=\"!!item.icon && !menuItemHasVisibleLabel(item)\"\r\n [attr.aria-label]=\"menuItemAriaLabel(item)\"\r\n (click)=\"selectMenuItem(item)\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"20\" />\r\n }\r\n @if (menuItemHasVisibleLabel(item)) {\r\n {{ item.label }}\r\n }\r\n </button>\r\n }\r\n }\r\n </div>\r\n </nav>\r\n } @else {\r\n <nav [class]=\"menuContainerClasses()\" [attr.aria-label]=\"'Toolbar menu'\">\r\n @for (item of menu(); track menuTrackKey($index, item)) {\r\n @if (item.divider) {\r\n <hr class=\"my-1 w-full border-0 border-t border-surface-100\" />\r\n } @else {\r\n <button\r\n type=\"button\"\r\n [disabled]=\"!!item.disabled\"\r\n [class]=\"menuItemButtonClasses()\"\r\n [class.justify-center]=\"!menuItemHasVisibleLabel(item)\"\r\n [attr.aria-label]=\"menuItemAriaLabel(item)\"\r\n (click)=\"selectMenuItem(item)\">\r\n @if (item.icon) {\r\n <tailwind-icon [icon]=\"item.icon\" [size]=\"22\" />\r\n }\r\n @if (menuItemHasVisibleLabel(item)) {\r\n {{ item.label }}\r\n }\r\n </button>\r\n }\r\n }\r\n </nav>\r\n }\r\n <div\r\n class=\"flex flex-wrap items-center gap-2 shrink-0\"\r\n [class.justify-end]=\"orientation() === 'horizontal'\"\r\n [class.mt-auto]=\"orientation() === 'vertical'\">\r\n <ng-content select=\"[tailwind-toolbar-end]\" />\r\n </div>\r\n</div>\r\n", styles: [":host{display:block}\n"] }]
4295
4465
  }], propDecorators: { rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], elevated: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevated", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], menu: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu", required: false }] }], onMenuSelect: [{ type: i0.Output, args: ["onMenuSelect"] }] } });
4296
4466
 
4297
4467
  class TailwindDivider extends TailwindComponent {
@@ -4694,5 +4864,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
4694
4864
  * Generated bundle index. Do not edit.
4695
4865
  */
4696
4866
 
4697
- export { TAILWIND_COMPONENTS_SIZE, TAILWIND_DATETIME_LANGUAGE, TAILWIND_ICON_SIZE, TAILWIND_MODAL_DATA, TAILWIND_SOLAR_ICON_NAMES, TailwindAccordion, TailwindAccordionItem, TailwindAlert, TailwindBadge, TailwindBreadcrumb, TailwindButton, TailwindCard, TailwindCheckbox, TailwindDatePicker, TailwindDateTimePicker, TailwindDivider, TailwindDrawer, TailwindIcon, TailwindInput, TailwindInputOtp, TailwindMenu, TailwindMessage, TailwindMeter, TailwindModal, TailwindModalRef, TailwindModalService, TailwindNotification, TailwindPagination, TailwindProgressBar, TailwindRadioGroup, TailwindSelect, TailwindSkeleton, TailwindSlider, TailwindSpinner, TailwindStep, TailwindStepper, TailwindTab, TailwindTabGroup, TailwindTable, TailwindTag, TailwindTextarea, TailwindTimePicker, TailwindTitle, TailwindToast, TailwindToastService, TailwindToggle, TailwindToolbar, TailwindTooltip, TailwindTooltipDirective, TailwindUpload };
4867
+ export { TAILWIND_COMPONENTS_SIZE, TAILWIND_DATETIME_LANGUAGE, TAILWIND_ICON_SIZE, TAILWIND_MODAL_DATA, TAILWIND_SOLAR_ICON_NAMES, TW_TABLE_SORT_DIR_ATTR, TW_TABLE_SORT_KEY_ATTR, TailwindAccordion, TailwindAccordionItem, TailwindAlert, TailwindBadge, TailwindBreadcrumb, TailwindButton, TailwindCard, TailwindCheckbox, TailwindDatePicker, TailwindDateTimePicker, TailwindDivider, TailwindDrawer, TailwindIcon, TailwindInput, TailwindInputOtp, TailwindMenu, TailwindMessage, TailwindMeter, TailwindModal, TailwindModalRef, TailwindModalService, TailwindNotification, TailwindPagination, TailwindProgressBar, TailwindRadioGroup, TailwindSelect, TailwindSkeleton, TailwindSlider, TailwindSortHeaderDirective, TailwindSpinner, TailwindStep, TailwindStepper, TailwindTab, TailwindTabGroup, TailwindTable, TailwindTableRowDirective, TailwindTableRowDirective as TailwindTableRowTemplateDirective, TailwindTag, TailwindTextarea, TailwindTimePicker, TailwindTitle, TailwindToast, TailwindToastService, TailwindToggle, TailwindToolbar, TailwindTooltip, TailwindTooltipDirective, TailwindUpload };
4698
4868
  //# sourceMappingURL=angular-tailwind-components.mjs.map