angular-tailwind-components 1.2.1 → 1.3.0

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,11 +1,12 @@
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';
6
6
  import { Overlay } from '@angular/cdk/overlay';
7
7
  import { TemplatePortal } from '@angular/cdk/portal';
8
8
  import { Subscription, fromEvent } from 'rxjs';
9
+ import { RouterLink } from '@angular/router';
9
10
 
10
11
  /** Common types used across all components */
11
12
 
@@ -1464,6 +1465,120 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
1464
1465
  args: ['focusout']
1465
1466
  }] } });
1466
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
+
1467
1582
  class TailwindButton extends TailwindComponent {
1468
1583
  /** Visual color */
1469
1584
  color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
@@ -2873,8 +2988,6 @@ class TailwindAlert extends TailwindComponent {
2873
2988
  severity = input('info', ...(ngDevMode ? [{ debugName: "severity" }] : /* istanbul ignore next */ []));
2874
2989
  /** Alert title */
2875
2990
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
2876
- /** Alert message */
2877
- message = input('', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
2878
2991
  /** Whether the alert can be dismissed */
2879
2992
  dismissible = input(false, ...(ngDevMode ? [{ debugName: "dismissible" }] : /* istanbul ignore next */ []));
2880
2993
  /** Whether to show a border on the left */
@@ -2899,12 +3012,12 @@ class TailwindAlert extends TailwindComponent {
2899
3012
  this.onDismiss.emit();
2900
3013
  }
2901
3014
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAlert, deps: null, target: i0.ɵɵFactoryTarget.Component });
2902
- 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"] });
2903
3016
  }
2904
3017
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAlert, decorators: [{
2905
3018
  type: Component,
2906
- 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"] }]
2907
- }], 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"] }] } });
2908
3021
 
2909
3022
  class TailwindSpinner extends TailwindComponent {
2910
3023
  /** Size variant */
@@ -3010,11 +3123,11 @@ class TailwindModal extends TailwindComponent {
3010
3123
  }, 200);
3011
3124
  }
3012
3125
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindModal, deps: [], target: i0.ɵɵFactoryTarget.Component });
3013
- 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"] });
3014
3127
  }
3015
3128
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindModal, decorators: [{
3016
3129
  type: Component,
3017
- 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"] }]
3018
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 }] }] } });
3019
3132
 
3020
3133
  class TailwindTab extends TailwindComponent {
@@ -3361,14 +3474,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
3361
3474
 
3362
3475
  class TailwindBreadcrumb extends TailwindComponent {
3363
3476
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
3477
+ separator = input('>', ...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
3364
3478
  ariaLabel = input('Breadcrumb', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
3365
3479
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindBreadcrumb, deps: null, target: i0.ɵɵFactoryTarget.Component });
3366
- 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 ?? item.href) && !last) {\n <a\n [href]=\"item.link ?? item.href\"\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: "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"] }] });
3367
3481
  }
3368
3482
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindBreadcrumb, decorators: [{
3369
3483
  type: Component,
3370
- args: [{ imports: [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 ?? item.href) && !last) {\n <a\n [href]=\"item.link ?? item.href\"\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"] }]
3371
- }], 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 }] }] } });
3372
3486
 
3373
3487
  class TailwindPagination extends TailwindComponent {
3374
3488
  totalItems = input.required(...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
@@ -3429,19 +3543,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
3429
3543
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
3430
3544
 
3431
3545
  class TailwindTable extends TailwindComponent {
3432
- columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
3433
3546
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
3434
3547
  selectable = input(false, ...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
3435
3548
  striped = input(false, ...(ngDevMode ? [{ debugName: "striped" }] : /* istanbul ignore next */ []));
3436
3549
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
3437
3550
  emptyMessage = input('No data available', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
3438
- // --- 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 */ []));
3439
3553
  paginated = input(true, ...(ngDevMode ? [{ debugName: "paginated" }] : /* istanbul ignore next */ []));
3440
3554
  pagination = input(...(ngDevMode ? [undefined, { debugName: "pagination" }] : /* istanbul ignore next */ []));
3441
- // --- Outputs ---
3442
3555
  onSortChange = output();
3443
3556
  onSelectionChange = output();
3444
- // --- 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
+ }
3445
3572
  sortKey = signal('', ...(ngDevMode ? [{ debugName: "sortKey" }] : /* istanbul ignore next */ []));
3446
3573
  sortDir = signal('asc', ...(ngDevMode ? [{ debugName: "sortDir" }] : /* istanbul ignore next */ []));
3447
3574
  selectedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedRows" }] : /* istanbul ignore next */ []));
@@ -3455,7 +3582,6 @@ class TailwindTable extends TailwindComponent {
3455
3582
  }
3456
3583
  });
3457
3584
  }
3458
- // --- Computed ---
3459
3585
  sortedData = computed(() => {
3460
3586
  let rows = [...this.data()];
3461
3587
  const key = this.sortKey();
@@ -3463,11 +3589,10 @@ class TailwindTable extends TailwindComponent {
3463
3589
  const dir = this.sortDir() === 'asc' ? 1 : -1;
3464
3590
  rows.sort((a, b) => {
3465
3591
  const va = a[key], vb = b[key];
3466
- if (va < vb)
3467
- return -dir;
3468
- if (va > vb)
3469
- return dir;
3470
- 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;
3471
3596
  });
3472
3597
  }
3473
3598
  return rows;
@@ -3480,7 +3605,6 @@ class TailwindTable extends TailwindComponent {
3480
3605
  const page = this.currentPage();
3481
3606
  return rows.slice((page - 1) * size, page * size);
3482
3607
  }, ...(ngDevMode ? [{ debugName: "displayedData" }] : /* istanbul ignore next */ []));
3483
- // --- Methods ---
3484
3608
  sort(key) {
3485
3609
  if (this.sortKey() === key) {
3486
3610
  this.sortDir.update(d => (d === 'asc' ? 'desc' : 'asc'));
@@ -3489,7 +3613,7 @@ class TailwindTable extends TailwindComponent {
3489
3613
  this.sortKey.set(key);
3490
3614
  this.sortDir.set('asc');
3491
3615
  }
3492
- this.currentPage.set(1); // Reset to first page on sort
3616
+ this.currentPage.set(1);
3493
3617
  this.onSortChange.emit({ key: this.sortKey(), direction: this.sortDir() });
3494
3618
  }
3495
3619
  toggleSelection(index) {
@@ -3503,13 +3627,47 @@ class TailwindTable extends TailwindComponent {
3503
3627
  });
3504
3628
  this.onSelectionChange.emit(this.selectedRows());
3505
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
+ }
3506
3655
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
3507
- 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"] }] });
3508
3657
  }
3509
3658
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindTable, decorators: [{
3510
3659
  type: Component,
3511
- 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"] }]
3512
- }], 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
+ }] } });
3513
3671
 
3514
3672
  const I18N$2 = {
3515
3673
  it: {
@@ -4017,11 +4175,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
4017
4175
  class TailwindAccordion extends TailwindComponent {
4018
4176
  items = contentChildren(TailwindAccordionItem, ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
4019
4177
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAccordion, deps: null, target: i0.ɵɵFactoryTarget.Component });
4020
- 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"] }] });
4021
4179
  }
4022
4180
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindAccordion, decorators: [{
4023
4181
  type: Component,
4024
- 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"] }]
4025
4183
  }], propDecorators: { items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TailwindAccordionItem), { isSignal: true }] }] } });
4026
4184
 
4027
4185
  class TailwindModalRef {
@@ -4250,16 +4408,16 @@ class TailwindToolbar extends TailwindComponent {
4250
4408
  onMenuSelect = output();
4251
4409
  menuContainerClasses = computed(() => this.orientation() === 'horizontal'
4252
4410
  ? 'min-w-0 flex-1 flex flex-row flex-wrap items-center gap-1'
4253
- : '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 */ []));
4254
4412
  menuItemButtonClasses = computed(() => this.orientation() === 'horizontal'
4255
- ? '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'
4256
- : '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 */ []));
4257
4415
  rootClasses = computed(() => {
4258
4416
  const horizontal = this.orientation() === 'horizontal';
4259
4417
  const sizeClasses = horizontal
4260
4418
  ? this.width() === 'full'
4261
- ? 'w-full'
4262
- : 'w-[95%] md:w-[85%] lg:w-[75%] mx-auto'
4419
+ ? 'w-full h-16'
4420
+ : 'container mx-auto h-16'
4263
4421
  : 'h-full w-full';
4264
4422
  const base = [
4265
4423
  'bg-white border border-surface-200',
@@ -4282,15 +4440,28 @@ class TailwindToolbar extends TailwindComponent {
4282
4440
  }
4283
4441
  this.onMenuSelect.emit(item);
4284
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
+ }
4285
4456
  menuTrackKey(index, item) {
4286
4457
  return item.value ?? item.label ?? String(index);
4287
4458
  }
4288
4459
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindToolbar, deps: null, target: i0.ɵɵFactoryTarget.Component });
4289
- 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"] }] });
4290
4461
  }
4291
4462
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TailwindToolbar, decorators: [{
4292
4463
  type: Component,
4293
- 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"] }]
4294
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"] }] } });
4295
4466
 
4296
4467
  class TailwindDivider extends TailwindComponent {
@@ -4693,5 +4864,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
4693
4864
  * Generated bundle index. Do not edit.
4694
4865
  */
4695
4866
 
4696
- 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 };
4697
4868
  //# sourceMappingURL=angular-tailwind-components.mjs.map