pdm-ui-kit 0.1.50 → 0.2.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.
Files changed (46) hide show
  1. package/README.md +189 -2
  2. package/esm2020/lib/components/alert-dialog/alert-dialog.component.mjs +3 -3
  3. package/esm2020/lib/components/breadcrumb/breadcrumb.component.mjs +37 -4
  4. package/esm2020/lib/components/calendar/calendar.component.mjs +3 -3
  5. package/esm2020/lib/components/card/card.component.mjs +36 -53
  6. package/esm2020/lib/components/command/command.component.mjs +3 -3
  7. package/esm2020/lib/components/context-menu/context-menu.component.mjs +3 -3
  8. package/esm2020/lib/components/data-table/data-table.component.mjs +214 -16
  9. package/esm2020/lib/components/dialog/dialog.component.mjs +133 -17
  10. package/esm2020/lib/components/draggable-table/draggable-table.component.mjs +300 -0
  11. package/esm2020/lib/components/drawer/drawer.component.mjs +123 -16
  12. package/esm2020/lib/components/dropdown-menu/dropdown-menu.component.mjs +3 -2
  13. package/esm2020/lib/components/hover-card/hover-card.component.mjs +3 -3
  14. package/esm2020/lib/components/menubar/menubar.component.mjs +3 -3
  15. package/esm2020/lib/components/navigation-menu/navigation-menu.component.mjs +25 -3
  16. package/esm2020/lib/components/pagination/pagination.component.mjs +3 -3
  17. package/esm2020/lib/components/popover/popover.component.mjs +5 -3
  18. package/esm2020/lib/components/select/select.component.mjs +5 -3
  19. package/esm2020/lib/components/sheet/sheet.component.mjs +68 -12
  20. package/esm2020/lib/components/sidebar/sidebar.component.mjs +52 -5
  21. package/esm2020/lib/components/table/table.component.mjs +152 -188
  22. package/esm2020/lib/components/tabs/tabs.component.mjs +3 -3
  23. package/esm2020/lib/components/tooltip/tooltip.component.mjs +3 -3
  24. package/esm2020/lib/pdm-ui-kit.module.mjs +5 -1
  25. package/esm2020/lib/utils/responsive.mjs +143 -0
  26. package/esm2020/lib/utils/z-index.mjs +93 -0
  27. package/esm2020/public-api.mjs +4 -1
  28. package/fesm2015/pdm-ui-kit.mjs +1430 -371
  29. package/fesm2015/pdm-ui-kit.mjs.map +1 -1
  30. package/fesm2020/pdm-ui-kit.mjs +1428 -369
  31. package/fesm2020/pdm-ui-kit.mjs.map +1 -1
  32. package/lib/components/breadcrumb/breadcrumb.component.d.ts +23 -1
  33. package/lib/components/card/card.component.d.ts +32 -19
  34. package/lib/components/data-table/data-table.component.d.ts +172 -14
  35. package/lib/components/dialog/dialog.component.d.ts +35 -1
  36. package/lib/components/draggable-table/draggable-table.component.d.ts +74 -0
  37. package/lib/components/drawer/drawer.component.d.ts +65 -7
  38. package/lib/components/navigation-menu/navigation-menu.component.d.ts +22 -1
  39. package/lib/components/sheet/sheet.component.d.ts +30 -3
  40. package/lib/components/sidebar/sidebar.component.d.ts +39 -1
  41. package/lib/components/table/table.component.d.ts +46 -25
  42. package/lib/pdm-ui-kit.module.d.ts +42 -41
  43. package/lib/utils/responsive.d.ts +107 -0
  44. package/lib/utils/z-index.d.ts +73 -0
  45. package/package.json +5 -3
  46. package/public-api.d.ts +3 -0
@@ -132,10 +132,10 @@ class PdmAlertDialogComponent {
132
132
  }
133
133
  }
134
134
  PdmAlertDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmAlertDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
135
- PdmAlertDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmAlertDialogComponent, selector: "pdm-alert-dialog", inputs: { open: "open", showTrigger: "showTrigger", triggerText: "triggerText", title: "title", description: "description", confirmText: "confirmText", cancelText: "cancelText", className: "className", closeOnEsc: "closeOnEsc" }, outputs: { openChange: "openChange", confirm: "confirm", cancel: "cancel" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<button\n *ngIf=\"showTrigger && !open\"\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onTriggerClick()\"\n>\n {{ triggerText }}\n</button>\n\n<div *ngIf=\"open\" class=\"fixed inset-0 z-50 flex items-center justify-center p-5\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onCancel()\"></div>\n <section\n role=\"alertdialog\"\n aria-modal=\"true\"\n [ngClass]=\"[\n 'relative z-10 w-full max-w-lg rounded-lg border border-border bg-background p-6 text-foreground shadow-lg',\n className\n ]\"\n >\n <div class=\"flex flex-col gap-2\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <div class=\"mt-4 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onCancel()\"\n >\n {{ cancelText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onConfirm()\"\n >\n {{ confirmText }}\n </button>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
135
+ PdmAlertDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmAlertDialogComponent, selector: "pdm-alert-dialog", inputs: { open: "open", showTrigger: "showTrigger", triggerText: "triggerText", title: "title", description: "description", confirmText: "confirmText", cancelText: "cancelText", className: "className", closeOnEsc: "closeOnEsc" }, outputs: { openChange: "openChange", confirm: "confirm", cancel: "cancel" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<button\n *ngIf=\"showTrigger && !open\"\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onTriggerClick()\"\n>\n {{ triggerText }}\n</button>\n\n<div *ngIf=\"open\" class=\"fixed inset-0 z-50 flex items-center justify-center p-5\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onCancel()\"></div>\n <section\n role=\"alertdialog\"\n aria-modal=\"true\"\n [ngClass]=\"[\n 'relative z-[60] w-full max-w-lg rounded-lg border border-border bg-background p-6 text-foreground shadow-lg',\n className\n ]\"\n >\n <div class=\"flex flex-col gap-2\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <div class=\"mt-4 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onCancel()\"\n >\n {{ cancelText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onConfirm()\"\n >\n {{ confirmText }}\n </button>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
136
136
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmAlertDialogComponent, decorators: [{
137
137
  type: Component,
138
- args: [{ selector: 'pdm-alert-dialog', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n *ngIf=\"showTrigger && !open\"\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onTriggerClick()\"\n>\n {{ triggerText }}\n</button>\n\n<div *ngIf=\"open\" class=\"fixed inset-0 z-50 flex items-center justify-center p-5\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onCancel()\"></div>\n <section\n role=\"alertdialog\"\n aria-modal=\"true\"\n [ngClass]=\"[\n 'relative z-10 w-full max-w-lg rounded-lg border border-border bg-background p-6 text-foreground shadow-lg',\n className\n ]\"\n >\n <div class=\"flex flex-col gap-2\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <div class=\"mt-4 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onCancel()\"\n >\n {{ cancelText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onConfirm()\"\n >\n {{ confirmText }}\n </button>\n </div>\n </section>\n</div>\n" }]
138
+ args: [{ selector: 'pdm-alert-dialog', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n *ngIf=\"showTrigger && !open\"\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onTriggerClick()\"\n>\n {{ triggerText }}\n</button>\n\n<div *ngIf=\"open\" class=\"fixed inset-0 z-50 flex items-center justify-center p-5\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onCancel()\"></div>\n <section\n role=\"alertdialog\"\n aria-modal=\"true\"\n [ngClass]=\"[\n 'relative z-[60] w-full max-w-lg rounded-lg border border-border bg-background p-6 text-foreground shadow-lg',\n className\n ]\"\n >\n <div class=\"flex flex-col gap-2\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <div class=\"mt-4 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onCancel()\"\n >\n {{ cancelText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onConfirm()\"\n >\n {{ confirmText }}\n </button>\n </div>\n </section>\n</div>\n" }]
139
139
  }], propDecorators: { open: [{
140
140
  type: Input
141
141
  }], showTrigger: [{
@@ -256,30 +256,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
256
256
  type: Input
257
257
  }] } });
258
258
 
259
+ /**
260
+ * Breadcrumb component con soporte responsive
261
+ *
262
+ * MEJORADO en v0.2.0:
263
+ * - Modo responsive real con overflow-x-auto
264
+ * - Collapse inteligente en mobile
265
+ *
266
+ * @example
267
+ * <pdm-breadcrumb
268
+ * mode="responsive"
269
+ * [items]="['Home', 'Products', 'Electronics', 'Laptops']">
270
+ * </pdm-breadcrumb>
271
+ */
259
272
  class PdmBreadcrumbComponent {
260
273
  constructor() {
261
274
  this.mode = 'link-component';
262
275
  this.items = ['Home', 'Components', 'Breadcrumb'];
263
276
  this.className = '';
277
+ /**
278
+ * Cantidad mínima de items para mostrar en mobile cuando mode="responsive"
279
+ * Default: 2 (primer y último item)
280
+ */
281
+ this.minItemsMobile = 2;
264
282
  }
265
283
  get renderedItems() {
266
- if ((this.mode === 'collapsed' || this.mode === 'responsive') && this.items.length > 3) {
284
+ if (this.mode === 'collapsed' && this.items.length > 3) {
267
285
  return [this.items[0], '...', this.items[this.items.length - 2], this.items[this.items.length - 1]];
268
286
  }
287
+ // Responsive mode: no collapse en el TS, se maneja en el template con CSS
269
288
  return this.items;
270
289
  }
290
+ /**
291
+ * Determina si un item debe estar visible en mobile (modo responsive)
292
+ */
293
+ shouldShowInMobile(index) {
294
+ if (this.mode !== 'responsive')
295
+ return true;
296
+ const totalItems = this.items.length;
297
+ if (totalItems <= this.minItemsMobile)
298
+ return true;
299
+ // Siempre mostrar primero y último
300
+ return index === 0 || index === totalItems - 1;
301
+ }
271
302
  }
272
303
  PdmBreadcrumbComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
273
- PdmBreadcrumbComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmBreadcrumbComponent, selector: "pdm-breadcrumb", inputs: { mode: "mode", items: "items", className: "className" }, ngImport: i0, template: "<nav\n aria-label=\"breadcrumb\"\n [ngClass]=\"['inline-flex items-center gap-1.5 text-sm', className]\"\n>\n <ng-container *ngFor=\"let item of renderedItems; let i = index; let last = last\">\n <span [ngClass]=\"[last ? 'text-foreground' : 'text-muted-foreground']\">{{ item }}</span>\n\n <ng-container *ngIf=\"!last\">\n <span class=\"inline-flex h-6 w-6 items-center justify-center text-muted-foreground\" aria-hidden=\"true\">\n <svg\n *ngIf=\"mode === 'custom-separator' && item !== '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M8 20L16 4\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n <svg\n *ngIf=\"(mode !== 'custom-separator' && item !== '...') || item === '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n </ng-container>\n\n <ng-container *ngIf=\"mode === 'dropdown' && i === 1 && item !== '...' && !last\">\n <span class=\"-ml-2 inline-flex h-6 w-6 items-center justify-center text-muted-foreground\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n </ng-container>\n </ng-container>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
304
+ PdmBreadcrumbComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmBreadcrumbComponent, selector: "pdm-breadcrumb", inputs: { mode: "mode", items: "items", className: "className", minItemsMobile: "minItemsMobile" }, ngImport: i0, template: "<nav\n aria-label=\"breadcrumb\"\n [ngClass]=\"[\n 'inline-flex items-center gap-1.5 text-sm',\n mode === 'responsive' ? 'overflow-x-auto max-w-full pb-1 scrollbar-thin' : '',\n className\n ]\"\n>\n <ng-container *ngFor=\"let item of renderedItems; let i = index; let last = last\">\n <!-- Item text -->\n <span \n [ngClass]=\"[\n last ? 'text-foreground font-medium' : 'text-muted-foreground hover:text-foreground transition-colors cursor-pointer',\n mode === 'responsive' && !shouldShowInMobile(i) ? 'hidden sm:inline' : '',\n 'whitespace-nowrap'\n ]\">\n {{ item }}\n </span>\n\n <!-- Separator -->\n <ng-container *ngIf=\"!last\">\n <span \n [ngClass]=\"[\n 'inline-flex h-6 w-6 flex-shrink-0 items-center justify-center text-muted-foreground',\n mode === 'responsive' && !shouldShowInMobile(i) && !shouldShowInMobile(i + 1) ? 'hidden sm:inline-flex' : ''\n ]\" \n aria-hidden=\"true\">\n <!-- Custom separator (slash) -->\n <svg\n *ngIf=\"mode === 'custom-separator' && item !== '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M8 20L16 4\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n \n <!-- Default separator (chevron) -->\n <svg\n *ngIf=\"(mode !== 'custom-separator' && item !== '...') || item === '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n \n <!-- Ellipsis indicator for responsive mode (only shown when items are hidden) -->\n <span \n *ngIf=\"mode === 'responsive' && !shouldShowInMobile(i) && i === 0\"\n class=\"inline-flex sm:hidden text-muted-foreground\">\n ...\n </span>\n </ng-container>\n\n <!-- Dropdown indicator -->\n <ng-container *ngIf=\"mode === 'dropdown' && i === 1 && item !== '...' && !last\">\n <span class=\"-ml-2 inline-flex h-6 w-6 items-center justify-center text-muted-foreground\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n </ng-container>\n </ng-container>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
274
305
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmBreadcrumbComponent, decorators: [{
275
306
  type: Component,
276
- args: [{ selector: 'pdm-breadcrumb', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav\n aria-label=\"breadcrumb\"\n [ngClass]=\"['inline-flex items-center gap-1.5 text-sm', className]\"\n>\n <ng-container *ngFor=\"let item of renderedItems; let i = index; let last = last\">\n <span [ngClass]=\"[last ? 'text-foreground' : 'text-muted-foreground']\">{{ item }}</span>\n\n <ng-container *ngIf=\"!last\">\n <span class=\"inline-flex h-6 w-6 items-center justify-center text-muted-foreground\" aria-hidden=\"true\">\n <svg\n *ngIf=\"mode === 'custom-separator' && item !== '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M8 20L16 4\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n <svg\n *ngIf=\"(mode !== 'custom-separator' && item !== '...') || item === '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n </ng-container>\n\n <ng-container *ngIf=\"mode === 'dropdown' && i === 1 && item !== '...' && !last\">\n <span class=\"-ml-2 inline-flex h-6 w-6 items-center justify-center text-muted-foreground\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n </ng-container>\n </ng-container>\n</nav>\n" }]
307
+ args: [{ selector: 'pdm-breadcrumb', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav\n aria-label=\"breadcrumb\"\n [ngClass]=\"[\n 'inline-flex items-center gap-1.5 text-sm',\n mode === 'responsive' ? 'overflow-x-auto max-w-full pb-1 scrollbar-thin' : '',\n className\n ]\"\n>\n <ng-container *ngFor=\"let item of renderedItems; let i = index; let last = last\">\n <!-- Item text -->\n <span \n [ngClass]=\"[\n last ? 'text-foreground font-medium' : 'text-muted-foreground hover:text-foreground transition-colors cursor-pointer',\n mode === 'responsive' && !shouldShowInMobile(i) ? 'hidden sm:inline' : '',\n 'whitespace-nowrap'\n ]\">\n {{ item }}\n </span>\n\n <!-- Separator -->\n <ng-container *ngIf=\"!last\">\n <span \n [ngClass]=\"[\n 'inline-flex h-6 w-6 flex-shrink-0 items-center justify-center text-muted-foreground',\n mode === 'responsive' && !shouldShowInMobile(i) && !shouldShowInMobile(i + 1) ? 'hidden sm:inline-flex' : ''\n ]\" \n aria-hidden=\"true\">\n <!-- Custom separator (slash) -->\n <svg\n *ngIf=\"mode === 'custom-separator' && item !== '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M8 20L16 4\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n \n <!-- Default separator (chevron) -->\n <svg\n *ngIf=\"(mode !== 'custom-separator' && item !== '...') || item === '...'\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n \n <!-- Ellipsis indicator for responsive mode (only shown when items are hidden) -->\n <span \n *ngIf=\"mode === 'responsive' && !shouldShowInMobile(i) && i === 0\"\n class=\"inline-flex sm:hidden text-muted-foreground\">\n ...\n </span>\n </ng-container>\n\n <!-- Dropdown indicator -->\n <ng-container *ngIf=\"mode === 'dropdown' && i === 1 && item !== '...' && !last\">\n <span class=\"-ml-2 inline-flex h-6 w-6 items-center justify-center text-muted-foreground\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n </ng-container>\n </ng-container>\n</nav>\n" }]
277
308
  }], propDecorators: { mode: [{
278
309
  type: Input
279
310
  }], items: [{
280
311
  type: Input
281
312
  }], className: [{
282
313
  type: Input
314
+ }], minItemsMobile: [{
315
+ type: Input
283
316
  }] } });
284
317
 
285
318
  class PdmButtonGroupComponent {
@@ -1064,10 +1097,10 @@ class PdmCalendarComponent {
1064
1097
  }
1065
1098
  }
1066
1099
  PdmCalendarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmCalendarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1067
- PdmCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmCalendarComponent, selector: "pdm-calendar", inputs: { variant: "variant", className: "className", disabledDates: "disabledDates", minDate: "minDate", maxDate: "maxDate", minYear: "minYear", maxYear: "maxYear", isDateDisabled: "isDateDisabled", allowSameDayRange: "allowSameDayRange", readonly: "readonly", value: "value", rangeValue: "rangeValue", month: "month" }, outputs: { valueChange: "valueChange", rangeValueChange: "rangeValueChange", monthChange: "monthChange", dateClick: "dateClick", disabledDateClick: "disabledDateClick" }, ngImport: i0, template: "<div [ngClass]=\"rootClasses\" [ngStyle]=\"rootStyle\">\n <div *ngFor=\"let month of visibleMonths; let monthIndex = index; trackBy: trackByIndex\" [ngClass]=\"monthPanelClasses(monthIndex)\">\n <div [ngClass]=\"headerClasses(month)\">\n <button\n *ngIf=\"month.showPrevButton; else prevPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Previous month\"\n (click)=\"goToPreviousMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m15 18-6-6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #prevPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n\n <ng-container *ngIf=\"month.titleStyle === 'dropdowns'; else plainTitle\">\n <div [ngClass]=\"dropdownWrapClasses()\">\n <div [ngClass]=\"dropdownClasses('w-[72px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderMonth\"\n aria-label=\"Month\"\n (change)=\"onSingleMonthChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let monthOption of monthOptions\"\n [value]=\"monthOption.value\"\n [selected]=\"monthOption.value === singleHeaderMonth\"\n >\n {{ monthOption.label }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n <div [ngClass]=\"dropdownClasses('w-[82px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderYear\"\n aria-label=\"Year\"\n (change)=\"onSingleYearChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let year of yearOptions\"\n [value]=\"year\"\n [selected]=\"year === singleHeaderYear\"\n >\n {{ year }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n </div>\n </ng-container>\n\n <ng-template #plainTitle>\n <div class=\"flex min-w-0 flex-1 items-center justify-center\">\n <p class=\"m-0 text-foreground text-center text-sm font-medium leading-5\">\n {{ month.title }}\n </p>\n </div>\n </ng-template>\n\n <button\n *ngIf=\"month.showNextButton; else nextPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Next month\"\n (click)=\"goToNextMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #nextPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n </div>\n\n <div [ngClass]=\"calendarGridWrapClasses()\">\n <div [ngClass]=\"weekdayRowClasses()\">\n <div *ngFor=\"let day of weekdays; trackBy: trackByIndex\" [ngClass]=\"weekdayCellClasses()\">\n <span>{{ day }}</span>\n </div>\n </div>\n\n <div *ngFor=\"let week of month.weeks; trackBy: trackByIndex\" [ngClass]=\"weekRowClasses()\">\n <div *ngFor=\"let cell of week; trackBy: trackByDate\" [ngClass]=\"dayCellClasses(cell)\">\n <button\n type=\"button\"\n [ngClass]=\"dayButtonClasses(cell)\"\n [disabled]=\"readonly\"\n [attr.aria-selected]=\"cell.selected\"\n [attr.aria-disabled]=\"cell.disabled || readonly\"\n [attr.title]=\"cell.date | date : 'yyyy-MM-dd'\"\n (click)=\"onDatePressed(cell)\"\n >\n <span [ngClass]=\"dayLabelClasses(cell)\">{{ cell.label }}</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1100
+ PdmCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmCalendarComponent, selector: "pdm-calendar", inputs: { variant: "variant", className: "className", disabledDates: "disabledDates", minDate: "minDate", maxDate: "maxDate", minYear: "minYear", maxYear: "maxYear", isDateDisabled: "isDateDisabled", allowSameDayRange: "allowSameDayRange", readonly: "readonly", value: "value", rangeValue: "rangeValue", month: "month" }, outputs: { valueChange: "valueChange", rangeValueChange: "rangeValueChange", monthChange: "monthChange", dateClick: "dateClick", disabledDateClick: "disabledDateClick" }, ngImport: i0, template: "<div [ngClass]=\"rootClasses\" [ngStyle]=\"rootStyle\">\n <div *ngFor=\"let month of visibleMonths; let monthIndex = index; trackBy: trackByIndex\" [ngClass]=\"monthPanelClasses(monthIndex)\">\n <div [ngClass]=\"headerClasses(month)\">\n <button\n *ngIf=\"month.showPrevButton; else prevPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Previous month\"\n (click)=\"goToPreviousMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m15 18-6-6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #prevPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n\n <ng-container *ngIf=\"month.titleStyle === 'dropdowns'; else plainTitle\">\n <div [ngClass]=\"dropdownWrapClasses()\">\n <div [ngClass]=\"dropdownClasses('w-16 sm:w-[72px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderMonth\"\n aria-label=\"Month\"\n (change)=\"onSingleMonthChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let monthOption of monthOptions\"\n [value]=\"monthOption.value\"\n [selected]=\"monthOption.value === singleHeaderMonth\"\n >\n {{ monthOption.label }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n <div [ngClass]=\"dropdownClasses('w-16 sm:w-[82px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderYear\"\n aria-label=\"Year\"\n (change)=\"onSingleYearChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let year of yearOptions\"\n [value]=\"year\"\n [selected]=\"year === singleHeaderYear\"\n >\n {{ year }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n </div>\n </ng-container>\n\n <ng-template #plainTitle>\n <div class=\"flex min-w-0 flex-1 items-center justify-center\">\n <p class=\"m-0 text-foreground text-center text-sm font-medium leading-5\">\n {{ month.title }}\n </p>\n </div>\n </ng-template>\n\n <button\n *ngIf=\"month.showNextButton; else nextPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Next month\"\n (click)=\"goToNextMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #nextPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n </div>\n\n <div [ngClass]=\"calendarGridWrapClasses()\">\n <div [ngClass]=\"weekdayRowClasses()\">\n <div *ngFor=\"let day of weekdays; trackBy: trackByIndex\" [ngClass]=\"weekdayCellClasses()\">\n <span>{{ day }}</span>\n </div>\n </div>\n\n <div *ngFor=\"let week of month.weeks; trackBy: trackByIndex\" [ngClass]=\"weekRowClasses()\">\n <div *ngFor=\"let cell of week; trackBy: trackByDate\" [ngClass]=\"dayCellClasses(cell)\">\n <button\n type=\"button\"\n [ngClass]=\"dayButtonClasses(cell)\"\n [disabled]=\"readonly\"\n [attr.aria-selected]=\"cell.selected\"\n [attr.aria-disabled]=\"cell.disabled || readonly\"\n [attr.title]=\"cell.date | date : 'yyyy-MM-dd'\"\n (click)=\"onDatePressed(cell)\"\n >\n <span [ngClass]=\"dayLabelClasses(cell)\">{{ cell.label }}</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1068
1101
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmCalendarComponent, decorators: [{
1069
1102
  type: Component,
1070
- args: [{ selector: 'pdm-calendar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"rootClasses\" [ngStyle]=\"rootStyle\">\n <div *ngFor=\"let month of visibleMonths; let monthIndex = index; trackBy: trackByIndex\" [ngClass]=\"monthPanelClasses(monthIndex)\">\n <div [ngClass]=\"headerClasses(month)\">\n <button\n *ngIf=\"month.showPrevButton; else prevPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Previous month\"\n (click)=\"goToPreviousMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m15 18-6-6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #prevPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n\n <ng-container *ngIf=\"month.titleStyle === 'dropdowns'; else plainTitle\">\n <div [ngClass]=\"dropdownWrapClasses()\">\n <div [ngClass]=\"dropdownClasses('w-[72px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderMonth\"\n aria-label=\"Month\"\n (change)=\"onSingleMonthChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let monthOption of monthOptions\"\n [value]=\"monthOption.value\"\n [selected]=\"monthOption.value === singleHeaderMonth\"\n >\n {{ monthOption.label }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n <div [ngClass]=\"dropdownClasses('w-[82px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderYear\"\n aria-label=\"Year\"\n (change)=\"onSingleYearChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let year of yearOptions\"\n [value]=\"year\"\n [selected]=\"year === singleHeaderYear\"\n >\n {{ year }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n </div>\n </ng-container>\n\n <ng-template #plainTitle>\n <div class=\"flex min-w-0 flex-1 items-center justify-center\">\n <p class=\"m-0 text-foreground text-center text-sm font-medium leading-5\">\n {{ month.title }}\n </p>\n </div>\n </ng-template>\n\n <button\n *ngIf=\"month.showNextButton; else nextPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Next month\"\n (click)=\"goToNextMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #nextPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n </div>\n\n <div [ngClass]=\"calendarGridWrapClasses()\">\n <div [ngClass]=\"weekdayRowClasses()\">\n <div *ngFor=\"let day of weekdays; trackBy: trackByIndex\" [ngClass]=\"weekdayCellClasses()\">\n <span>{{ day }}</span>\n </div>\n </div>\n\n <div *ngFor=\"let week of month.weeks; trackBy: trackByIndex\" [ngClass]=\"weekRowClasses()\">\n <div *ngFor=\"let cell of week; trackBy: trackByDate\" [ngClass]=\"dayCellClasses(cell)\">\n <button\n type=\"button\"\n [ngClass]=\"dayButtonClasses(cell)\"\n [disabled]=\"readonly\"\n [attr.aria-selected]=\"cell.selected\"\n [attr.aria-disabled]=\"cell.disabled || readonly\"\n [attr.title]=\"cell.date | date : 'yyyy-MM-dd'\"\n (click)=\"onDatePressed(cell)\"\n >\n <span [ngClass]=\"dayLabelClasses(cell)\">{{ cell.label }}</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n</div>\n" }]
1103
+ args: [{ selector: 'pdm-calendar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"rootClasses\" [ngStyle]=\"rootStyle\">\n <div *ngFor=\"let month of visibleMonths; let monthIndex = index; trackBy: trackByIndex\" [ngClass]=\"monthPanelClasses(monthIndex)\">\n <div [ngClass]=\"headerClasses(month)\">\n <button\n *ngIf=\"month.showPrevButton; else prevPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Previous month\"\n (click)=\"goToPreviousMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m15 18-6-6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #prevPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n\n <ng-container *ngIf=\"month.titleStyle === 'dropdowns'; else plainTitle\">\n <div [ngClass]=\"dropdownWrapClasses()\">\n <div [ngClass]=\"dropdownClasses('w-16 sm:w-[72px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderMonth\"\n aria-label=\"Month\"\n (change)=\"onSingleMonthChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let monthOption of monthOptions\"\n [value]=\"monthOption.value\"\n [selected]=\"monthOption.value === singleHeaderMonth\"\n >\n {{ monthOption.label }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n <div [ngClass]=\"dropdownClasses('w-16 sm:w-[82px]')\">\n <select\n [ngClass]=\"dropdownSelectClasses()\"\n [ngStyle]=\"dropdownSelectStyle\"\n [value]=\"singleHeaderYear\"\n aria-label=\"Year\"\n (change)=\"onSingleYearChange($any($event.target).value)\"\n >\n <option\n *ngFor=\"let year of yearOptions\"\n [value]=\"year\"\n [selected]=\"year === singleHeaderYear\"\n >\n {{ year }}\n </option>\n </select>\n <svg viewBox=\"0 0 24 24\" class=\"h-3 w-3 text-foreground\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </div>\n </div>\n </ng-container>\n\n <ng-template #plainTitle>\n <div class=\"flex min-w-0 flex-1 items-center justify-center\">\n <p class=\"m-0 text-foreground text-center text-sm font-medium leading-5\">\n {{ month.title }}\n </p>\n </div>\n </ng-template>\n\n <button\n *ngIf=\"month.showNextButton; else nextPlaceholder\"\n type=\"button\"\n [ngClass]=\"navButtonClasses()\"\n aria-label=\"Next month\"\n (click)=\"goToNextMonth()\"\n [disabled]=\"readonly\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n <ng-template #nextPlaceholder>\n <div [ngClass]=\"navPlaceholderClasses()\" aria-hidden=\"true\"></div>\n </ng-template>\n </div>\n\n <div [ngClass]=\"calendarGridWrapClasses()\">\n <div [ngClass]=\"weekdayRowClasses()\">\n <div *ngFor=\"let day of weekdays; trackBy: trackByIndex\" [ngClass]=\"weekdayCellClasses()\">\n <span>{{ day }}</span>\n </div>\n </div>\n\n <div *ngFor=\"let week of month.weeks; trackBy: trackByIndex\" [ngClass]=\"weekRowClasses()\">\n <div *ngFor=\"let cell of week; trackBy: trackByDate\" [ngClass]=\"dayCellClasses(cell)\">\n <button\n type=\"button\"\n [ngClass]=\"dayButtonClasses(cell)\"\n [disabled]=\"readonly\"\n [attr.aria-selected]=\"cell.selected\"\n [attr.aria-disabled]=\"cell.disabled || readonly\"\n [attr.title]=\"cell.date | date : 'yyyy-MM-dd'\"\n (click)=\"onDatePressed(cell)\"\n >\n <span [ngClass]=\"dayLabelClasses(cell)\">{{ cell.label }}</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n</div>\n" }]
1071
1104
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { variant: [{
1072
1105
  type: Input
1073
1106
  }], className: [{
@@ -1205,66 +1238,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
1205
1238
  type: Output
1206
1239
  }] } });
1207
1240
 
1241
+ /**
1242
+ * Card component - Visual container primitivo
1243
+ *
1244
+ * BREAKING CHANGE en v0.2.0: variant="login" eliminado.
1245
+ * Card es ahora un componente UI puro sin lógica de negocio.
1246
+ *
1247
+ * Para crear un login form, componer con primitivos:
1248
+ *
1249
+ * @example
1250
+ * <pdm-card>
1251
+ * <div pdmCardHeader>
1252
+ * <h3 class="text-lg font-semibold">Login</h3>
1253
+ * <p class="text-sm text-muted-foreground">Enter your credentials</p>
1254
+ * </div>
1255
+ * <div pdmCardContent>
1256
+ * <form [formGroup]="form">
1257
+ * <pdm-field>
1258
+ * <pdm-label>Email</pdm-label>
1259
+ * <pdm-input type="email" formControlName="email" />
1260
+ * </pdm-field>
1261
+ * <pdm-field>
1262
+ * <pdm-label>Password</pdm-label>
1263
+ * <pdm-input-password formControlName="password" />
1264
+ * </pdm-field>
1265
+ * </form>
1266
+ * </div>
1267
+ * <div pdmCardFooter>
1268
+ * <pdm-button (click)="onLogin()">Login</pdm-button>
1269
+ * </div>
1270
+ * </pdm-card>
1271
+ */
1208
1272
  class PdmCardComponent {
1209
1273
  constructor() {
1210
- this.variant = 'default';
1211
1274
  this.className = '';
1212
- this.title = 'Login to your account';
1213
- this.description = 'Enter your email below to login to your account';
1214
- this.actionText = 'Sign up';
1215
- this.emailLabel = 'Email';
1216
- this.emailPlaceholder = 'm@example.com';
1217
- this.passwordLabel = 'Password';
1218
- this.passwordHint = 'Forgot password?';
1219
- this.primaryActionText = 'Login';
1220
- this.secondaryActionText = 'Login with Google';
1221
- this.primaryAction = new EventEmitter();
1222
- this.secondaryAction = new EventEmitter();
1223
- this.actionPressed = new EventEmitter();
1224
- }
1225
- onPrimaryAction() {
1226
- this.primaryAction.emit();
1227
- }
1228
- onSecondaryAction() {
1229
- this.secondaryAction.emit();
1230
- }
1231
- onActionPressed() {
1232
- this.actionPressed.emit();
1233
1275
  }
1234
1276
  }
1235
1277
  PdmCardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1236
- PdmCardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmCardComponent, selector: "pdm-card", inputs: { variant: "variant", className: "className", title: "title", description: "description", actionText: "actionText", emailLabel: "emailLabel", emailPlaceholder: "emailPlaceholder", passwordLabel: "passwordLabel", passwordHint: "passwordHint", primaryActionText: "primaryActionText", secondaryActionText: "secondaryActionText" }, outputs: { primaryAction: "primaryAction", secondaryAction: "secondaryAction", actionPressed: "actionPressed" }, ngImport: i0, template: "<section\n [ngClass]=\"[\n 'w-full rounded-lg border border-border bg-background py-6 shadow-sm',\n className\n ]\"\n>\n <ng-container *ngIf=\"variant === 'login'; else defaultCard\">\n <div class=\"flex w-full items-start gap-1.5 px-6\">\n <div class=\"min-w-0 flex-1\">\n <h3 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ title }}</h3>\n <p class=\"m-0 mt-1.5 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border-0 bg-transparent px-4 py-2 text-sm font-medium text-foreground\"\n (click)=\"onActionPressed()\"\n >\n {{ actionText }}\n </button>\n </div>\n\n <div class=\"mt-6 flex flex-col gap-4 px-6\">\n <div class=\"w-full\">\n <label class=\"mb-3 block text-sm font-medium text-foreground\">{{ emailLabel }}</label>\n <input\n type=\"email\"\n [placeholder]=\"emailPlaceholder\"\n class=\"h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n </div>\n\n <div class=\"w-full\">\n <div class=\"mb-3 flex w-full items-center justify-between gap-4\">\n <label class=\"text-sm font-medium text-foreground\">{{ passwordLabel }}</label>\n <button type=\"button\" class=\"appearance-none border-0 bg-transparent p-0 text-sm text-foreground\">\n {{ passwordHint }}\n </button>\n </div>\n <input\n type=\"password\"\n class=\"h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n </div>\n </div>\n\n <div class=\"mt-6 flex w-full flex-col gap-2 px-6\">\n <button\n type=\"button\"\n class=\"flex h-9 w-full appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onPrimaryAction()\"\n >\n {{ primaryActionText }}\n </button>\n <button\n type=\"button\"\n class=\"flex h-9 w-full appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n </div>\n </ng-container>\n\n <ng-template #defaultCard>\n <div class=\"flex w-full flex-col gap-6\">\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardHeader]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardContent]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardFooter]\"></ng-content>\n </div>\n </div>\n </ng-template>\n</section>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1278
+ PdmCardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmCardComponent, selector: "pdm-card", inputs: { className: "className" }, ngImport: i0, template: "<section\n [ngClass]=\"[\n 'w-full rounded-lg border border-border bg-background py-6 shadow-sm',\n className\n ]\"\n>\n <div class=\"flex w-full flex-col gap-6\">\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardHeader]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardContent]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardFooter]\"></ng-content>\n </div>\n </div>\n</section>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1237
1279
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmCardComponent, decorators: [{
1238
1280
  type: Component,
1239
- args: [{ selector: 'pdm-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n [ngClass]=\"[\n 'w-full rounded-lg border border-border bg-background py-6 shadow-sm',\n className\n ]\"\n>\n <ng-container *ngIf=\"variant === 'login'; else defaultCard\">\n <div class=\"flex w-full items-start gap-1.5 px-6\">\n <div class=\"min-w-0 flex-1\">\n <h3 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ title }}</h3>\n <p class=\"m-0 mt-1.5 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border-0 bg-transparent px-4 py-2 text-sm font-medium text-foreground\"\n (click)=\"onActionPressed()\"\n >\n {{ actionText }}\n </button>\n </div>\n\n <div class=\"mt-6 flex flex-col gap-4 px-6\">\n <div class=\"w-full\">\n <label class=\"mb-3 block text-sm font-medium text-foreground\">{{ emailLabel }}</label>\n <input\n type=\"email\"\n [placeholder]=\"emailPlaceholder\"\n class=\"h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n </div>\n\n <div class=\"w-full\">\n <div class=\"mb-3 flex w-full items-center justify-between gap-4\">\n <label class=\"text-sm font-medium text-foreground\">{{ passwordLabel }}</label>\n <button type=\"button\" class=\"appearance-none border-0 bg-transparent p-0 text-sm text-foreground\">\n {{ passwordHint }}\n </button>\n </div>\n <input\n type=\"password\"\n class=\"h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n </div>\n </div>\n\n <div class=\"mt-6 flex w-full flex-col gap-2 px-6\">\n <button\n type=\"button\"\n class=\"flex h-9 w-full appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onPrimaryAction()\"\n >\n {{ primaryActionText }}\n </button>\n <button\n type=\"button\"\n class=\"flex h-9 w-full appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n </div>\n </ng-container>\n\n <ng-template #defaultCard>\n <div class=\"flex w-full flex-col gap-6\">\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardHeader]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardContent]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardFooter]\"></ng-content>\n </div>\n </div>\n </ng-template>\n</section>\n" }]
1240
- }], propDecorators: { variant: [{
1241
- type: Input
1242
- }], className: [{
1243
- type: Input
1244
- }], title: [{
1245
- type: Input
1246
- }], description: [{
1247
- type: Input
1248
- }], actionText: [{
1249
- type: Input
1250
- }], emailLabel: [{
1251
- type: Input
1252
- }], emailPlaceholder: [{
1253
- type: Input
1254
- }], passwordLabel: [{
1255
- type: Input
1256
- }], passwordHint: [{
1257
- type: Input
1258
- }], primaryActionText: [{
1259
- type: Input
1260
- }], secondaryActionText: [{
1281
+ args: [{ selector: 'pdm-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n [ngClass]=\"[\n 'w-full rounded-lg border border-border bg-background py-6 shadow-sm',\n className\n ]\"\n>\n <div class=\"flex w-full flex-col gap-6\">\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardHeader]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardContent]\"></ng-content>\n </div>\n <div class=\"px-6\">\n <ng-content select=\"[pdmCardFooter]\"></ng-content>\n </div>\n </div>\n</section>\n" }]
1282
+ }], propDecorators: { className: [{
1261
1283
  type: Input
1262
- }], primaryAction: [{
1263
- type: Output
1264
- }], secondaryAction: [{
1265
- type: Output
1266
- }], actionPressed: [{
1267
- type: Output
1268
1284
  }] } });
1269
1285
 
1270
1286
  class PdmChartComponent {
@@ -1764,10 +1780,10 @@ class PdmCommandComponent {
1764
1780
  }
1765
1781
  }
1766
1782
  PdmCommandComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmCommandComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1767
- PdmCommandComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmCommandComponent, selector: "pdm-command", inputs: { open: "open", hintLabel: "hintLabel", hintKey: "hintKey", placeholder: "placeholder", emptyMessage: "emptyMessage", items: "items", className: "className" }, outputs: { itemSelect: "itemSelect", openChange: "openChange" }, ngImport: i0, template: "<div [ngClass]=\"['w-full', className]\">\n <div *ngIf=\"!open\" class=\"flex items-center gap-1\">\n <span class=\"text-sm font-medium text-muted-foreground\">{{ hintLabel }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-5 appearance-none items-center gap-0.5 rounded-sm border border-border bg-muted px-1.5\"\n (click)=\"toggleOpen()\"\n >\n <pdm-icon name=\"command\" [size]=\"12\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <span class=\"text-xs text-muted-foreground\">{{ hintKey }}</span>\n </button>\n </div>\n\n <section\n *ngIf=\"open\"\n class=\"flex w-full flex-col overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-md\"\n >\n <div class=\"flex items-center gap-2 border-b border-border px-3\">\n <pdm-icon name=\"search\" [size]=\"16\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n [value]=\"query\"\n (input)=\"onQueryChange($event)\"\n class=\"h-10 w-full bg-transparent py-3 text-sm text-foreground outline-none placeholder:text-muted-foreground\"\n />\n </div>\n\n <div class=\"max-h-72 overflow-y-auto p-1\">\n <ng-container *ngFor=\"let group of groupedItems; let groupIndex = index\">\n <div *ngIf=\"group.name\" class=\"px-2 py-1.5 text-xs text-muted-foreground\">{{ group.name }}</div>\n <button\n *ngFor=\"let item of group.items\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"flex w-full appearance-none items-center gap-2 rounded-sm border-0 bg-transparent px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground\"\n [ngClass]=\"[\n item.disabled ? 'opacity-50' : '',\n item.label === 'Calendar' ? 'bg-accent text-accent-foreground' : ''\n ]\"\n (click)=\"select(item.value)\"\n >\n <span class=\"inline-flex h-4 w-4 items-center justify-center text-foreground\">\n <pdm-icon *ngIf=\"item.icon\" [name]=\"item.icon\" [size]=\"16\" [decorative]=\"true\"></pdm-icon>\n </span>\n <span class=\"min-w-0 flex-1 text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n </button>\n <div *ngIf=\"groupIndex === 0 && groupedItems.length > 1\" class=\"my-1 border-t border-border\"></div>\n </ng-container>\n\n <p *ngIf=\"filteredItems.length === 0\" class=\"m-0 py-6 text-center text-sm text-muted-foreground\">{{ emptyMessage }}</p>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PdmIconComponent, selector: "pdm-icon", inputs: ["name", "library", "assetUrl", "size", "strokeWidth", "className", "ariaLabel", "decorative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1783
+ PdmCommandComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmCommandComponent, selector: "pdm-command", inputs: { open: "open", hintLabel: "hintLabel", hintKey: "hintKey", placeholder: "placeholder", emptyMessage: "emptyMessage", items: "items", className: "className" }, outputs: { itemSelect: "itemSelect", openChange: "openChange" }, ngImport: i0, template: "<div [ngClass]=\"['w-full', className]\">\n <div *ngIf=\"!open\" class=\"flex items-center gap-1\">\n <span class=\"text-sm font-medium text-muted-foreground\">{{ hintLabel }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-5 appearance-none items-center gap-0.5 rounded-sm border border-border bg-muted px-1.5\"\n (click)=\"toggleOpen()\"\n >\n <pdm-icon name=\"command\" [size]=\"12\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <span class=\"text-xs text-muted-foreground\">{{ hintKey }}</span>\n </button>\n </div>\n\n <section\n *ngIf=\"open\"\n class=\"flex w-full flex-col overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-md\"\n >\n <div class=\"flex items-center gap-2 border-b border-border px-3\">\n <pdm-icon name=\"search\" [size]=\"16\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n [value]=\"query\"\n (input)=\"onQueryChange($event)\"\n class=\"h-10 w-full bg-transparent py-3 text-sm text-foreground outline-none placeholder:text-muted-foreground\"\n />\n </div>\n\n <div class=\"max-h-[50vh] overflow-y-auto p-1 md:max-h-72\">\n <ng-container *ngFor=\"let group of groupedItems; let groupIndex = index\">\n <div *ngIf=\"group.name\" class=\"px-2 py-1.5 text-xs text-muted-foreground\">{{ group.name }}</div>\n <button\n *ngFor=\"let item of group.items\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"flex w-full appearance-none items-center gap-2 rounded-sm border-0 bg-transparent px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground\"\n [ngClass]=\"[\n item.disabled ? 'opacity-50' : '',\n item.label === 'Calendar' ? 'bg-accent text-accent-foreground' : ''\n ]\"\n (click)=\"select(item.value)\"\n >\n <span class=\"inline-flex h-4 w-4 items-center justify-center text-foreground\">\n <pdm-icon *ngIf=\"item.icon\" [name]=\"item.icon\" [size]=\"16\" [decorative]=\"true\"></pdm-icon>\n </span>\n <span class=\"min-w-0 flex-1 text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n </button>\n <div *ngIf=\"groupIndex === 0 && groupedItems.length > 1\" class=\"my-1 border-t border-border\"></div>\n </ng-container>\n\n <p *ngIf=\"filteredItems.length === 0\" class=\"m-0 py-6 text-center text-sm text-muted-foreground\">{{ emptyMessage }}</p>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PdmIconComponent, selector: "pdm-icon", inputs: ["name", "library", "assetUrl", "size", "strokeWidth", "className", "ariaLabel", "decorative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1768
1784
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmCommandComponent, decorators: [{
1769
1785
  type: Component,
1770
- args: [{ selector: 'pdm-command', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"['w-full', className]\">\n <div *ngIf=\"!open\" class=\"flex items-center gap-1\">\n <span class=\"text-sm font-medium text-muted-foreground\">{{ hintLabel }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-5 appearance-none items-center gap-0.5 rounded-sm border border-border bg-muted px-1.5\"\n (click)=\"toggleOpen()\"\n >\n <pdm-icon name=\"command\" [size]=\"12\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <span class=\"text-xs text-muted-foreground\">{{ hintKey }}</span>\n </button>\n </div>\n\n <section\n *ngIf=\"open\"\n class=\"flex w-full flex-col overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-md\"\n >\n <div class=\"flex items-center gap-2 border-b border-border px-3\">\n <pdm-icon name=\"search\" [size]=\"16\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n [value]=\"query\"\n (input)=\"onQueryChange($event)\"\n class=\"h-10 w-full bg-transparent py-3 text-sm text-foreground outline-none placeholder:text-muted-foreground\"\n />\n </div>\n\n <div class=\"max-h-72 overflow-y-auto p-1\">\n <ng-container *ngFor=\"let group of groupedItems; let groupIndex = index\">\n <div *ngIf=\"group.name\" class=\"px-2 py-1.5 text-xs text-muted-foreground\">{{ group.name }}</div>\n <button\n *ngFor=\"let item of group.items\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"flex w-full appearance-none items-center gap-2 rounded-sm border-0 bg-transparent px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground\"\n [ngClass]=\"[\n item.disabled ? 'opacity-50' : '',\n item.label === 'Calendar' ? 'bg-accent text-accent-foreground' : ''\n ]\"\n (click)=\"select(item.value)\"\n >\n <span class=\"inline-flex h-4 w-4 items-center justify-center text-foreground\">\n <pdm-icon *ngIf=\"item.icon\" [name]=\"item.icon\" [size]=\"16\" [decorative]=\"true\"></pdm-icon>\n </span>\n <span class=\"min-w-0 flex-1 text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n </button>\n <div *ngIf=\"groupIndex === 0 && groupedItems.length > 1\" class=\"my-1 border-t border-border\"></div>\n </ng-container>\n\n <p *ngIf=\"filteredItems.length === 0\" class=\"m-0 py-6 text-center text-sm text-muted-foreground\">{{ emptyMessage }}</p>\n </div>\n </section>\n</div>\n" }]
1786
+ args: [{ selector: 'pdm-command', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"['w-full', className]\">\n <div *ngIf=\"!open\" class=\"flex items-center gap-1\">\n <span class=\"text-sm font-medium text-muted-foreground\">{{ hintLabel }}</span>\n <button\n type=\"button\"\n class=\"inline-flex h-5 appearance-none items-center gap-0.5 rounded-sm border border-border bg-muted px-1.5\"\n (click)=\"toggleOpen()\"\n >\n <pdm-icon name=\"command\" [size]=\"12\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <span class=\"text-xs text-muted-foreground\">{{ hintKey }}</span>\n </button>\n </div>\n\n <section\n *ngIf=\"open\"\n class=\"flex w-full flex-col overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-md\"\n >\n <div class=\"flex items-center gap-2 border-b border-border px-3\">\n <pdm-icon name=\"search\" [size]=\"16\" className=\"text-muted-foreground\" [decorative]=\"true\"></pdm-icon>\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n [value]=\"query\"\n (input)=\"onQueryChange($event)\"\n class=\"h-10 w-full bg-transparent py-3 text-sm text-foreground outline-none placeholder:text-muted-foreground\"\n />\n </div>\n\n <div class=\"max-h-[50vh] overflow-y-auto p-1 md:max-h-72\">\n <ng-container *ngFor=\"let group of groupedItems; let groupIndex = index\">\n <div *ngIf=\"group.name\" class=\"px-2 py-1.5 text-xs text-muted-foreground\">{{ group.name }}</div>\n <button\n *ngFor=\"let item of group.items\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"flex w-full appearance-none items-center gap-2 rounded-sm border-0 bg-transparent px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground\"\n [ngClass]=\"[\n item.disabled ? 'opacity-50' : '',\n item.label === 'Calendar' ? 'bg-accent text-accent-foreground' : ''\n ]\"\n (click)=\"select(item.value)\"\n >\n <span class=\"inline-flex h-4 w-4 items-center justify-center text-foreground\">\n <pdm-icon *ngIf=\"item.icon\" [name]=\"item.icon\" [size]=\"16\" [decorative]=\"true\"></pdm-icon>\n </span>\n <span class=\"min-w-0 flex-1 text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n </button>\n <div *ngIf=\"groupIndex === 0 && groupedItems.length > 1\" class=\"my-1 border-t border-border\"></div>\n </ng-container>\n\n <p *ngIf=\"filteredItems.length === 0\" class=\"m-0 py-6 text-center text-sm text-muted-foreground\">{{ emptyMessage }}</p>\n </div>\n </section>\n</div>\n" }]
1771
1787
  }], propDecorators: { open: [{
1772
1788
  type: Input
1773
1789
  }], hintLabel: [{
@@ -1850,10 +1866,10 @@ class PdmContextMenuComponent {
1850
1866
  }
1851
1867
  }
1852
1868
  PdmContextMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmContextMenuComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1853
- PdmContextMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmContextMenuComponent, selector: "pdm-context-menu", inputs: { items: "items", className: "className", triggerLabel: "triggerLabel", width: "width", height: "height" }, outputs: { itemSelect: "itemSelect" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div class=\"relative\" [ngClass]=\"className\" (contextmenu)=\"onContextMenu($event)\">\n <div\n class=\"flex items-center justify-center rounded-md border border-dashed border-border\"\n [style.width.px]=\"width\"\n [style.height.px]=\"height\"\n >\n <span class=\"text-sm font-medium text-foreground\">{{ triggerLabel }}</span>\n </div>\n\n <div\n *ngIf=\"open\"\n class=\"fixed z-50 w-52 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\"\n [style.left.px]=\"x + 4\"\n [style.top.px]=\"y + 2\"\n >\n <div>\n <ng-container *ngFor=\"let item of items\">\n <div *ngIf=\"item.type === 'separator'\" class=\"-mx-1 my-1 h-px bg-muted\"></div>\n\n <div *ngIf=\"item.type === 'label'\" class=\"px-2 py-1.5 text-sm font-semibold text-foreground\">\n {{ item.label }}\n </div>\n\n <button\n *ngIf=\"!item.type || item.type === 'item'\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent py-1.5 pr-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n [ngClass]=\"item.inset ? 'pl-8' : 'px-2'\"\n (click)=\"select(item)\"\n >\n <span class=\"mr-2 inline-flex w-4 shrink-0 items-center justify-center text-foreground\">\n <svg *ngIf=\"item.checked\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 12.5L9.2 16.7L19 7\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n <span *ngIf=\"item.selectedDot\" class=\"h-2 w-2 rounded-full bg-foreground\"></span>\n </span>\n <span class=\"min-w-0 flex-1 truncate text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n <svg *ngIf=\"item.showChevron\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5 text-muted-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </ng-container>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1869
+ PdmContextMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmContextMenuComponent, selector: "pdm-context-menu", inputs: { items: "items", className: "className", triggerLabel: "triggerLabel", width: "width", height: "height" }, outputs: { itemSelect: "itemSelect" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div class=\"relative\" [ngClass]=\"className\" (contextmenu)=\"onContextMenu($event)\">\n <div\n class=\"flex items-center justify-center rounded-md border border-dashed border-border\"\n [style.width.px]=\"width\"\n [style.height.px]=\"height\"\n >\n <span class=\"text-sm font-medium text-foreground\">{{ triggerLabel }}</span>\n </div>\n\n <div\n *ngIf=\"open\"\n class=\"fixed z-[70] min-w-48 max-w-xs rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md sm:min-w-52\"\n [style.left.px]=\"x + 4\"\n [style.top.px]=\"y + 2\"\n >\n <div>\n <ng-container *ngFor=\"let item of items\">\n <div *ngIf=\"item.type === 'separator'\" class=\"-mx-1 my-1 h-px bg-muted\"></div>\n\n <div *ngIf=\"item.type === 'label'\" class=\"px-2 py-1.5 text-sm font-semibold text-foreground\">\n {{ item.label }}\n </div>\n\n <button\n *ngIf=\"!item.type || item.type === 'item'\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent py-1.5 pr-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n [ngClass]=\"item.inset ? 'pl-8' : 'px-2'\"\n (click)=\"select(item)\"\n >\n <span class=\"mr-2 inline-flex w-4 shrink-0 items-center justify-center text-foreground\">\n <svg *ngIf=\"item.checked\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 12.5L9.2 16.7L19 7\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n <span *ngIf=\"item.selectedDot\" class=\"h-2 w-2 rounded-full bg-foreground\"></span>\n </span>\n <span class=\"min-w-0 flex-1 truncate text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n <svg *ngIf=\"item.showChevron\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5 text-muted-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </ng-container>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1854
1870
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmContextMenuComponent, decorators: [{
1855
1871
  type: Component,
1856
- args: [{ selector: 'pdm-context-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"relative\" [ngClass]=\"className\" (contextmenu)=\"onContextMenu($event)\">\n <div\n class=\"flex items-center justify-center rounded-md border border-dashed border-border\"\n [style.width.px]=\"width\"\n [style.height.px]=\"height\"\n >\n <span class=\"text-sm font-medium text-foreground\">{{ triggerLabel }}</span>\n </div>\n\n <div\n *ngIf=\"open\"\n class=\"fixed z-50 w-52 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\"\n [style.left.px]=\"x + 4\"\n [style.top.px]=\"y + 2\"\n >\n <div>\n <ng-container *ngFor=\"let item of items\">\n <div *ngIf=\"item.type === 'separator'\" class=\"-mx-1 my-1 h-px bg-muted\"></div>\n\n <div *ngIf=\"item.type === 'label'\" class=\"px-2 py-1.5 text-sm font-semibold text-foreground\">\n {{ item.label }}\n </div>\n\n <button\n *ngIf=\"!item.type || item.type === 'item'\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent py-1.5 pr-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n [ngClass]=\"item.inset ? 'pl-8' : 'px-2'\"\n (click)=\"select(item)\"\n >\n <span class=\"mr-2 inline-flex w-4 shrink-0 items-center justify-center text-foreground\">\n <svg *ngIf=\"item.checked\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 12.5L9.2 16.7L19 7\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n <span *ngIf=\"item.selectedDot\" class=\"h-2 w-2 rounded-full bg-foreground\"></span>\n </span>\n <span class=\"min-w-0 flex-1 truncate text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n <svg *ngIf=\"item.showChevron\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5 text-muted-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </ng-container>\n </div>\n </div>\n</div>\n" }]
1872
+ args: [{ selector: 'pdm-context-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"relative\" [ngClass]=\"className\" (contextmenu)=\"onContextMenu($event)\">\n <div\n class=\"flex items-center justify-center rounded-md border border-dashed border-border\"\n [style.width.px]=\"width\"\n [style.height.px]=\"height\"\n >\n <span class=\"text-sm font-medium text-foreground\">{{ triggerLabel }}</span>\n </div>\n\n <div\n *ngIf=\"open\"\n class=\"fixed z-[70] min-w-48 max-w-xs rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md sm:min-w-52\"\n [style.left.px]=\"x + 4\"\n [style.top.px]=\"y + 2\"\n >\n <div>\n <ng-container *ngFor=\"let item of items\">\n <div *ngIf=\"item.type === 'separator'\" class=\"-mx-1 my-1 h-px bg-muted\"></div>\n\n <div *ngIf=\"item.type === 'label'\" class=\"px-2 py-1.5 text-sm font-semibold text-foreground\">\n {{ item.label }}\n </div>\n\n <button\n *ngIf=\"!item.type || item.type === 'item'\"\n type=\"button\"\n [disabled]=\"item.disabled\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent py-1.5 pr-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n [ngClass]=\"item.inset ? 'pl-8' : 'px-2'\"\n (click)=\"select(item)\"\n >\n <span class=\"mr-2 inline-flex w-4 shrink-0 items-center justify-center text-foreground\">\n <svg *ngIf=\"item.checked\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 12.5L9.2 16.7L19 7\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n <span *ngIf=\"item.selectedDot\" class=\"h-2 w-2 rounded-full bg-foreground\"></span>\n </span>\n <span class=\"min-w-0 flex-1 truncate text-foreground\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"text-xs text-muted-foreground\">{{ item.shortcut }}</span>\n <svg *ngIf=\"item.showChevron\" viewBox=\"0 0 24 24\" class=\"h-3.5 w-3.5 text-muted-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 6L15 12L9 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </ng-container>\n </div>\n </div>\n</div>\n" }]
1857
1873
  }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { items: [{
1858
1874
  type: Input
1859
1875
  }], className: [{
@@ -1871,31 +1887,459 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
1871
1887
  args: ['document:keydown.escape']
1872
1888
  }] } });
1873
1889
 
1890
+ /**
1891
+ * Sistema de responsive utilities para PDM UI Kit
1892
+ *
1893
+ * Proporciona constantes, tipos y helpers para manejar responsive design
1894
+ * de forma consistente en todos los componentes.
1895
+ */
1896
+ /**
1897
+ * Breakpoints estándar de Tailwind CSS
1898
+ * Mobile-first approach: los estilos base son para mobile, los breakpoints son MIN-WIDTH
1899
+ */
1900
+ const BREAKPOINTS = {
1901
+ sm: '640px',
1902
+ md: '768px',
1903
+ lg: '1024px',
1904
+ xl: '1280px',
1905
+ '2xl': '1536px' // extra large desktop
1906
+ };
1907
+ /**
1908
+ * Helper para generar clases responsive de forma programática
1909
+ *
1910
+ * @example
1911
+ * responsive({ default: 'block', sm: 'flex', lg: 'grid' })
1912
+ * // Returns: 'block sm:flex lg:grid'
1913
+ */
1914
+ function responsive(config) {
1915
+ const classes = [];
1916
+ if (config.default) {
1917
+ classes.push(config.default);
1918
+ }
1919
+ ['sm', 'md', 'lg', 'xl', '2xl'].forEach(bp => {
1920
+ if (config[bp]) {
1921
+ classes.push(`${bp}:${config[bp]}`);
1922
+ }
1923
+ });
1924
+ return classes.join(' ');
1925
+ }
1926
+ /**
1927
+ * Helper para overflow responsive
1928
+ * Maneja el caso común de scroll en mobile, auto en desktop
1929
+ *
1930
+ * @example
1931
+ * overflowResponsive('x', 'scroll', 'auto')
1932
+ * // Returns: 'overflow-x-scroll sm:overflow-x-auto'
1933
+ */
1934
+ function overflowResponsive(axis, mobile, desktop) {
1935
+ const axisClass = axis === 'both' ? 'overflow' : `overflow-${axis}`;
1936
+ const mobileClass = `${axisClass}-${mobile}`;
1937
+ if (!desktop || desktop === mobile) {
1938
+ return mobileClass;
1939
+ }
1940
+ return `${mobileClass} sm:${axisClass}-${desktop}`;
1941
+ }
1942
+ /**
1943
+ * Helper para spacing responsive
1944
+ * Útil para padding/margin que necesita ajustarse por breakpoint
1945
+ *
1946
+ * @example
1947
+ * spacingResponsive('px', { default: '4', sm: '6', lg: '8' })
1948
+ * // Returns: 'px-4 sm:px-6 lg:px-8'
1949
+ */
1950
+ function spacingResponsive(property, values) {
1951
+ return responsive(Object.entries(values).reduce((acc, [key, value]) => {
1952
+ acc[key] = `${property}-${value}`;
1953
+ return acc;
1954
+ }, {}));
1955
+ }
1956
+ /**
1957
+ * Helper para width responsive
1958
+ *
1959
+ * @example
1960
+ * widthResponsive({ default: 'full', sm: 'auto', lg: '1/2' })
1961
+ * // Returns: 'w-full sm:w-auto lg:w-1/2'
1962
+ */
1963
+ function widthResponsive(values) {
1964
+ return responsive(Object.entries(values).reduce((acc, [key, value]) => {
1965
+ acc[key] = `w-${value}`;
1966
+ return acc;
1967
+ }, {}));
1968
+ }
1969
+ /**
1970
+ * Clases comunes para containers responsive
1971
+ * Pensadas para wrappers que contienen contenido que puede desbordar
1972
+ */
1973
+ const RESPONSIVE_CONTAINER = {
1974
+ // Container con scroll horizontal en mobile, contenido visible en desktop
1975
+ tableWrapper: 'relative w-full overflow-x-auto sm:overflow-x-visible',
1976
+ // Container con padding negativo en mobile para scroll edge-to-edge
1977
+ tableWrapperFullBleed: 'relative w-full -mx-4 px-4 overflow-x-auto sm:mx-0 sm:px-0 sm:overflow-x-visible',
1978
+ // Container con max-width responsive
1979
+ contentWrapper: 'w-full mx-auto px-4 sm:px-6 lg:px-8 max-w-screen-2xl',
1980
+ // Container para modals/dialogs
1981
+ modalWrapper: 'w-full max-w-lg mx-auto px-4 sm:px-0',
1982
+ // Container para forms
1983
+ formWrapper: 'w-full max-w-md mx-auto space-y-4'
1984
+ };
1985
+ /**
1986
+ * Clases comunes para display responsive
1987
+ */
1988
+ const RESPONSIVE_DISPLAY = {
1989
+ // Ocultar en mobile, mostrar en desktop
1990
+ hideOnMobile: 'hidden sm:block',
1991
+ // Mostrar solo en mobile
1992
+ showOnMobile: 'block sm:hidden',
1993
+ // Stack en mobile, flex en desktop
1994
+ stackToFlex: 'flex flex-col sm:flex-row',
1995
+ // Stack en mobile, grid en desktop
1996
+ stackToGrid: 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3'
1997
+ };
1998
+ /**
1999
+ * Clases para table responsive strategies
2000
+ */
2001
+ const TABLE_RESPONSIVE = {
2002
+ // Scroll horizontal (default, más simple)
2003
+ scroll: {
2004
+ wrapper: 'relative w-full overflow-x-auto',
2005
+ table: 'w-full min-w-full',
2006
+ cell: 'whitespace-nowrap'
2007
+ },
2008
+ // Permitir wrap del contenido
2009
+ wrap: {
2010
+ wrapper: 'relative w-full overflow-x-auto',
2011
+ table: 'w-full',
2012
+ cell: 'whitespace-normal break-words'
2013
+ },
2014
+ // Stack en mobile (cada fila se convierte en card)
2015
+ // Requiere lógica adicional en el componente
2016
+ stack: {
2017
+ wrapper: 'relative w-full',
2018
+ table: 'w-full',
2019
+ row: 'block sm:table-row border-b sm:border-b-0',
2020
+ cell: 'block sm:table-cell py-2 sm:py-0 before:content-[attr(data-label)] before:font-medium before:inline-block before:w-32 sm:before:content-none'
2021
+ },
2022
+ // Collapse: ocultar columnas menos importantes en mobile
2023
+ // Se usa con clases de visibility en las columnas específicas
2024
+ collapse: {
2025
+ wrapper: 'relative w-full overflow-x-auto',
2026
+ table: 'w-full',
2027
+ cell: 'whitespace-nowrap',
2028
+ // Estas clases se aplican a columnas opcionales
2029
+ optionalColumn: 'hidden md:table-cell'
2030
+ }
2031
+ };
2032
+
2033
+ /**
2034
+ * Componente base de tabla con soporte responsive
2035
+ *
2036
+ * SIMPLIFICADO: Ya no incluye drag & drop (usar pdm-draggable-table para eso)
2037
+ *
2038
+ * @example
2039
+ * // Tabla simple con scroll horizontal
2040
+ * <pdm-table variant="default">
2041
+ * <thead><tr><th>Name</th><th>Email</th></tr></thead>
2042
+ * <tbody><tr><td>John</td><td>john@example.com</td></tr></tbody>
2043
+ * </pdm-table>
2044
+ *
2045
+ * @example
2046
+ * // Tabla interactiva con wrap en mobile
2047
+ * <pdm-table variant="interactive" responsiveStrategy="wrap">
2048
+ * ...
2049
+ * </pdm-table>
2050
+ */
2051
+ class PdmTableComponent {
2052
+ constructor() {
2053
+ /**
2054
+ * Variante visual de la tabla
2055
+ * - default: tabla básica sin estilos extra
2056
+ * - data: tabla con bordes y espaciado para data
2057
+ * - interactive: tabla con hover, sticky header y estilos interactivos
2058
+ */
2059
+ this.variant = 'default';
2060
+ /**
2061
+ * Estrategia responsive para la tabla
2062
+ * - scroll: scroll horizontal en mobile (default, más simple)
2063
+ * - wrap: permite que el contenido haga wrap
2064
+ * - stack: convierte filas en cards en mobile (requiere data-label en celdas)
2065
+ * - collapse: oculta columnas menos importantes en mobile
2066
+ */
2067
+ this.responsiveStrategy = 'scroll';
2068
+ /**
2069
+ * Clases CSS adicionales para el wrapper
2070
+ */
2071
+ this.className = '';
2072
+ /**
2073
+ * Si es true, aplica padding negativo en mobile para scroll edge-to-edge
2074
+ * Útil cuando la tabla está dentro de un container con padding
2075
+ */
2076
+ this.fullBleed = false;
2077
+ }
2078
+ get wrapperClasses() {
2079
+ const baseClasses = ['relative', 'w-full'];
2080
+ const strategyClasses = this.getResponsiveStrategyClasses();
2081
+ const variantClasses = this.getVariantWrapperClasses();
2082
+ // Full bleed: scroll edge-to-edge en mobile
2083
+ if (this.fullBleed && this.responsiveStrategy === 'scroll') {
2084
+ baseClasses.push('-mx-4', 'px-4', 'sm:mx-0', 'sm:px-0');
2085
+ }
2086
+ return [
2087
+ ...baseClasses,
2088
+ ...strategyClasses,
2089
+ ...variantClasses,
2090
+ this.className
2091
+ ].filter(Boolean);
2092
+ }
2093
+ get tableClasses() {
2094
+ const baseClasses = ['w-full', 'caption-bottom', 'text-sm'];
2095
+ const variantClasses = this.getVariantTableClasses();
2096
+ const cellClasses = this.getCellClasses();
2097
+ return [...baseClasses, ...variantClasses, ...cellClasses].filter(Boolean);
2098
+ }
2099
+ getResponsiveStrategyClasses() {
2100
+ const strategy = TABLE_RESPONSIVE[this.responsiveStrategy];
2101
+ if (this.responsiveStrategy === 'scroll') {
2102
+ return ['overflow-x-auto'];
2103
+ }
2104
+ if (this.responsiveStrategy === 'wrap') {
2105
+ return ['overflow-x-auto'];
2106
+ }
2107
+ if (this.responsiveStrategy === 'stack') {
2108
+ // Stack requiere lógica en el template, aquí solo el wrapper
2109
+ return [];
2110
+ }
2111
+ if (this.responsiveStrategy === 'collapse') {
2112
+ return ['overflow-x-auto'];
2113
+ }
2114
+ return ['overflow-auto'];
2115
+ }
2116
+ getVariantWrapperClasses() {
2117
+ if (this.variant === 'interactive') {
2118
+ return ['rounded-xl', 'border', 'border-border', 'bg-background'];
2119
+ }
2120
+ if (this.variant === 'data') {
2121
+ return ['rounded-md', 'border', 'border-border', 'bg-background'];
2122
+ }
2123
+ return [];
2124
+ }
2125
+ getVariantTableClasses() {
2126
+ if (this.variant === 'data') {
2127
+ return [
2128
+ 'border-collapse',
2129
+ 'text-foreground',
2130
+ '[&_thead_tr]:border-b',
2131
+ '[&_thead_tr]:border-border',
2132
+ '[&_tbody_tr]:border-b',
2133
+ '[&_tbody_tr]:border-border',
2134
+ '[&_tbody_tr:last-child]:border-b-0',
2135
+ '[&_th]:h-10',
2136
+ '[&_th]:px-2',
2137
+ '[&_th]:text-left',
2138
+ '[&_th]:align-middle',
2139
+ '[&_th]:font-medium',
2140
+ '[&_td]:p-2',
2141
+ '[&_td]:align-middle'
2142
+ ];
2143
+ }
2144
+ if (this.variant === 'interactive') {
2145
+ return [
2146
+ 'text-foreground',
2147
+ '[&_thead]:sticky',
2148
+ '[&_thead]:top-0',
2149
+ '[&_thead]:z-10',
2150
+ '[&_thead]:bg-muted/70',
2151
+ '[&_thead_tr]:border-b',
2152
+ '[&_thead_tr]:border-border',
2153
+ '[&_th]:h-12',
2154
+ '[&_th]:px-4',
2155
+ '[&_th]:text-left',
2156
+ '[&_th]:align-middle',
2157
+ '[&_th]:text-sm',
2158
+ '[&_th]:font-medium',
2159
+ '[&_tbody_tr]:border-b',
2160
+ '[&_tbody_tr]:border-border',
2161
+ '[&_tbody_tr]:transition-colors',
2162
+ '[&_tbody_tr:hover]:bg-muted/50',
2163
+ '[&_tbody_tr:last-child]:border-b-0',
2164
+ '[&_td]:h-14',
2165
+ '[&_td]:px-4',
2166
+ '[&_td]:align-middle',
2167
+ '[&_td]:text-sm',
2168
+ '[&_svg]:text-muted-foreground'
2169
+ ];
2170
+ }
2171
+ return [];
2172
+ }
2173
+ getCellClasses() {
2174
+ // Manejo responsive de whitespace
2175
+ if (this.responsiveStrategy === 'scroll') {
2176
+ // En scroll, permitir wrap en mobile, nowrap en desktop
2177
+ return ['[&_td]:whitespace-normal', '[&_th]:whitespace-normal', 'sm:[&_td]:whitespace-nowrap', 'sm:[&_th]:whitespace-nowrap'];
2178
+ }
2179
+ if (this.responsiveStrategy === 'wrap') {
2180
+ // En wrap, siempre permitir wrap
2181
+ return ['[&_td]:whitespace-normal', '[&_td]:break-words', '[&_th]:whitespace-normal'];
2182
+ }
2183
+ // Default: nowrap (comportamiento anterior para backward compatibility)
2184
+ return [];
2185
+ }
2186
+ }
2187
+ PdmTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2188
+ PdmTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmTableComponent, selector: "pdm-table", inputs: { variant: "variant", responsiveStrategy: "responsiveStrategy", className: "className", fullBleed: "fullBleed" }, ngImport: i0, template: "<div [ngClass]=\"wrapperClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table-container' : null\">\n <table #tableElement [ngClass]=\"tableClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table' : null\">\n <ng-content></ng-content>\n </table>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2189
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTableComponent, decorators: [{
2190
+ type: Component,
2191
+ args: [{ selector: 'pdm-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"wrapperClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table-container' : null\">\n <table #tableElement [ngClass]=\"tableClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table' : null\">\n <ng-content></ng-content>\n </table>\n</div>\n" }]
2192
+ }], propDecorators: { variant: [{
2193
+ type: Input
2194
+ }], responsiveStrategy: [{
2195
+ type: Input
2196
+ }], className: [{
2197
+ type: Input
2198
+ }], fullBleed: [{
2199
+ type: Input
2200
+ }] } });
2201
+
2202
+ /**
2203
+ * Data-table genérico con paginación, filtrado y selección
2204
+ *
2205
+ * NUEVO: Ahora es genérico y configurable via columnas
2206
+ *
2207
+ * @example
2208
+ * // Definir columnas
2209
+ * columns: PdmDataTableColumn<User>[] = [
2210
+ * { key: 'name', label: 'Name', sortable: true },
2211
+ * { key: 'email', label: 'Email', sortable: true },
2212
+ * { key: 'role', label: 'Role', hideOnMobile: true },
2213
+ * { key: 'createdAt', label: 'Created', render: (val) => formatDate(val) }
2214
+ * ];
2215
+ *
2216
+ * // En el template
2217
+ * <pdm-data-table
2218
+ * [columns]="columns"
2219
+ * [rows]="users"
2220
+ * [selectable]="true"
2221
+ * (selectionChange)="onSelect($event)">
2222
+ * </pdm-data-table>
2223
+ */
1874
2224
  class PdmDataTableComponent {
1875
2225
  constructor() {
1876
2226
  this.className = '';
2227
+ /**
2228
+ * Columnas a mostrar
2229
+ * Si no se provee, intenta inferir del primer row (legacy mode)
2230
+ */
2231
+ this.columns = [];
2232
+ /**
2233
+ * Estrategia responsive de la tabla
2234
+ */
2235
+ this.responsiveStrategy = 'scroll';
2236
+ /**
2237
+ * Si es true, muestra checkbox de selección en cada fila
2238
+ */
2239
+ this.selectable = false;
2240
+ /**
2241
+ * Si es true, muestra botón de acciones (tres puntos) en cada fila
2242
+ */
2243
+ this.showActions = false;
2244
+ /**
2245
+ * Si es true, muestra filtro de búsqueda
2246
+ */
2247
+ this.showFilter = true;
2248
+ /**
2249
+ * Si es true, muestra controles de paginación
2250
+ */
2251
+ this.showPagination = true;
2252
+ /**
2253
+ * Si es true, muestra selector de columnas
2254
+ */
2255
+ this.showColumnSelector = false;
2256
+ // Labels i18n
1877
2257
  this.filterPlaceholder = 'Filter...';
1878
2258
  this.columnsLabel = 'Columns';
1879
- this.statusLabel = 'Status';
1880
- this.emailLabel = 'Email';
1881
- this.amountLabel = 'Amount';
1882
2259
  this.previousLabel = 'Previous';
1883
2260
  this.nextLabel = 'Next';
1884
2261
  this.emptyLabel = 'No results.';
2262
+ this.rowsSelectedLabel = 'row(s) selected';
2263
+ // DEPRECATED: Labels hardcodeados para backward compatibility
2264
+ /**
2265
+ * @deprecated Use columns configuration instead
2266
+ */
2267
+ this.statusLabel = 'Status';
2268
+ /**
2269
+ * @deprecated Use columns configuration instead
2270
+ */
2271
+ this.emailLabel = 'Email';
2272
+ /**
2273
+ * @deprecated Use columns configuration instead
2274
+ */
2275
+ this.amountLabel = 'Amount';
2276
+ /**
2277
+ * Datos a mostrar
2278
+ */
1885
2279
  this.rows = [];
2280
+ /**
2281
+ * Página actual (1-indexed)
2282
+ */
1886
2283
  this.page = 1;
1887
- this.pageSize = 5;
2284
+ /**
2285
+ * Cantidad de filas por página
2286
+ */
2287
+ this.pageSize = 10;
2288
+ /**
2289
+ * Query de filtrado
2290
+ */
1888
2291
  this.query = '';
1889
2292
  this.queryChange = new EventEmitter();
1890
2293
  this.rowAction = new EventEmitter();
1891
2294
  this.pageChange = new EventEmitter();
1892
2295
  this.selectionChange = new EventEmitter();
2296
+ this.columnSort = new EventEmitter();
2297
+ // Estado interno
2298
+ this.selectedRows = new Set();
2299
+ this.sortDirection = 'asc';
2300
+ }
2301
+ /**
2302
+ * Backward compatibility: si no hay columnas definidas, inferir del primer row
2303
+ */
2304
+ get effectiveColumns() {
2305
+ if (this.columns.length > 0) {
2306
+ return this.columns;
2307
+ }
2308
+ // Legacy mode: inferir columnas del primer row (solo para PdmDataTableRow)
2309
+ if (this.rows.length > 0) {
2310
+ const firstRow = this.rows[0];
2311
+ return Object.keys(firstRow)
2312
+ .filter(key => key !== 'selected')
2313
+ .map(key => ({
2314
+ key: key,
2315
+ label: this.getLegacyLabel(key),
2316
+ align: key === 'amount' ? 'right' : 'left'
2317
+ }));
2318
+ }
2319
+ return [];
2320
+ }
2321
+ /**
2322
+ * LEGACY: mapeo de keys a labels hardcodeados
2323
+ */
2324
+ getLegacyLabel(key) {
2325
+ const map = {
2326
+ status: this.statusLabel,
2327
+ email: this.emailLabel,
2328
+ amount: this.amountLabel
2329
+ };
2330
+ return map[key] || key.charAt(0).toUpperCase() + key.slice(1);
1893
2331
  }
1894
2332
  get filteredRows() {
1895
2333
  const q = this.query.trim().toLowerCase();
1896
2334
  if (!q)
1897
2335
  return this.rows;
1898
- return this.rows.filter((r) => r.email.toLowerCase().includes(q));
2336
+ if (this.filterFn) {
2337
+ return this.rows.filter(row => this.filterFn(row, q));
2338
+ }
2339
+ // Filtrado default: buscar en todos los campos string
2340
+ return this.rows.filter(row => {
2341
+ return Object.values(row).some(val => typeof val === 'string' && val.toLowerCase().includes(q));
2342
+ });
1899
2343
  }
1900
2344
  get pagedRows() {
1901
2345
  const start = (this.page - 1) * this.pageSize;
@@ -1905,14 +2349,33 @@ class PdmDataTableComponent {
1905
2349
  return Math.max(1, Math.ceil(this.filteredRows.length / this.pageSize));
1906
2350
  }
1907
2351
  get selectedCount() {
1908
- return this.rows.filter((row) => row.selected).length;
2352
+ return this.selectedRows.size;
1909
2353
  }
1910
2354
  onQueryInput(event) {
1911
2355
  const value = event.target.value;
1912
2356
  this.queryChange.emit(value);
1913
2357
  }
1914
2358
  onToggleRow(row, event) {
1915
- this.selectionChange.emit({ id: row.id, selected: event.target.checked });
2359
+ const checked = event.target.checked;
2360
+ if (checked) {
2361
+ this.selectedRows.add(row);
2362
+ }
2363
+ else {
2364
+ this.selectedRows.delete(row);
2365
+ }
2366
+ this.selectionChange.emit({ row, selected: checked });
2367
+ }
2368
+ onToggleAll(event) {
2369
+ const checked = event.target.checked;
2370
+ if (checked) {
2371
+ this.pagedRows.forEach(row => this.selectedRows.add(row));
2372
+ }
2373
+ else {
2374
+ this.pagedRows.forEach(row => this.selectedRows.delete(row));
2375
+ }
2376
+ }
2377
+ isSelected(row) {
2378
+ return this.selectedRows.has(row);
1916
2379
  }
1917
2380
  previous() {
1918
2381
  if (this.page <= 1)
@@ -1925,25 +2388,75 @@ class PdmDataTableComponent {
1925
2388
  this.pageChange.emit(this.page + 1);
1926
2389
  }
1927
2390
  onAction(row) {
1928
- this.rowAction.emit(row.id);
2391
+ this.rowAction.emit(row);
2392
+ }
2393
+ onSort(column) {
2394
+ if (!column.sortable)
2395
+ return;
2396
+ if (this.sortColumn === column) {
2397
+ this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
2398
+ }
2399
+ else {
2400
+ this.sortColumn = column;
2401
+ this.sortDirection = 'asc';
2402
+ }
2403
+ this.columnSort.emit({ column, direction: this.sortDirection });
2404
+ }
2405
+ getCellValue(row, column) {
2406
+ const value = row[column.key];
2407
+ if (column.render) {
2408
+ return column.render(value, row);
2409
+ }
2410
+ return value != null ? String(value) : '';
2411
+ }
2412
+ getCellClass(column) {
2413
+ const classes = ['px-2', 'py-2'];
2414
+ if (column.align === 'center')
2415
+ classes.push('text-center');
2416
+ if (column.align === 'right')
2417
+ classes.push('text-right');
2418
+ if (column.hideOnMobile)
2419
+ classes.push('hidden', 'md:table-cell');
2420
+ if (column.cellClass)
2421
+ classes.push(column.cellClass);
2422
+ return classes.join(' ');
2423
+ }
2424
+ getHeaderClass(column) {
2425
+ const classes = ['px-2', 'py-2', 'text-left', 'font-medium'];
2426
+ if (column.hideOnMobile)
2427
+ classes.push('hidden', 'md:table-cell');
2428
+ if (column.headerClass)
2429
+ classes.push(column.headerClass);
2430
+ return classes.join(' ');
2431
+ }
2432
+ getColumnStyle(column) {
2433
+ return column.width ? { width: column.width } : {};
1929
2434
  }
1930
2435
  }
1931
2436
  PdmDataTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1932
- PdmDataTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDataTableComponent, selector: "pdm-data-table", inputs: { className: "className", filterPlaceholder: "filterPlaceholder", columnsLabel: "columnsLabel", statusLabel: "statusLabel", emailLabel: "emailLabel", amountLabel: "amountLabel", previousLabel: "previousLabel", nextLabel: "nextLabel", emptyLabel: "emptyLabel", rows: "rows", page: "page", pageSize: "pageSize", query: "query" }, outputs: { queryChange: "queryChange", rowAction: "rowAction", pageChange: "pageChange", selectionChange: "selectionChange" }, ngImport: i0, template: "<section [ngClass]=\"['flex w-full max-w-3xl flex-col items-end', className]\">\n <div class=\"flex w-full items-center justify-between py-4\">\n <input\n type=\"text\"\n [placeholder]=\"filterPlaceholder\"\n [value]=\"query\"\n (input)=\"onQueryInput($event)\"\n class=\"h-9 flex-1 rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n\n <button type=\"button\" class=\"inline-flex h-9 appearance-none items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium text-foreground shadow-sm\">\n <span>{{ columnsLabel }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4 text-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"w-full overflow-hidden rounded-md border border-border bg-background\">\n <table class=\"w-full border-collapse text-sm text-foreground\">\n <thead>\n <tr class=\"border-b border-border\">\n <th class=\"w-10 px-2 text-left font-medium\"><input type=\"checkbox\" class=\"h-4 w-4 rounded-sm border border-input\" /></th>\n <th class=\"w-32 px-2 py-2 text-left font-medium\">{{ statusLabel }}</th>\n <th class=\"px-2 py-2 text-left font-medium\">\n <button type=\"button\" class=\"inline-flex appearance-none items-center gap-1 rounded-sm border-0 bg-transparent px-3 py-2 text-sm\">\n <span>{{ emailLabel }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 6L4 10L8 14M16 18L20 14L16 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </th>\n <th class=\"w-24 px-2 py-2 text-right font-medium\">{{ amountLabel }}</th>\n <th class=\"px-2 py-2\"></th>\n </tr>\n </thead>\n\n <tbody>\n <tr *ngFor=\"let row of pagedRows\" class=\"border-b border-border last:border-b-0\">\n <td class=\"px-2 py-2\"><input type=\"checkbox\" [checked]=\"row.selected\" (change)=\"onToggleRow(row, $event)\" class=\"h-4 w-4 rounded-sm border border-input\" /></td>\n <td class=\"px-2 py-2\">{{ row.status }}</td>\n <td class=\"px-2 py-2\">{{ row.email }}</td>\n <td class=\"px-2 py-2 text-right\">{{ row.amount }}</td>\n <td class=\"px-2 py-2\">\n <button type=\"button\" class=\"inline-flex h-8 w-8 appearance-none items-center justify-center border-0 bg-transparent p-0\" (click)=\"onAction(row)\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"18\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n </svg>\n </button>\n </td>\n </tr>\n <tr *ngIf=\"pagedRows.length === 0\">\n <td colspan=\"5\" class=\"px-3 py-6 text-center text-sm text-muted-foreground\">{{ emptyLabel }}</td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <div class=\"flex w-full items-center gap-2 py-4\">\n <p class=\"m-0 flex-1 pr-2 text-sm text-muted-foreground\">{{ selectedCount }} of {{ rows.length }} row(s) selected.</p>\n <button type=\"button\" class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50\" [disabled]=\"page <= 1\" (click)=\"previous()\">{{ previousLabel }}</button>\n <button type=\"button\" class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50\" [disabled]=\"page >= totalPages\" (click)=\"next()\">{{ nextLabel }}</button>\n </div>\n</section>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2437
+ PdmDataTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDataTableComponent, selector: "pdm-data-table", inputs: { className: "className", columns: "columns", responsiveStrategy: "responsiveStrategy", selectable: "selectable", showActions: "showActions", showFilter: "showFilter", showPagination: "showPagination", showColumnSelector: "showColumnSelector", filterPlaceholder: "filterPlaceholder", columnsLabel: "columnsLabel", previousLabel: "previousLabel", nextLabel: "nextLabel", emptyLabel: "emptyLabel", rowsSelectedLabel: "rowsSelectedLabel", statusLabel: "statusLabel", emailLabel: "emailLabel", amountLabel: "amountLabel", rows: "rows", page: "page", pageSize: "pageSize", query: "query", filterFn: "filterFn" }, outputs: { queryChange: "queryChange", rowAction: "rowAction", pageChange: "pageChange", selectionChange: "selectionChange", columnSort: "columnSort" }, ngImport: i0, template: "<section [ngClass]=\"['flex w-full flex-col', className]\">\n <!-- Toolbar: Filtro + Selector de columnas -->\n <div *ngIf=\"showFilter || showColumnSelector\" class=\"flex w-full items-center justify-between gap-2 py-4\">\n <input\n *ngIf=\"showFilter\"\n type=\"text\"\n [placeholder]=\"filterPlaceholder\"\n [value]=\"query\"\n (input)=\"onQueryInput($event)\"\n class=\"h-9 flex-1 rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n\n <button \n *ngIf=\"showColumnSelector\"\n type=\"button\" \n class=\"inline-flex h-9 appearance-none items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium text-foreground shadow-sm whitespace-nowrap\">\n <span>{{ columnsLabel }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4 text-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <!-- Tabla con responsive -->\n <pdm-table \n variant=\"data\"\n [responsiveStrategy]=\"responsiveStrategy\"\n [fullBleed]=\"false\">\n <thead>\n <tr>\n <!-- Columna de selecci\u00F3n -->\n <th *ngIf=\"selectable\" class=\"w-10 px-2 py-2 text-left font-medium\">\n <input \n type=\"checkbox\" \n (change)=\"onToggleAll($event)\"\n class=\"h-4 w-4 rounded-sm border border-input\" \n />\n </th>\n\n <!-- Columnas din\u00E1micas -->\n <th \n *ngFor=\"let column of effectiveColumns\"\n [ngClass]=\"getHeaderClass(column)\"\n [ngStyle]=\"getColumnStyle(column)\">\n \n <!-- Header sortable -->\n <button \n *ngIf=\"column.sortable\"\n type=\"button\" \n (click)=\"onSort(column)\"\n class=\"inline-flex appearance-none items-center gap-1 rounded-sm border-0 bg-transparent px-3 py-2 text-sm hover:underline\">\n <span>{{ column.label }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 6L4 10L8 14M16 18L20 14L16 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n\n <!-- Header no sortable -->\n <span *ngIf=\"!column.sortable\">{{ column.label }}</span>\n </th>\n\n <!-- Columna de acciones -->\n <th *ngIf=\"showActions\" class=\"w-10 px-2 py-2\"></th>\n </tr>\n </thead>\n\n <tbody>\n <!-- Filas con datos -->\n <tr *ngFor=\"let row of pagedRows\">\n <!-- Celda de selecci\u00F3n -->\n <td *ngIf=\"selectable\" class=\"px-2 py-2\">\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(row)\" \n (change)=\"onToggleRow(row, $event)\" \n class=\"h-4 w-4 rounded-sm border border-input\" \n />\n </td>\n\n <!-- Celdas din\u00E1micas -->\n <td \n *ngFor=\"let column of effectiveColumns\"\n [ngClass]=\"getCellClass(column)\">\n \n <!-- Template personalizado si existe -->\n <ng-container *ngIf=\"column.cellTemplate; else defaultCell\">\n <ng-container \n *ngTemplateOutlet=\"column.cellTemplate; context: { $implicit: row, value: row[column.key] }\">\n </ng-container>\n </ng-container>\n\n <!-- Renderizado default -->\n <ng-template #defaultCell>\n {{ getCellValue(row, column) }}\n </ng-template>\n </td>\n\n <!-- Celda de acciones -->\n <td *ngIf=\"showActions\" class=\"px-2 py-2\">\n <button \n type=\"button\" \n class=\"inline-flex h-8 w-8 appearance-none items-center justify-center border-0 bg-transparent p-0 hover:text-foreground\" \n (click)=\"onAction(row)\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"18\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n </svg>\n </button>\n </td>\n </tr>\n\n <!-- Fila vac\u00EDa -->\n <tr *ngIf=\"pagedRows.length === 0\">\n <td \n [attr.colspan]=\"effectiveColumns.length + (selectable ? 1 : 0) + (showActions ? 1 : 0)\" \n class=\"px-3 py-6 text-center text-sm text-muted-foreground\">\n {{ emptyLabel }}\n </td>\n </tr>\n </tbody>\n </pdm-table>\n\n <!-- Footer: Info + Paginaci\u00F3n -->\n <div *ngIf=\"showPagination || selectable\" class=\"flex w-full items-center gap-2 py-4 flex-wrap sm:flex-nowrap\">\n <p *ngIf=\"selectable\" class=\"m-0 flex-1 pr-2 text-sm text-muted-foreground whitespace-nowrap\">\n {{ selectedCount }} of {{ rows.length }} {{ rowsSelectedLabel }}\n </p>\n\n <div *ngIf=\"showPagination\" class=\"flex items-center gap-2 ml-auto\">\n <span class=\"text-sm text-muted-foreground whitespace-nowrap\">\n Page {{ page }} of {{ totalPages }}\n </span>\n <button \n type=\"button\" \n class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed\" \n [disabled]=\"page <= 1\" \n (click)=\"previous()\">\n {{ previousLabel }}\n </button>\n <button \n type=\"button\" \n class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed\" \n [disabled]=\"page >= totalPages\" \n (click)=\"next()\">\n {{ nextLabel }}\n </button>\n </div>\n </div>\n</section>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: PdmTableComponent, selector: "pdm-table", inputs: ["variant", "responsiveStrategy", "className", "fullBleed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1933
2438
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDataTableComponent, decorators: [{
1934
2439
  type: Component,
1935
- args: [{ selector: 'pdm-data-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<section [ngClass]=\"['flex w-full max-w-3xl flex-col items-end', className]\">\n <div class=\"flex w-full items-center justify-between py-4\">\n <input\n type=\"text\"\n [placeholder]=\"filterPlaceholder\"\n [value]=\"query\"\n (input)=\"onQueryInput($event)\"\n class=\"h-9 flex-1 rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n\n <button type=\"button\" class=\"inline-flex h-9 appearance-none items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium text-foreground shadow-sm\">\n <span>{{ columnsLabel }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4 text-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"w-full overflow-hidden rounded-md border border-border bg-background\">\n <table class=\"w-full border-collapse text-sm text-foreground\">\n <thead>\n <tr class=\"border-b border-border\">\n <th class=\"w-10 px-2 text-left font-medium\"><input type=\"checkbox\" class=\"h-4 w-4 rounded-sm border border-input\" /></th>\n <th class=\"w-32 px-2 py-2 text-left font-medium\">{{ statusLabel }}</th>\n <th class=\"px-2 py-2 text-left font-medium\">\n <button type=\"button\" class=\"inline-flex appearance-none items-center gap-1 rounded-sm border-0 bg-transparent px-3 py-2 text-sm\">\n <span>{{ emailLabel }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 6L4 10L8 14M16 18L20 14L16 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </th>\n <th class=\"w-24 px-2 py-2 text-right font-medium\">{{ amountLabel }}</th>\n <th class=\"px-2 py-2\"></th>\n </tr>\n </thead>\n\n <tbody>\n <tr *ngFor=\"let row of pagedRows\" class=\"border-b border-border last:border-b-0\">\n <td class=\"px-2 py-2\"><input type=\"checkbox\" [checked]=\"row.selected\" (change)=\"onToggleRow(row, $event)\" class=\"h-4 w-4 rounded-sm border border-input\" /></td>\n <td class=\"px-2 py-2\">{{ row.status }}</td>\n <td class=\"px-2 py-2\">{{ row.email }}</td>\n <td class=\"px-2 py-2 text-right\">{{ row.amount }}</td>\n <td class=\"px-2 py-2\">\n <button type=\"button\" class=\"inline-flex h-8 w-8 appearance-none items-center justify-center border-0 bg-transparent p-0\" (click)=\"onAction(row)\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"18\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n </svg>\n </button>\n </td>\n </tr>\n <tr *ngIf=\"pagedRows.length === 0\">\n <td colspan=\"5\" class=\"px-3 py-6 text-center text-sm text-muted-foreground\">{{ emptyLabel }}</td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <div class=\"flex w-full items-center gap-2 py-4\">\n <p class=\"m-0 flex-1 pr-2 text-sm text-muted-foreground\">{{ selectedCount }} of {{ rows.length }} row(s) selected.</p>\n <button type=\"button\" class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50\" [disabled]=\"page <= 1\" (click)=\"previous()\">{{ previousLabel }}</button>\n <button type=\"button\" class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50\" [disabled]=\"page >= totalPages\" (click)=\"next()\">{{ nextLabel }}</button>\n </div>\n</section>\n" }]
2440
+ args: [{ selector: 'pdm-data-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<section [ngClass]=\"['flex w-full flex-col', className]\">\n <!-- Toolbar: Filtro + Selector de columnas -->\n <div *ngIf=\"showFilter || showColumnSelector\" class=\"flex w-full items-center justify-between gap-2 py-4\">\n <input\n *ngIf=\"showFilter\"\n type=\"text\"\n [placeholder]=\"filterPlaceholder\"\n [value]=\"query\"\n (input)=\"onQueryInput($event)\"\n class=\"h-9 flex-1 rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n />\n\n <button \n *ngIf=\"showColumnSelector\"\n type=\"button\" \n class=\"inline-flex h-9 appearance-none items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium text-foreground shadow-sm whitespace-nowrap\">\n <span>{{ columnsLabel }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4 text-foreground\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 10L12 15L17 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <!-- Tabla con responsive -->\n <pdm-table \n variant=\"data\"\n [responsiveStrategy]=\"responsiveStrategy\"\n [fullBleed]=\"false\">\n <thead>\n <tr>\n <!-- Columna de selecci\u00F3n -->\n <th *ngIf=\"selectable\" class=\"w-10 px-2 py-2 text-left font-medium\">\n <input \n type=\"checkbox\" \n (change)=\"onToggleAll($event)\"\n class=\"h-4 w-4 rounded-sm border border-input\" \n />\n </th>\n\n <!-- Columnas din\u00E1micas -->\n <th \n *ngFor=\"let column of effectiveColumns\"\n [ngClass]=\"getHeaderClass(column)\"\n [ngStyle]=\"getColumnStyle(column)\">\n \n <!-- Header sortable -->\n <button \n *ngIf=\"column.sortable\"\n type=\"button\" \n (click)=\"onSort(column)\"\n class=\"inline-flex appearance-none items-center gap-1 rounded-sm border-0 bg-transparent px-3 py-2 text-sm hover:underline\">\n <span>{{ column.label }}</span>\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 6L4 10L8 14M16 18L20 14L16 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path>\n </svg>\n </button>\n\n <!-- Header no sortable -->\n <span *ngIf=\"!column.sortable\">{{ column.label }}</span>\n </th>\n\n <!-- Columna de acciones -->\n <th *ngIf=\"showActions\" class=\"w-10 px-2 py-2\"></th>\n </tr>\n </thead>\n\n <tbody>\n <!-- Filas con datos -->\n <tr *ngFor=\"let row of pagedRows\">\n <!-- Celda de selecci\u00F3n -->\n <td *ngIf=\"selectable\" class=\"px-2 py-2\">\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(row)\" \n (change)=\"onToggleRow(row, $event)\" \n class=\"h-4 w-4 rounded-sm border border-input\" \n />\n </td>\n\n <!-- Celdas din\u00E1micas -->\n <td \n *ngFor=\"let column of effectiveColumns\"\n [ngClass]=\"getCellClass(column)\">\n \n <!-- Template personalizado si existe -->\n <ng-container *ngIf=\"column.cellTemplate; else defaultCell\">\n <ng-container \n *ngTemplateOutlet=\"column.cellTemplate; context: { $implicit: row, value: row[column.key] }\">\n </ng-container>\n </ng-container>\n\n <!-- Renderizado default -->\n <ng-template #defaultCell>\n {{ getCellValue(row, column) }}\n </ng-template>\n </td>\n\n <!-- Celda de acciones -->\n <td *ngIf=\"showActions\" class=\"px-2 py-2\">\n <button \n type=\"button\" \n class=\"inline-flex h-8 w-8 appearance-none items-center justify-center border-0 bg-transparent p-0 hover:text-foreground\" \n (click)=\"onAction(row)\">\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n <circle cx=\"18\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"></circle>\n </svg>\n </button>\n </td>\n </tr>\n\n <!-- Fila vac\u00EDa -->\n <tr *ngIf=\"pagedRows.length === 0\">\n <td \n [attr.colspan]=\"effectiveColumns.length + (selectable ? 1 : 0) + (showActions ? 1 : 0)\" \n class=\"px-3 py-6 text-center text-sm text-muted-foreground\">\n {{ emptyLabel }}\n </td>\n </tr>\n </tbody>\n </pdm-table>\n\n <!-- Footer: Info + Paginaci\u00F3n -->\n <div *ngIf=\"showPagination || selectable\" class=\"flex w-full items-center gap-2 py-4 flex-wrap sm:flex-nowrap\">\n <p *ngIf=\"selectable\" class=\"m-0 flex-1 pr-2 text-sm text-muted-foreground whitespace-nowrap\">\n {{ selectedCount }} of {{ rows.length }} {{ rowsSelectedLabel }}\n </p>\n\n <div *ngIf=\"showPagination\" class=\"flex items-center gap-2 ml-auto\">\n <span class=\"text-sm text-muted-foreground whitespace-nowrap\">\n Page {{ page }} of {{ totalPages }}\n </span>\n <button \n type=\"button\" \n class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed\" \n [disabled]=\"page <= 1\" \n (click)=\"previous()\">\n {{ previousLabel }}\n </button>\n <button \n type=\"button\" \n class=\"h-9 appearance-none rounded-md border border-input bg-background px-4 text-sm font-medium text-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed\" \n [disabled]=\"page >= totalPages\" \n (click)=\"next()\">\n {{ nextLabel }}\n </button>\n </div>\n </div>\n</section>\n" }]
1936
2441
  }], propDecorators: { className: [{
1937
2442
  type: Input
1938
- }], filterPlaceholder: [{
2443
+ }], columns: [{
1939
2444
  type: Input
1940
- }], columnsLabel: [{
2445
+ }], responsiveStrategy: [{
1941
2446
  type: Input
1942
- }], statusLabel: [{
2447
+ }], selectable: [{
1943
2448
  type: Input
1944
- }], emailLabel: [{
2449
+ }], showActions: [{
1945
2450
  type: Input
1946
- }], amountLabel: [{
2451
+ }], showFilter: [{
2452
+ type: Input
2453
+ }], showPagination: [{
2454
+ type: Input
2455
+ }], showColumnSelector: [{
2456
+ type: Input
2457
+ }], filterPlaceholder: [{
2458
+ type: Input
2459
+ }], columnsLabel: [{
1947
2460
  type: Input
1948
2461
  }], previousLabel: [{
1949
2462
  type: Input
@@ -1951,6 +2464,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
1951
2464
  type: Input
1952
2465
  }], emptyLabel: [{
1953
2466
  type: Input
2467
+ }], rowsSelectedLabel: [{
2468
+ type: Input
2469
+ }], statusLabel: [{
2470
+ type: Input
2471
+ }], emailLabel: [{
2472
+ type: Input
2473
+ }], amountLabel: [{
2474
+ type: Input
1954
2475
  }], rows: [{
1955
2476
  type: Input
1956
2477
  }], page: [{
@@ -1959,6 +2480,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
1959
2480
  type: Input
1960
2481
  }], query: [{
1961
2482
  type: Input
2483
+ }], filterFn: [{
2484
+ type: Input
1962
2485
  }], queryChange: [{
1963
2486
  type: Output
1964
2487
  }], rowAction: [{
@@ -1967,6 +2490,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
1967
2490
  type: Output
1968
2491
  }], selectionChange: [{
1969
2492
  type: Output
2493
+ }], columnSort: [{
2494
+ type: Output
1970
2495
  }] } });
1971
2496
 
1972
2497
  /**
@@ -2382,30 +2907,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
2382
2907
  args: ['document:keydown.escape']
2383
2908
  }] } });
2384
2909
 
2385
- class PdmDialogComponent {
2386
- constructor() {
2387
- this.open = false;
2388
- this.variant = 'default';
2389
- this.size = 'desktop';
2390
- this.title = 'Edit profile';
2391
- this.description = '';
2392
- this.closeOnBackdrop = true;
2393
- this.closeOnEsc = true;
2394
- this.showCloseButton = true;
2395
- this.showHeader = true;
2396
- this.showFooter = true;
2397
- this.primaryActionText = 'Save changes';
2398
- this.secondaryActionText = 'Cancel';
2399
- this.alignFooter = 'right';
2400
- this.headerClassName = '';
2401
- this.bodyClassName = '';
2402
- this.footerClassName = '';
2403
- this.className = '';
2404
- this.openChange = new EventEmitter();
2405
- this.primaryAction = new EventEmitter();
2406
- this.secondaryAction = new EventEmitter();
2407
- }
2408
- onEsc() {
2910
+ /**
2911
+ * Z-Index Scale - Sistema centralizado de z-index
2912
+ *
2913
+ * JERARQUÍA (de menor a mayor):
2914
+ * 1. base (z-0) - Elementos normales del DOM
2915
+ * 2. dropdown (z-10) - Selects, combobox, date-pickers
2916
+ * 3. sticky (z-20) - Headers, navigation bars
2917
+ * 4. overlay (z-30) - Popovers, hover cards, context menus
2918
+ * 5. drawer (z-40) - Sidebar drawer, sheets laterales
2919
+ * 6. modal (z-50) - Dialogs, alert-dialogs
2920
+ * 7. modal-backdrop (z-40) - Backdrop de modals
2921
+ * 8. popover (z-60) - Tooltips, dropdowns DENTRO de modals
2922
+ * 9. toast (z-[100]) - Notificaciones que deben estar sobre TODO
2923
+ *
2924
+ * REGLA CRÍTICA:
2925
+ * - Componentes overlay (select options, dropdown menu, tooltip) SIEMPRE z-60 o mayor
2926
+ * - Esto permite que funcionen DENTRO de modals (z-50)
2927
+ * - Backdrop de modal debe ser z-40 para estar DEBAJO del contenido del modal (z-50)
2928
+ */
2929
+ const Z_INDEX = {
2930
+ /**
2931
+ * Base - contenido normal del DOM
2932
+ */
2933
+ base: 'z-0',
2934
+ /**
2935
+ * Dropdown - Selects, combobox, date-pickers
2936
+ * Debe estar SOBRE contenido normal pero BAJO modals
2937
+ */
2938
+ dropdown: 'z-10',
2939
+ /**
2940
+ * Sticky - Headers, navigation fija
2941
+ */
2942
+ sticky: 'z-20',
2943
+ /**
2944
+ * Overlay - Popovers, hover cards, context menus
2945
+ * Debe estar SOBRE sticky pero BAJO modals
2946
+ */
2947
+ overlay: 'z-30',
2948
+ /**
2949
+ * Drawer backdrop - Backdrop de sidebar drawer
2950
+ * Debe estar DEBAJO del drawer panel
2951
+ */
2952
+ drawerBackdrop: 'z-40',
2953
+ /**
2954
+ * Drawer - Sidebar drawer, sheets laterales
2955
+ * Debe estar SOBRE su backdrop pero BAJO modals
2956
+ */
2957
+ drawer: 'z-50',
2958
+ /**
2959
+ * Modal backdrop - Backdrop de dialogs
2960
+ * Debe estar SOBRE drawers pero DEBAJO del contenido del modal
2961
+ */
2962
+ modalBackdrop: 'z-50',
2963
+ /**
2964
+ * Modal - Dialogs, alert-dialogs, sheets
2965
+ * Debe estar SOBRE su backdrop
2966
+ */
2967
+ modal: 'z-[60]',
2968
+ /**
2969
+ * Popover - Tooltips, dropdowns, selects options DENTRO de modals
2970
+ * CRÍTICO: Debe ser MAYOR que modal (z-50) para aparecer sobre modals
2971
+ */
2972
+ popover: 'z-[70]',
2973
+ /**
2974
+ * Toast - Notificaciones globales
2975
+ * Debe estar sobre TODO
2976
+ */
2977
+ toast: 'z-[100]'
2978
+ };
2979
+ /**
2980
+ * Helper para debugging z-index issues
2981
+ */
2982
+ function logZIndexStack(element) {
2983
+ if (typeof window === 'undefined')
2984
+ return;
2985
+ let current = element;
2986
+ const stack = [];
2987
+ while (current && current !== document.body) {
2988
+ const computed = window.getComputedStyle(current);
2989
+ const zIndex = computed.zIndex;
2990
+ const position = computed.position;
2991
+ if (zIndex !== 'auto') {
2992
+ stack.push({
2993
+ element: current.tagName + (current.className ? `.${current.className.split(' ')[0]}` : ''),
2994
+ zIndex,
2995
+ position
2996
+ });
2997
+ }
2998
+ current = current.parentElement;
2999
+ }
3000
+ console.table(stack);
3001
+ }
3002
+
3003
+ /**
3004
+ * Modal/Dialog component con soporte responsive
3005
+ *
3006
+ * MEJORADO en v0.2.0:
3007
+ * - Modo 'responsive' (default): fullscreen en mobile, modal en desktop
3008
+ * - Tamaños predefinidos: sm, md, lg, xl
3009
+ * - Mejor manejo de scroll en mobile
3010
+ *
3011
+ * @example
3012
+ * // Responsive (recomendado)
3013
+ * <pdm-dialog [open]="isOpen" size="responsive">
3014
+ * <p>Content</p>
3015
+ * </pdm-dialog>
3016
+ *
3017
+ * @example
3018
+ * // Tamaño fijo
3019
+ * <pdm-dialog [open]="isOpen" size="lg">
3020
+ * <p>Content</p>
3021
+ * </pdm-dialog>
3022
+ */
3023
+ class PdmDialogComponent {
3024
+ constructor() {
3025
+ this.open = false;
3026
+ this.variant = 'default';
3027
+ /**
3028
+ * Tamaño del dialog
3029
+ * - responsive: fullscreen mobile, modal desktop (recomendado)
3030
+ * - sm: 400px max
3031
+ * - md: 500px max
3032
+ * - lg: 640px max (default)
3033
+ * - xl: 800px max
3034
+ * - desktop/mobile/mobile-fullscreen: legacy, deprecado
3035
+ */
3036
+ this.size = 'responsive';
3037
+ this.title = 'Edit profile';
3038
+ this.description = '';
3039
+ this.closeOnBackdrop = true;
3040
+ this.closeOnEsc = true;
3041
+ this.showCloseButton = true;
3042
+ this.showHeader = true;
3043
+ this.showFooter = true;
3044
+ this.primaryActionText = 'Save changes';
3045
+ this.secondaryActionText = 'Cancel';
3046
+ this.alignFooter = 'right';
3047
+ this.headerClassName = '';
3048
+ this.bodyClassName = '';
3049
+ this.footerClassName = '';
3050
+ this.className = '';
3051
+ this.openChange = new EventEmitter();
3052
+ this.primaryAction = new EventEmitter();
3053
+ this.secondaryAction = new EventEmitter();
3054
+ }
3055
+ onEsc() {
2409
3056
  if (this.open && this.closeOnEsc) {
2410
3057
  this.close();
2411
3058
  }
@@ -2425,47 +3072,132 @@ class PdmDialogComponent {
2425
3072
  }
2426
3073
  }
2427
3074
  get panelClassName() {
3075
+ // Legacy sizes (backward compatibility)
3076
+ if (this.size === 'desktop') {
3077
+ return this.buildClasses(['max-w-[640px]', 'max-h-[calc(100vh-2rem)]', 'rounded-[10px]']);
3078
+ }
3079
+ if (this.size === 'mobile') {
3080
+ return this.buildClasses(['max-w-[320px]', 'min-h-[240px]', 'rounded-[10px]']);
3081
+ }
3082
+ if (this.size === 'mobile-fullscreen') {
3083
+ return this.buildClasses(['max-w-[320px]', 'h-[min(100dvh,640px)]', 'rounded-none', 'sm:rounded-[10px]']);
3084
+ }
3085
+ // New responsive mode (recomendado)
3086
+ if (this.size === 'responsive') {
3087
+ return this.buildClasses([
3088
+ // Mobile: fullscreen con bordes redondeados solo arriba
3089
+ 'w-full',
3090
+ 'h-full',
3091
+ 'max-h-[100dvh]',
3092
+ 'rounded-t-[10px]',
3093
+ 'sm:rounded-[10px]',
3094
+ // Desktop: modal centrado
3095
+ 'sm:w-auto',
3096
+ 'sm:h-auto',
3097
+ 'sm:max-w-[640px]',
3098
+ 'sm:max-h-[calc(100vh-4rem)]'
3099
+ ]);
3100
+ }
3101
+ // New size options
3102
+ const sizeMap = {
3103
+ sm: 'sm:max-w-[400px]',
3104
+ md: 'sm:max-w-[500px]',
3105
+ lg: 'sm:max-w-[640px]',
3106
+ xl: 'sm:max-w-[800px]'
3107
+ };
3108
+ const maxWidth = sizeMap[this.size] || sizeMap.lg;
3109
+ return this.buildClasses([
3110
+ // Mobile: fullscreen
3111
+ 'w-full',
3112
+ 'h-full',
3113
+ 'max-h-[100dvh]',
3114
+ 'rounded-t-[10px]',
3115
+ // Desktop: modal
3116
+ 'sm:rounded-[10px]',
3117
+ 'sm:w-auto',
3118
+ 'sm:h-auto',
3119
+ maxWidth,
3120
+ 'sm:max-h-[calc(100vh-4rem)]'
3121
+ ]);
3122
+ }
3123
+ buildClasses(sizeClasses) {
2428
3124
  const base = [
2429
- 'relative z-10 w-full border border-border bg-background text-foreground shadow-lg',
2430
- this.size === 'desktop' ? 'max-w-[640px] max-h-[calc(100vh-2rem)] rounded-[10px] overflow-visible' : '',
2431
- this.size === 'mobile' ? 'max-w-[320px] min-h-[240px] rounded-[10px] overflow-visible' : '',
2432
- this.size === 'mobile-fullscreen'
2433
- ? 'max-w-[320px] h-[min(100dvh,640px)] rounded-none sm:rounded-[10px] overflow-visible'
2434
- : '',
3125
+ 'relative',
3126
+ Z_INDEX.modal,
3127
+ 'flex',
3128
+ 'flex-col',
3129
+ 'border',
3130
+ 'border-border',
3131
+ 'bg-background',
3132
+ 'text-foreground',
3133
+ 'shadow-lg',
3134
+ 'overflow-hidden',
3135
+ ...sizeClasses,
2435
3136
  this.className
2436
3137
  ];
2437
3138
  return base.filter(Boolean).join(' ');
2438
3139
  }
2439
3140
  get bodyWrapperClassName() {
2440
3141
  const base = [
2441
- 'min-h-0 flex-1',
2442
- this.size === 'mobile-fullscreen' ? 'overflow-y-auto px-4 py-6' : 'px-6 py-6',
3142
+ 'flex-1',
3143
+ 'overflow-y-auto',
3144
+ 'px-4',
3145
+ 'py-6',
3146
+ 'sm:px-6',
2443
3147
  this.bodyClassName
2444
3148
  ];
2445
3149
  return base.filter(Boolean).join(' ');
2446
3150
  }
2447
3151
  get headerWrapperClassName() {
2448
- return ['flex items-start justify-between gap-3 p-4', this.headerClassName].filter(Boolean).join(' ');
3152
+ const base = [
3153
+ 'flex',
3154
+ 'items-start',
3155
+ 'justify-between',
3156
+ 'gap-3',
3157
+ 'p-4',
3158
+ 'sm:p-6',
3159
+ 'border-b',
3160
+ 'border-border',
3161
+ this.headerClassName
3162
+ ];
3163
+ return base.filter(Boolean).join(' ');
2449
3164
  }
2450
3165
  get footerWrapperClassName() {
2451
3166
  const effectiveAlign = this.alignFooter === 'right' && this.variant === 'custom-close' ? 'left' : this.alignFooter;
2452
3167
  const base = [
2453
3168
  'p-4',
3169
+ 'sm:p-6',
3170
+ 'border-t',
3171
+ 'border-border',
3172
+ // Mobile: siempre full-width
3173
+ 'flex',
3174
+ 'flex-col',
3175
+ 'gap-2',
3176
+ // Desktop: según alignFooter
2454
3177
  effectiveAlign === 'full-width'
2455
- ? 'flex flex-col gap-2'
2456
- : effectiveAlign === 'left'
2457
- ? 'flex items-center gap-2 justify-start'
2458
- : 'flex items-center gap-2 justify-end',
3178
+ ? 'sm:flex-col'
3179
+ : 'sm:flex-row sm:items-center',
3180
+ effectiveAlign === 'left' ? 'sm:justify-start' : '',
3181
+ effectiveAlign === 'right' ? 'sm:justify-end' : '',
2459
3182
  this.footerClassName
2460
3183
  ];
2461
3184
  return base.filter(Boolean).join(' ');
2462
3185
  }
3186
+ get containerClassName() {
3187
+ // Container con backdrop z-50
3188
+ // Mobile: fullscreen desde el bottom
3189
+ // Desktop: centrado
3190
+ return responsive({
3191
+ default: `fixed inset-x-0 bottom-0 ${Z_INDEX.modalBackdrop} flex items-end justify-center`,
3192
+ sm: `fixed inset-0 ${Z_INDEX.modalBackdrop} flex items-center justify-center p-4`
3193
+ });
3194
+ }
2463
3195
  }
2464
3196
  PdmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2465
- PdmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDialogComponent, selector: "pdm-dialog", inputs: { open: "open", variant: "variant", size: "size", title: "title", description: "description", closeOnBackdrop: "closeOnBackdrop", closeOnEsc: "closeOnEsc", showCloseButton: "showCloseButton", showHeader: "showHeader", showFooter: "showFooter", primaryActionText: "primaryActionText", secondaryActionText: "secondaryActionText", alignFooter: "alignFooter", headerClassName: "headerClassName", bodyClassName: "bodyClassName", footerClassName: "footerClassName", className: "className" }, outputs: { openChange: "openChange", primaryAction: "primaryAction", secondaryAction: "secondaryAction" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onBackdropClick()\"></div>\n <section role=\"dialog\" aria-modal=\"true\" [ngClass]=\"panelClassName\">\n <div *ngIf=\"showHeader\" [ngClass]=\"headerWrapperClassName\">\n <div class=\"min-w-0\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 mt-2 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <button\n *ngIf=\"showCloseButton\"\n type=\"button\"\n class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-sm border-0 bg-transparent p-0 text-foreground opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\"\n (click)=\"close()\"\n aria-label=\"Close dialog\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 6L18 18M18 6L6 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <div [ngClass]=\"bodyWrapperClassName\">\n <ng-content></ng-content>\n </div>\n\n <div *ngIf=\"showFooter\" [ngClass]=\"footerWrapperClassName\">\n <ng-container *ngIf=\"variant === 'custom-close'; else defaultActions\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n </ng-container>\n\n <ng-template #defaultActions>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onPrimaryAction()\"\n >\n {{ primaryActionText }}\n </button>\n </ng-template>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3197
+ PdmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDialogComponent, selector: "pdm-dialog", inputs: { open: "open", variant: "variant", size: "size", title: "title", description: "description", closeOnBackdrop: "closeOnBackdrop", closeOnEsc: "closeOnEsc", showCloseButton: "showCloseButton", showHeader: "showHeader", showFooter: "showFooter", primaryActionText: "primaryActionText", secondaryActionText: "secondaryActionText", alignFooter: "alignFooter", headerClassName: "headerClassName", bodyClassName: "bodyClassName", footerClassName: "footerClassName", className: "className" }, outputs: { openChange: "openChange", primaryAction: "primaryAction", secondaryAction: "secondaryAction" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div *ngIf=\"open\" [ngClass]=\"containerClassName\">\n <!-- Backdrop -->\n <div class=\"absolute inset-0 bg-foreground/30 backdrop-blur-sm\" (click)=\"onBackdropClick()\"></div>\n \n <!-- Dialog Panel -->\n <section role=\"dialog\" aria-modal=\"true\" [ngClass]=\"panelClassName\">\n <!-- Header -->\n <div *ngIf=\"showHeader\" [ngClass]=\"headerWrapperClassName\">\n <div class=\"min-w-0 flex-1\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 mt-2 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <button\n *ngIf=\"showCloseButton\"\n type=\"button\"\n class=\"inline-flex h-6 w-6 flex-shrink-0 appearance-none items-center justify-center rounded-sm border-0 bg-transparent p-0 text-foreground opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\"\n (click)=\"close()\"\n aria-label=\"Close dialog\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 6L18 18M18 6L6 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <!-- Body -->\n <div [ngClass]=\"bodyWrapperClassName\">\n <ng-content></ng-content>\n </div>\n\n <!-- Footer -->\n <div *ngIf=\"showFooter\" [ngClass]=\"footerWrapperClassName\">\n <ng-container *ngIf=\"variant === 'custom-close'; else defaultActions\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-full appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm sm:w-auto\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n </ng-container>\n\n <ng-template #defaultActions>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-full appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm sm:w-auto\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-full appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm sm:w-auto\"\n (click)=\"onPrimaryAction()\"\n >\n {{ primaryActionText }}\n </button>\n </ng-template>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2466
3198
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDialogComponent, decorators: [{
2467
3199
  type: Component,
2468
- args: [{ selector: 'pdm-dialog', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onBackdropClick()\"></div>\n <section role=\"dialog\" aria-modal=\"true\" [ngClass]=\"panelClassName\">\n <div *ngIf=\"showHeader\" [ngClass]=\"headerWrapperClassName\">\n <div class=\"min-w-0\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 mt-2 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <button\n *ngIf=\"showCloseButton\"\n type=\"button\"\n class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-sm border-0 bg-transparent p-0 text-foreground opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\"\n (click)=\"close()\"\n aria-label=\"Close dialog\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 6L18 18M18 6L6 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <div [ngClass]=\"bodyWrapperClassName\">\n <ng-content></ng-content>\n </div>\n\n <div *ngIf=\"showFooter\" [ngClass]=\"footerWrapperClassName\">\n <ng-container *ngIf=\"variant === 'custom-close'; else defaultActions\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n </ng-container>\n\n <ng-template #defaultActions>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm\"\n (click)=\"onPrimaryAction()\"\n >\n {{ primaryActionText }}\n </button>\n </ng-template>\n </div>\n </section>\n</div>\n" }]
3200
+ args: [{ selector: 'pdm-dialog', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"open\" [ngClass]=\"containerClassName\">\n <!-- Backdrop -->\n <div class=\"absolute inset-0 bg-foreground/30 backdrop-blur-sm\" (click)=\"onBackdropClick()\"></div>\n \n <!-- Dialog Panel -->\n <section role=\"dialog\" aria-modal=\"true\" [ngClass]=\"panelClassName\">\n <!-- Header -->\n <div *ngIf=\"showHeader\" [ngClass]=\"headerWrapperClassName\">\n <div class=\"min-w-0 flex-1\">\n <h2 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ title }}</h2>\n <p *ngIf=\"description\" class=\"m-0 mt-2 text-sm text-muted-foreground\">{{ description }}</p>\n </div>\n <button\n *ngIf=\"showCloseButton\"\n type=\"button\"\n class=\"inline-flex h-6 w-6 flex-shrink-0 appearance-none items-center justify-center rounded-sm border-0 bg-transparent p-0 text-foreground opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\"\n (click)=\"close()\"\n aria-label=\"Close dialog\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 6L18 18M18 6L6 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <!-- Body -->\n <div [ngClass]=\"bodyWrapperClassName\">\n <ng-content></ng-content>\n </div>\n\n <!-- Footer -->\n <div *ngIf=\"showFooter\" [ngClass]=\"footerWrapperClassName\">\n <ng-container *ngIf=\"variant === 'custom-close'; else defaultActions\">\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-full appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm sm:w-auto\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n </ng-container>\n\n <ng-template #defaultActions>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-full appearance-none items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm sm:w-auto\"\n (click)=\"onSecondaryAction()\"\n >\n {{ secondaryActionText }}\n </button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-full appearance-none items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm sm:w-auto\"\n (click)=\"onPrimaryAction()\"\n >\n {{ primaryActionText }}\n </button>\n </ng-template>\n </div>\n </section>\n</div>\n" }]
2469
3201
  }], propDecorators: { open: [{
2470
3202
  type: Input
2471
3203
  }], variant: [{
@@ -2511,6 +3243,304 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
2511
3243
  args: ['document:keydown.escape']
2512
3244
  }] } });
2513
3245
 
3246
+ /**
3247
+ * Tabla con funcionalidad de reordenamiento de filas mediante drag & drop
3248
+ *
3249
+ * Extiende pdm-table agregando la capacidad de reordenar filas.
3250
+ * Si no necesitás drag & drop, usá pdm-table directamente (más simple y liviano).
3251
+ *
3252
+ * @example
3253
+ * <pdm-draggable-table
3254
+ * variant="interactive"
3255
+ * [reorderRows]="true"
3256
+ * (rowOrderChange)="onOrderChange($event)">
3257
+ * <tbody>
3258
+ * <tr data-row-id="1"><td>Row 1</td></tr>
3259
+ * <tr data-row-id="2"><td>Row 2</td></tr>
3260
+ * </tbody>
3261
+ * </pdm-draggable-table>
3262
+ *
3263
+ * IMPORTANTE: Cada <tr> debe tener un atributo data-row-id único
3264
+ */
3265
+ class PdmDraggableTableComponent {
3266
+ constructor(renderer) {
3267
+ this.renderer = renderer;
3268
+ this.variant = 'default';
3269
+ this.responsiveStrategy = 'scroll';
3270
+ this.className = '';
3271
+ this.fullBleed = false;
3272
+ /**
3273
+ * Habilita el reordenamiento de filas mediante drag & drop
3274
+ */
3275
+ this.reorderRows = false;
3276
+ /**
3277
+ * Selector CSS para identificar los handles de drag
3278
+ * Por defecto busca: [data-drag-handle], [data-slot=row-drag-handle], .row-drag-handle
3279
+ * Si no encuentra ninguno, inserta un handle automático
3280
+ */
3281
+ this.dragHandleSelector = '[data-drag-handle],[data-slot=row-drag-handle],.row-drag-handle,[data-auto-drag-handle]';
3282
+ /**
3283
+ * Emite el nuevo orden de las filas cuando el usuario termina de arrastrar
3284
+ * Array de data-row-id en el nuevo orden
3285
+ */
3286
+ this.rowOrderChange = new EventEmitter();
3287
+ this.cleanupListeners = [];
3288
+ this.draggedRow = null;
3289
+ }
3290
+ ngAfterViewInit() {
3291
+ this.syncReorderBehavior();
3292
+ }
3293
+ // Getters para clases CSS (mismo comportamiento que pdm-table)
3294
+ get wrapperClasses() {
3295
+ const baseClasses = ['relative', 'w-full'];
3296
+ const strategyClasses = this.getResponsiveStrategyClasses();
3297
+ const variantClasses = this.getVariantWrapperClasses();
3298
+ if (this.fullBleed && this.responsiveStrategy === 'scroll') {
3299
+ baseClasses.push('-mx-4', 'px-4', 'sm:mx-0', 'sm:px-0');
3300
+ }
3301
+ return [
3302
+ ...baseClasses,
3303
+ ...strategyClasses,
3304
+ ...variantClasses,
3305
+ this.className
3306
+ ].filter(Boolean);
3307
+ }
3308
+ get tableClasses() {
3309
+ const baseClasses = ['w-full', 'caption-bottom', 'text-sm'];
3310
+ const variantClasses = this.getVariantTableClasses();
3311
+ const cellClasses = this.getCellClasses();
3312
+ return [...baseClasses, ...variantClasses, ...cellClasses].filter(Boolean);
3313
+ }
3314
+ getResponsiveStrategyClasses() {
3315
+ if (this.responsiveStrategy === 'scroll' || this.responsiveStrategy === 'wrap' || this.responsiveStrategy === 'collapse') {
3316
+ return ['overflow-x-auto'];
3317
+ }
3318
+ return [];
3319
+ }
3320
+ getVariantWrapperClasses() {
3321
+ if (this.variant === 'interactive') {
3322
+ return ['rounded-xl', 'border', 'border-border', 'bg-background'];
3323
+ }
3324
+ if (this.variant === 'data') {
3325
+ return ['rounded-md', 'border', 'border-border', 'bg-background'];
3326
+ }
3327
+ return [];
3328
+ }
3329
+ getVariantTableClasses() {
3330
+ if (this.variant === 'data') {
3331
+ return [
3332
+ 'border-collapse', 'text-foreground',
3333
+ '[&_thead_tr]:border-b', '[&_thead_tr]:border-border',
3334
+ '[&_tbody_tr]:border-b', '[&_tbody_tr]:border-border',
3335
+ '[&_tbody_tr:last-child]:border-b-0',
3336
+ '[&_th]:h-10', '[&_th]:px-2', '[&_th]:text-left', '[&_th]:align-middle', '[&_th]:font-medium',
3337
+ '[&_td]:p-2', '[&_td]:align-middle'
3338
+ ];
3339
+ }
3340
+ if (this.variant === 'interactive') {
3341
+ return [
3342
+ 'text-foreground',
3343
+ '[&_thead]:sticky', '[&_thead]:top-0', '[&_thead]:z-10', '[&_thead]:bg-muted/70',
3344
+ '[&_thead_tr]:border-b', '[&_thead_tr]:border-border',
3345
+ '[&_th]:h-12', '[&_th]:px-4', '[&_th]:text-left', '[&_th]:align-middle', '[&_th]:text-sm', '[&_th]:font-medium',
3346
+ '[&_tbody_tr]:border-b', '[&_tbody_tr]:border-border',
3347
+ '[&_tbody_tr]:transition-colors', '[&_tbody_tr:hover]:bg-muted/50',
3348
+ '[&_tbody_tr:last-child]:border-b-0',
3349
+ '[&_td]:h-14', '[&_td]:px-4', '[&_td]:align-middle', '[&_td]:text-sm',
3350
+ '[&_svg]:text-muted-foreground'
3351
+ ];
3352
+ }
3353
+ return [];
3354
+ }
3355
+ getCellClasses() {
3356
+ if (this.responsiveStrategy === 'scroll') {
3357
+ return ['[&_td]:whitespace-normal', '[&_th]:whitespace-normal', 'sm:[&_td]:whitespace-nowrap', 'sm:[&_th]:whitespace-nowrap'];
3358
+ }
3359
+ if (this.responsiveStrategy === 'wrap') {
3360
+ return ['[&_td]:whitespace-normal', '[&_td]:break-words', '[&_th]:whitespace-normal'];
3361
+ }
3362
+ return [];
3363
+ }
3364
+ ngOnChanges(changes) {
3365
+ if (changes['reorderRows'] || changes['variant']) {
3366
+ this.syncReorderBehavior();
3367
+ }
3368
+ }
3369
+ ngOnDestroy() {
3370
+ this.cleanupReorderBehavior();
3371
+ }
3372
+ syncReorderBehavior() {
3373
+ this.cleanupReorderBehavior();
3374
+ if (!this.reorderRows) {
3375
+ return;
3376
+ }
3377
+ const tbody = this.getTbody();
3378
+ if (!tbody) {
3379
+ return;
3380
+ }
3381
+ this.setRowsDraggable(tbody, true);
3382
+ this.cleanupListeners.push(this.renderer.listen(tbody, 'mousedown', (event) => this.armDragFromHandle(event)), this.renderer.listen(tbody, 'dragstart', (event) => this.onDragStart(event)), this.renderer.listen(tbody, 'dragover', (event) => this.onDragOver(event, tbody)), this.renderer.listen(tbody, 'drop', (event) => this.onDrop(event)), this.renderer.listen(tbody, 'dragend', () => this.onDragEnd()));
3383
+ // Observer para detectar cambios en el DOM (filas agregadas/removidas)
3384
+ this.observer = new MutationObserver(() => this.setRowsDraggable(tbody, true));
3385
+ this.observer.observe(tbody, { childList: true });
3386
+ }
3387
+ cleanupReorderBehavior() {
3388
+ this.cleanupListeners.forEach((dispose) => dispose());
3389
+ this.cleanupListeners = [];
3390
+ if (this.observer) {
3391
+ this.observer.disconnect();
3392
+ this.observer = undefined;
3393
+ }
3394
+ const tbody = this.getTbody();
3395
+ if (tbody) {
3396
+ this.setRowsDraggable(tbody, false);
3397
+ }
3398
+ this.draggedRow = null;
3399
+ }
3400
+ getTbody() {
3401
+ var _a, _b;
3402
+ return (_b = (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.nativeElement.tBodies.item(0)) !== null && _b !== void 0 ? _b : null;
3403
+ }
3404
+ setRowsDraggable(tbody, enabled) {
3405
+ const rows = Array.from(tbody.rows);
3406
+ rows.forEach((row) => {
3407
+ this.syncAutoDragHandle(row, enabled);
3408
+ row.draggable = false;
3409
+ if (!enabled) {
3410
+ delete row.dataset['dragging'];
3411
+ delete row.dataset['dragArmed'];
3412
+ }
3413
+ });
3414
+ }
3415
+ /**
3416
+ * Inserta un handle de drag automático si no existe uno custom
3417
+ */
3418
+ syncAutoDragHandle(row, enabled) {
3419
+ const firstCell = row.cells.item(0);
3420
+ if (!firstCell) {
3421
+ return;
3422
+ }
3423
+ const existingAutoHandle = firstCell.querySelector('[data-auto-drag-handle]');
3424
+ if (!enabled) {
3425
+ existingAutoHandle === null || existingAutoHandle === void 0 ? void 0 : existingAutoHandle.remove();
3426
+ return;
3427
+ }
3428
+ const hasCustomHandle = !!firstCell.querySelector('[data-drag-handle],[data-slot=row-drag-handle],.row-drag-handle');
3429
+ if (hasCustomHandle || existingAutoHandle) {
3430
+ return;
3431
+ }
3432
+ // Crear handle automático
3433
+ const button = this.renderer.createElement('button');
3434
+ this.renderer.setAttribute(button, 'type', 'button');
3435
+ this.renderer.setAttribute(button, 'aria-label', 'Drag row');
3436
+ this.renderer.setAttribute(button, 'data-auto-drag-handle', 'true');
3437
+ this.renderer.addClass(button, 'inline-flex');
3438
+ this.renderer.addClass(button, 'h-7');
3439
+ this.renderer.addClass(button, 'w-7');
3440
+ this.renderer.addClass(button, 'items-center');
3441
+ this.renderer.addClass(button, 'justify-center');
3442
+ this.renderer.addClass(button, 'cursor-grab');
3443
+ this.renderer.addClass(button, 'active:cursor-grabbing');
3444
+ this.renderer.addClass(button, 'text-muted-foreground');
3445
+ const dots = this.renderer.createElement('span');
3446
+ this.renderer.addClass(dots, 'text-sm');
3447
+ this.renderer.addClass(dots, 'leading-none');
3448
+ this.renderer.setProperty(dots, 'textContent', '⋮⋮');
3449
+ this.renderer.appendChild(button, dots);
3450
+ this.renderer.insertBefore(firstCell, button, firstCell.firstChild);
3451
+ }
3452
+ onDragStart(event) {
3453
+ const target = event.target;
3454
+ const row = target === null || target === void 0 ? void 0 : target.closest('tr');
3455
+ if (!row) {
3456
+ return;
3457
+ }
3458
+ const handle = target === null || target === void 0 ? void 0 : target.closest(this.dragHandleSelector);
3459
+ const isArmed = row.dataset['dragArmed'] === 'true';
3460
+ if ((!handle || !row.contains(handle)) && !isArmed) {
3461
+ event.preventDefault();
3462
+ return;
3463
+ }
3464
+ this.draggedRow = row;
3465
+ this.draggedRow.dataset['dragging'] = 'true';
3466
+ if (event.dataTransfer) {
3467
+ event.dataTransfer.effectAllowed = 'move';
3468
+ event.dataTransfer.setData('text/plain', '');
3469
+ }
3470
+ }
3471
+ onDragOver(event, tbody) {
3472
+ if (!this.draggedRow) {
3473
+ return;
3474
+ }
3475
+ event.preventDefault();
3476
+ const target = event.target;
3477
+ const targetRow = target === null || target === void 0 ? void 0 : target.closest('tr');
3478
+ if (!targetRow || targetRow === this.draggedRow) {
3479
+ return;
3480
+ }
3481
+ const rect = targetRow.getBoundingClientRect();
3482
+ const shouldInsertBefore = event.clientY < rect.top + rect.height / 2;
3483
+ tbody.insertBefore(this.draggedRow, shouldInsertBefore ? targetRow : targetRow.nextSibling);
3484
+ }
3485
+ onDrop(event) {
3486
+ event.preventDefault();
3487
+ }
3488
+ onDragEnd() {
3489
+ const tbody = this.getTbody();
3490
+ if (tbody) {
3491
+ Array.from(tbody.rows).forEach((row) => {
3492
+ row.draggable = false;
3493
+ delete row.dataset['dragArmed'];
3494
+ });
3495
+ }
3496
+ if (this.draggedRow) {
3497
+ delete this.draggedRow.dataset['dragging'];
3498
+ this.draggedRow = null;
3499
+ }
3500
+ if (!tbody) {
3501
+ return;
3502
+ }
3503
+ const order = Array.from(tbody.rows).map((row, index) => row.getAttribute('data-row-id') || String(index));
3504
+ this.rowOrderChange.emit(order);
3505
+ }
3506
+ armDragFromHandle(event) {
3507
+ const target = event.target;
3508
+ const handle = target === null || target === void 0 ? void 0 : target.closest(this.dragHandleSelector);
3509
+ if (!handle) {
3510
+ return;
3511
+ }
3512
+ const row = handle.closest('tr');
3513
+ if (!row) {
3514
+ return;
3515
+ }
3516
+ row.draggable = true;
3517
+ row.dataset['dragArmed'] = 'true';
3518
+ }
3519
+ }
3520
+ PdmDraggableTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDraggableTableComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
3521
+ PdmDraggableTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDraggableTableComponent, selector: "pdm-draggable-table", inputs: { variant: "variant", responsiveStrategy: "responsiveStrategy", className: "className", fullBleed: "fullBleed", reorderRows: "reorderRows", dragHandleSelector: "dragHandleSelector" }, outputs: { rowOrderChange: "rowOrderChange" }, viewQueries: [{ propertyName: "tableElement", first: true, predicate: ["tableElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div [ngClass]=\"wrapperClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table-container' : null\">\n <table #tableElement [ngClass]=\"tableClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table' : null\">\n <ng-content></ng-content>\n </table>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3522
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDraggableTableComponent, decorators: [{
3523
+ type: Component,
3524
+ args: [{ selector: 'pdm-draggable-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"wrapperClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table-container' : null\">\n <table #tableElement [ngClass]=\"tableClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table' : null\">\n <ng-content></ng-content>\n </table>\n</div>\n" }]
3525
+ }], ctorParameters: function () { return [{ type: i0.Renderer2 }]; }, propDecorators: { variant: [{
3526
+ type: Input
3527
+ }], responsiveStrategy: [{
3528
+ type: Input
3529
+ }], className: [{
3530
+ type: Input
3531
+ }], fullBleed: [{
3532
+ type: Input
3533
+ }], reorderRows: [{
3534
+ type: Input
3535
+ }], dragHandleSelector: [{
3536
+ type: Input
3537
+ }], rowOrderChange: [{
3538
+ type: Output
3539
+ }], tableElement: [{
3540
+ type: ViewChild,
3541
+ args: ['tableElement']
3542
+ }] } });
3543
+
2514
3544
  class PdmDropdownMenuComponent {
2515
3545
  constructor(elementRef, cdr, overlay, viewContainerRef) {
2516
3546
  this.elementRef = elementRef;
@@ -2624,7 +3654,7 @@ class PdmDropdownMenuComponent {
2624
3654
  this.cdr.markForCheck();
2625
3655
  const positionStrategy = createFlexiblePositionStrategy(this.overlay, triggerEl, 8);
2626
3656
  // Resolve panelClass: overlayOptions.panelClass wins; otherwise map panelClassName.
2627
- const resolvedPanelClass = (_c = (_b = this.overlayOptions) === null || _b === void 0 ? void 0 : _b.panelClass) !== null && _c !== void 0 ? _c : (this.panelClassName ? ['block', this.panelClassName] : ['block']);
3657
+ const resolvedPanelClass = (_c = (_b = this.overlayOptions) === null || _b === void 0 ? void 0 : _b.panelClass) !== null && _c !== void 0 ? _c : (this.panelClassName ? [Z_INDEX.popover, this.panelClassName] : [Z_INDEX.popover]);
2628
3658
  this.overlayRef = this.overlay.create(Object.assign(Object.assign({ positionStrategy, scrollStrategy: this.overlay.scrollStrategies.reposition() }, this.overlayOptions), {
2629
3659
  // panelClass always overrides last: it already merges panelClassName + overlayOptions.
2630
3660
  panelClass: resolvedPanelClass }));
@@ -2690,13 +3720,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
2690
3720
  args: ['document:keydown.escape']
2691
3721
  }] } });
2692
3722
 
3723
+ /**
3724
+ * Drawer/Sheet component con soporte responsive
3725
+ *
3726
+ * MEJORADO en v0.2.0:
3727
+ * - Posicionamiento configurable (bottom, left, right, top)
3728
+ * - Tamaños predefinidos
3729
+ * - Responsive: bottom sheet en mobile, side panel en desktop
3730
+ * - Contenido genérico via ng-content
3731
+ *
3732
+ * @example
3733
+ * // Drawer simple desde el bottom
3734
+ * <pdm-drawer [open]="isOpen" position="bottom">
3735
+ * <h3>Title</h3>
3736
+ * <p>Content</p>
3737
+ * </pdm-drawer>
3738
+ *
3739
+ * @example
3740
+ * // Side panel desde la right
3741
+ * <pdm-drawer [open]="isOpen" position="right" size="md">
3742
+ * <p>Content</p>
3743
+ * </pdm-drawer>
3744
+ */
2693
3745
  class PdmDrawerComponent {
2694
3746
  constructor() {
2695
3747
  this.open = false;
3748
+ /**
3749
+ * Posición del drawer
3750
+ * - bottom: desde abajo (default, mejor para mobile)
3751
+ * - left: side panel desde izquierda
3752
+ * - right: side panel desde derecha
3753
+ * - top: desde arriba (poco común)
3754
+ */
3755
+ this.position = 'bottom';
3756
+ /**
3757
+ * Tamaño del drawer
3758
+ * - sm: 400px (side) / 50vh (bottom/top)
3759
+ * - md: 500px (side) / 66vh (bottom/top) (default)
3760
+ * - lg: 640px (side) / 80vh (bottom/top)
3761
+ * - full: 100% ancho/alto
3762
+ */
3763
+ this.size = 'md';
3764
+ /**
3765
+ * @deprecated Use position="bottom" instead
3766
+ */
2696
3767
  this.variant = 'drawer';
2697
3768
  this.className = '';
2698
3769
  this.title = '';
2699
3770
  this.description = '';
3771
+ /**
3772
+ * Mostrar handle visual (línea para arrastrar)
3773
+ * Solo tiene sentido en position="bottom"
3774
+ */
3775
+ this.showHandle = true;
3776
+ /**
3777
+ * Mostrar botón de cerrar
3778
+ */
3779
+ this.showCloseButton = true;
3780
+ this.closeOnEsc = true;
3781
+ this.closeOnBackdropClick = true;
3782
+ this.openChange = new EventEmitter();
3783
+ // DEPRECATED: contenido específico que se movió a ng-content
2700
3784
  this.value = '';
2701
3785
  this.unit = '';
2702
3786
  this.decrementLabel = '-';
@@ -2710,14 +3794,9 @@ class PdmDrawerComponent {
2710
3794
  this.usernameLabel = 'Username';
2711
3795
  this.usernameValue = '';
2712
3796
  this.responsivePrimaryLabel = '';
2713
- /** Close when the ESC key is pressed. Default: `true`. */
2714
- this.closeOnEsc = true;
2715
- /** Close when the backdrop is clicked. Default: `true`. */
2716
- this.closeOnBackdropClick = true;
2717
- this.openChange = new EventEmitter();
3797
+ this.bars = [];
2718
3798
  this.primaryAction = new EventEmitter();
2719
3799
  this.secondaryAction = new EventEmitter();
2720
- this.bars = [];
2721
3800
  }
2722
3801
  onEsc() {
2723
3802
  if (this.open && this.closeOnEsc) {
@@ -2738,14 +3817,67 @@ class PdmDrawerComponent {
2738
3817
  onSecondaryAction() {
2739
3818
  this.secondaryAction.emit();
2740
3819
  }
3820
+ get containerClassName() {
3821
+ return `fixed inset-0 ${Z_INDEX.drawer} ${this.className}`;
3822
+ }
3823
+ get panelClassName() {
3824
+ const base = [
3825
+ 'absolute',
3826
+ 'bg-background',
3827
+ 'border',
3828
+ 'border-border',
3829
+ 'shadow-lg',
3830
+ 'overflow-auto'
3831
+ ];
3832
+ // Posicionamiento
3833
+ const positionClasses = this.getPositionClasses();
3834
+ // Tamaño
3835
+ const sizeClasses = this.getSizeClasses();
3836
+ return [...base, ...positionClasses, ...sizeClasses].filter(Boolean).join(' ');
3837
+ }
3838
+ getPositionClasses() {
3839
+ const map = {
3840
+ bottom: ['inset-x-0', 'bottom-0', 'rounded-t-xl'],
3841
+ top: ['inset-x-0', 'top-0', 'rounded-b-xl'],
3842
+ left: ['inset-y-0', 'left-0', 'rounded-r-xl'],
3843
+ right: ['inset-y-0', 'right-0', 'rounded-l-xl']
3844
+ };
3845
+ return map[this.position] || map.bottom;
3846
+ }
3847
+ getSizeClasses() {
3848
+ const isVertical = this.position === 'bottom' || this.position === 'top';
3849
+ if (this.size === 'full') {
3850
+ return ['w-full', 'h-full'];
3851
+ }
3852
+ const sizeMap = {
3853
+ sm: isVertical ? 'max-h-[50vh]' : 'max-w-[400px]',
3854
+ md: isVertical ? 'max-h-[66vh]' : 'max-w-[500px]',
3855
+ lg: isVertical ? 'max-h-[80vh]' : 'max-w-[640px]'
3856
+ };
3857
+ const maxDimension = sizeMap[this.size] || sizeMap.md;
3858
+ if (isVertical) {
3859
+ return ['w-full', maxDimension];
3860
+ }
3861
+ else {
3862
+ return ['h-full', maxDimension];
3863
+ }
3864
+ }
3865
+ get showLegacyContent() {
3866
+ // Mostrar contenido legacy si variant está siendo usado
3867
+ return this.variant === 'drawer' || this.variant === 'responsive-dialog';
3868
+ }
2741
3869
  }
2742
3870
  PdmDrawerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2743
- PdmDrawerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDrawerComponent, selector: "pdm-drawer", inputs: { open: "open", variant: "variant", className: "className", title: "title", description: "description", value: "value", unit: "unit", decrementLabel: "decrementLabel", incrementLabel: "incrementLabel", primaryLabel: "primaryLabel", secondaryLabel: "secondaryLabel", profileTitle: "profileTitle", profileDescription: "profileDescription", nameLabel: "nameLabel", nameValue: "nameValue", usernameLabel: "usernameLabel", usernameValue: "usernameValue", responsivePrimaryLabel: "responsivePrimaryLabel", closeOnEsc: "closeOnEsc", closeOnBackdropClick: "closeOnBackdropClick", bars: "bars" }, outputs: { openChange: "openChange", primaryAction: "primaryAction", secondaryAction: "secondaryAction" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50\" [ngClass]=\"className\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onBackdropClick()\"></div>\n\n <section\n *ngIf=\"variant === 'drawer'; else responsiveDialog\"\n class=\"absolute inset-x-0 bottom-0 mx-auto w-full max-w-6xl rounded-t-lg border border-border bg-background p-6 shadow-lg\"\n >\n <div class=\"mx-auto mb-4 h-1 w-10 rounded-full bg-border\"></div>\n\n <div class=\"mx-auto flex max-w-sm flex-col items-center\">\n <h3 class=\"m-0 text-sm font-semibold text-foreground\">{{ title }}</h3>\n <p class=\"m-0 mt-1 text-xs text-muted-foreground\">{{ description }}</p>\n\n <div class=\"mt-3 flex w-full items-center justify-center gap-4\">\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ decrementLabel }}</button>\n <div class=\"text-center\">\n <div class=\"text-5xl font-semibold leading-none text-foreground\">{{ value }}</div>\n <div class=\"mt-1 text-xs tracking-wide text-muted-foreground\">{{ unit }}</div>\n </div>\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ incrementLabel }}</button>\n </div>\n\n <div *ngIf=\"bars.length\" class=\"mt-3 flex h-14 w-full items-end gap-1\">\n <div *ngFor=\"let bar of bars\" class=\"flex-1 bg-foreground\" [style.height.px]=\"bar\"></div>\n </div>\n\n <button *ngIf=\"primaryLabel\" type=\"button\" class=\"mt-3 h-9 w-full appearance-none rounded-md bg-primary text-sm font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ primaryLabel }}</button>\n <button *ngIf=\"secondaryLabel\" type=\"button\" class=\"mt-2 h-9 w-full appearance-none rounded-md border border-input bg-background text-sm font-medium text-foreground\" (click)=\"onSecondaryAction()\">{{ secondaryLabel }}</button>\n </div>\n </section>\n\n <ng-template #responsiveDialog>\n <section class=\"absolute left-1/2 top-1/2 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-background p-6 shadow-lg\">\n <div class=\"flex items-start justify-between\">\n <div>\n <h3 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ profileTitle }}</h3>\n <p class=\"m-0 mt-1 text-sm text-muted-foreground\">{{ profileDescription }}</p>\n </div>\n <button type=\"button\" class=\"h-5 w-5 appearance-none border-0 bg-transparent p-0 text-muted-foreground\" (click)=\"close()\">\u00D7</button>\n </div>\n\n <div class=\"mt-3 flex flex-col gap-3\">\n <div>\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ nameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ nameValue }}</div>\n </div>\n <div>\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ usernameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ usernameValue }}</div>\n </div>\n </div>\n\n <button *ngIf=\"responsivePrimaryLabel\" type=\"button\" class=\"mt-3 h-8 w-full appearance-none rounded-md bg-primary text-xs font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ responsivePrimaryLabel }}</button>\n </section>\n </ng-template>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3871
+ PdmDrawerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmDrawerComponent, selector: "pdm-drawer", inputs: { open: "open", position: "position", size: "size", variant: "variant", className: "className", title: "title", description: "description", showHandle: "showHandle", showCloseButton: "showCloseButton", closeOnEsc: "closeOnEsc", closeOnBackdropClick: "closeOnBackdropClick", value: "value", unit: "unit", decrementLabel: "decrementLabel", incrementLabel: "incrementLabel", primaryLabel: "primaryLabel", secondaryLabel: "secondaryLabel", profileTitle: "profileTitle", profileDescription: "profileDescription", nameLabel: "nameLabel", nameValue: "nameValue", usernameLabel: "usernameLabel", usernameValue: "usernameValue", responsivePrimaryLabel: "responsivePrimaryLabel", bars: "bars" }, outputs: { openChange: "openChange", primaryAction: "primaryAction", secondaryAction: "secondaryAction" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div *ngIf=\"open\" [ngClass]=\"containerClassName\">\n <!-- Backdrop -->\n <div class=\"absolute inset-0 bg-foreground/30 backdrop-blur-sm\" (click)=\"onBackdropClick()\"></div>\n\n <!-- Panel -->\n <section [ngClass]=\"panelClassName\">\n <!-- Handle visual (solo para bottom) -->\n <div \n *ngIf=\"showHandle && position === 'bottom'\" \n class=\"mx-auto mb-4 mt-2 h-1 w-10 rounded-full bg-border\">\n </div>\n\n <!-- Header (opcional) -->\n <div *ngIf=\"title || description || showCloseButton\" class=\"flex items-start justify-between gap-4 p-6 pb-4\">\n <div *ngIf=\"title || description\" class=\"flex-1 min-w-0\">\n <h3 *ngIf=\"title\" class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">\n {{ title }}\n </h3>\n <p *ngIf=\"description\" class=\"m-0 mt-1 text-sm text-muted-foreground\">\n {{ description }}\n </p>\n </div>\n \n <button\n *ngIf=\"showCloseButton\"\n type=\"button\"\n class=\"inline-flex h-6 w-6 flex-shrink-0 appearance-none items-center justify-center rounded-sm border-0 bg-transparent p-0 text-foreground opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\"\n (click)=\"close()\"\n aria-label=\"Close drawer\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 6L18 18M18 6L6 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"px-6 pb-6\">\n <!-- Contenido gen\u00E9rico -->\n <ng-container *ngIf=\"!showLegacyContent\">\n <ng-content></ng-content>\n </ng-container>\n\n <!-- LEGACY: contenido espec\u00EDfico hardcodeado (backward compatibility) -->\n <ng-container *ngIf=\"showLegacyContent\">\n <!-- Variant: drawer -->\n <div *ngIf=\"variant === 'drawer'\" class=\"mx-auto flex max-w-sm flex-col items-center\">\n <div *ngIf=\"value !== ''\" class=\"mt-3 flex w-full items-center justify-center gap-4\">\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ decrementLabel }}</button>\n <div class=\"text-center\">\n <div class=\"text-5xl font-semibold leading-none text-foreground\">{{ value }}</div>\n <div *ngIf=\"unit\" class=\"mt-1 text-xs tracking-wide text-muted-foreground\">{{ unit }}</div>\n </div>\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ incrementLabel }}</button>\n </div>\n\n <div *ngIf=\"bars.length\" class=\"mt-3 flex h-14 w-full items-end gap-1\">\n <div *ngFor=\"let bar of bars\" class=\"flex-1 bg-foreground\" [style.height.px]=\"bar\"></div>\n </div>\n\n <button *ngIf=\"primaryLabel\" type=\"button\" class=\"mt-3 h-9 w-full appearance-none rounded-md bg-primary text-sm font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ primaryLabel }}</button>\n <button *ngIf=\"secondaryLabel\" type=\"button\" class=\"mt-2 h-9 w-full appearance-none rounded-md border border-input bg-background text-sm font-medium text-foreground\" (click)=\"onSecondaryAction()\">{{ secondaryLabel }}</button>\n </div>\n\n <!-- Variant: responsive-dialog -->\n <div *ngIf=\"variant === 'responsive-dialog'\" class=\"flex flex-col gap-3\">\n <div *ngIf=\"nameLabel && nameValue\">\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ nameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ nameValue }}</div>\n </div>\n <div *ngIf=\"usernameLabel && usernameValue\">\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ usernameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ usernameValue }}</div>\n </div>\n\n <button *ngIf=\"responsivePrimaryLabel\" type=\"button\" class=\"mt-3 h-8 w-full appearance-none rounded-md bg-primary text-xs font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ responsivePrimaryLabel }}</button>\n </div>\n </ng-container>\n </div>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2744
3872
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmDrawerComponent, decorators: [{
2745
3873
  type: Component,
2746
- args: [{ selector: 'pdm-drawer', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50\" [ngClass]=\"className\">\n <div class=\"absolute inset-0 bg-foreground/30\" (click)=\"onBackdropClick()\"></div>\n\n <section\n *ngIf=\"variant === 'drawer'; else responsiveDialog\"\n class=\"absolute inset-x-0 bottom-0 mx-auto w-full max-w-6xl rounded-t-lg border border-border bg-background p-6 shadow-lg\"\n >\n <div class=\"mx-auto mb-4 h-1 w-10 rounded-full bg-border\"></div>\n\n <div class=\"mx-auto flex max-w-sm flex-col items-center\">\n <h3 class=\"m-0 text-sm font-semibold text-foreground\">{{ title }}</h3>\n <p class=\"m-0 mt-1 text-xs text-muted-foreground\">{{ description }}</p>\n\n <div class=\"mt-3 flex w-full items-center justify-center gap-4\">\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ decrementLabel }}</button>\n <div class=\"text-center\">\n <div class=\"text-5xl font-semibold leading-none text-foreground\">{{ value }}</div>\n <div class=\"mt-1 text-xs tracking-wide text-muted-foreground\">{{ unit }}</div>\n </div>\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ incrementLabel }}</button>\n </div>\n\n <div *ngIf=\"bars.length\" class=\"mt-3 flex h-14 w-full items-end gap-1\">\n <div *ngFor=\"let bar of bars\" class=\"flex-1 bg-foreground\" [style.height.px]=\"bar\"></div>\n </div>\n\n <button *ngIf=\"primaryLabel\" type=\"button\" class=\"mt-3 h-9 w-full appearance-none rounded-md bg-primary text-sm font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ primaryLabel }}</button>\n <button *ngIf=\"secondaryLabel\" type=\"button\" class=\"mt-2 h-9 w-full appearance-none rounded-md border border-input bg-background text-sm font-medium text-foreground\" (click)=\"onSecondaryAction()\">{{ secondaryLabel }}</button>\n </div>\n </section>\n\n <ng-template #responsiveDialog>\n <section class=\"absolute left-1/2 top-1/2 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-background p-6 shadow-lg\">\n <div class=\"flex items-start justify-between\">\n <div>\n <h3 class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">{{ profileTitle }}</h3>\n <p class=\"m-0 mt-1 text-sm text-muted-foreground\">{{ profileDescription }}</p>\n </div>\n <button type=\"button\" class=\"h-5 w-5 appearance-none border-0 bg-transparent p-0 text-muted-foreground\" (click)=\"close()\">\u00D7</button>\n </div>\n\n <div class=\"mt-3 flex flex-col gap-3\">\n <div>\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ nameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ nameValue }}</div>\n </div>\n <div>\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ usernameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ usernameValue }}</div>\n </div>\n </div>\n\n <button *ngIf=\"responsivePrimaryLabel\" type=\"button\" class=\"mt-3 h-8 w-full appearance-none rounded-md bg-primary text-xs font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ responsivePrimaryLabel }}</button>\n </section>\n </ng-template>\n</div>\n" }]
3874
+ args: [{ selector: 'pdm-drawer', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"open\" [ngClass]=\"containerClassName\">\n <!-- Backdrop -->\n <div class=\"absolute inset-0 bg-foreground/30 backdrop-blur-sm\" (click)=\"onBackdropClick()\"></div>\n\n <!-- Panel -->\n <section [ngClass]=\"panelClassName\">\n <!-- Handle visual (solo para bottom) -->\n <div \n *ngIf=\"showHandle && position === 'bottom'\" \n class=\"mx-auto mb-4 mt-2 h-1 w-10 rounded-full bg-border\">\n </div>\n\n <!-- Header (opcional) -->\n <div *ngIf=\"title || description || showCloseButton\" class=\"flex items-start justify-between gap-4 p-6 pb-4\">\n <div *ngIf=\"title || description\" class=\"flex-1 min-w-0\">\n <h3 *ngIf=\"title\" class=\"m-0 text-lg font-semibold leading-none tracking-tight text-foreground\">\n {{ title }}\n </h3>\n <p *ngIf=\"description\" class=\"m-0 mt-1 text-sm text-muted-foreground\">\n {{ description }}\n </p>\n </div>\n \n <button\n *ngIf=\"showCloseButton\"\n type=\"button\"\n class=\"inline-flex h-6 w-6 flex-shrink-0 appearance-none items-center justify-center rounded-sm border-0 bg-transparent p-0 text-foreground opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\"\n (click)=\"close()\"\n aria-label=\"Close drawer\"\n >\n <svg viewBox=\"0 0 24 24\" class=\"h-4 w-4\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 6L18 18M18 6L6 18\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"></path>\n </svg>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"px-6 pb-6\">\n <!-- Contenido gen\u00E9rico -->\n <ng-container *ngIf=\"!showLegacyContent\">\n <ng-content></ng-content>\n </ng-container>\n\n <!-- LEGACY: contenido espec\u00EDfico hardcodeado (backward compatibility) -->\n <ng-container *ngIf=\"showLegacyContent\">\n <!-- Variant: drawer -->\n <div *ngIf=\"variant === 'drawer'\" class=\"mx-auto flex max-w-sm flex-col items-center\">\n <div *ngIf=\"value !== ''\" class=\"mt-3 flex w-full items-center justify-center gap-4\">\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ decrementLabel }}</button>\n <div class=\"text-center\">\n <div class=\"text-5xl font-semibold leading-none text-foreground\">{{ value }}</div>\n <div *ngIf=\"unit\" class=\"mt-1 text-xs tracking-wide text-muted-foreground\">{{ unit }}</div>\n </div>\n <button type=\"button\" class=\"inline-flex h-6 w-6 appearance-none items-center justify-center rounded-full border border-border bg-transparent p-0 text-muted-foreground\">{{ incrementLabel }}</button>\n </div>\n\n <div *ngIf=\"bars.length\" class=\"mt-3 flex h-14 w-full items-end gap-1\">\n <div *ngFor=\"let bar of bars\" class=\"flex-1 bg-foreground\" [style.height.px]=\"bar\"></div>\n </div>\n\n <button *ngIf=\"primaryLabel\" type=\"button\" class=\"mt-3 h-9 w-full appearance-none rounded-md bg-primary text-sm font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ primaryLabel }}</button>\n <button *ngIf=\"secondaryLabel\" type=\"button\" class=\"mt-2 h-9 w-full appearance-none rounded-md border border-input bg-background text-sm font-medium text-foreground\" (click)=\"onSecondaryAction()\">{{ secondaryLabel }}</button>\n </div>\n\n <!-- Variant: responsive-dialog -->\n <div *ngIf=\"variant === 'responsive-dialog'\" class=\"flex flex-col gap-3\">\n <div *ngIf=\"nameLabel && nameValue\">\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ nameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ nameValue }}</div>\n </div>\n <div *ngIf=\"usernameLabel && usernameValue\">\n <label class=\"mb-1 block text-xs font-medium text-foreground\">{{ usernameLabel }}</label>\n <div class=\"h-8 rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground\">{{ usernameValue }}</div>\n </div>\n\n <button *ngIf=\"responsivePrimaryLabel\" type=\"button\" class=\"mt-3 h-8 w-full appearance-none rounded-md bg-primary text-xs font-medium text-primary-foreground\" (click)=\"onPrimaryAction()\">{{ responsivePrimaryLabel }}</button>\n </div>\n </ng-container>\n </div>\n </section>\n</div>\n" }]
2747
3875
  }], propDecorators: { open: [{
2748
3876
  type: Input
3877
+ }], position: [{
3878
+ type: Input
3879
+ }], size: [{
3880
+ type: Input
2749
3881
  }], variant: [{
2750
3882
  type: Input
2751
3883
  }], className: [{
@@ -2754,6 +3886,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
2754
3886
  type: Input
2755
3887
  }], description: [{
2756
3888
  type: Input
3889
+ }], showHandle: [{
3890
+ type: Input
3891
+ }], showCloseButton: [{
3892
+ type: Input
3893
+ }], closeOnEsc: [{
3894
+ type: Input
3895
+ }], closeOnBackdropClick: [{
3896
+ type: Input
3897
+ }], openChange: [{
3898
+ type: Output
2757
3899
  }], value: [{
2758
3900
  type: Input
2759
3901
  }], unit: [{
@@ -2778,20 +3920,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
2778
3920
  type: Input
2779
3921
  }], usernameValue: [{
2780
3922
  type: Input
2781
- }], responsivePrimaryLabel: [{
2782
- type: Input
2783
- }], closeOnEsc: [{
3923
+ }], responsivePrimaryLabel: [{
2784
3924
  type: Input
2785
- }], closeOnBackdropClick: [{
3925
+ }], bars: [{
2786
3926
  type: Input
2787
- }], openChange: [{
2788
- type: Output
2789
3927
  }], primaryAction: [{
2790
3928
  type: Output
2791
3929
  }], secondaryAction: [{
2792
3930
  type: Output
2793
- }], bars: [{
2794
- type: Input
2795
3931
  }], onEsc: [{
2796
3932
  type: HostListener,
2797
3933
  args: ['document:keydown.escape']
@@ -2936,10 +4072,10 @@ class PdmHoverCardComponent {
2936
4072
  }
2937
4073
  }
2938
4074
  PdmHoverCardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmHoverCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2939
- PdmHoverCardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmHoverCardComponent, selector: "pdm-hover-card", inputs: { className: "className", panelClassName: "panelClassName", side: "side", align: "align", panelWidth: "panelWidth" }, ngImport: i0, template: "<div\n class=\"relative inline-flex\"\n [ngClass]=\"className\"\n (mouseenter)=\"open = true\"\n (mouseleave)=\"open = false\"\n (focusin)=\"open = true\"\n (focusout)=\"open = false\"\n>\n <div>\n <ng-content select=\"[pdmHoverTrigger]\"></ng-content>\n </div>\n\n <section\n *ngIf=\"open\"\n [style.width.px]=\"panelWidth\"\n [ngClass]=\"[\n 'absolute z-30 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md',\n positionClass,\n panelClassName\n ]\"\n >\n <ng-content select=\"[pdmHoverContent]\"></ng-content>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4075
+ PdmHoverCardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmHoverCardComponent, selector: "pdm-hover-card", inputs: { className: "className", panelClassName: "panelClassName", side: "side", align: "align", panelWidth: "panelWidth" }, ngImport: i0, template: "<div\n class=\"relative inline-flex\"\n [ngClass]=\"className\"\n (mouseenter)=\"open = true\"\n (mouseleave)=\"open = false\"\n (focusin)=\"open = true\"\n (focusout)=\"open = false\"\n>\n <div>\n <ng-content select=\"[pdmHoverTrigger]\"></ng-content>\n </div>\n\n <section\n *ngIf=\"open\"\n [style.width.px]=\"panelWidth\"\n [ngClass]=\"[\n 'absolute z-[70] rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md',\n positionClass,\n panelClassName\n ]\"\n >\n <ng-content select=\"[pdmHoverContent]\"></ng-content>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2940
4076
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmHoverCardComponent, decorators: [{
2941
4077
  type: Component,
2942
- args: [{ selector: 'pdm-hover-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"relative inline-flex\"\n [ngClass]=\"className\"\n (mouseenter)=\"open = true\"\n (mouseleave)=\"open = false\"\n (focusin)=\"open = true\"\n (focusout)=\"open = false\"\n>\n <div>\n <ng-content select=\"[pdmHoverTrigger]\"></ng-content>\n </div>\n\n <section\n *ngIf=\"open\"\n [style.width.px]=\"panelWidth\"\n [ngClass]=\"[\n 'absolute z-30 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md',\n positionClass,\n panelClassName\n ]\"\n >\n <ng-content select=\"[pdmHoverContent]\"></ng-content>\n </section>\n</div>\n" }]
4078
+ args: [{ selector: 'pdm-hover-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"relative inline-flex\"\n [ngClass]=\"className\"\n (mouseenter)=\"open = true\"\n (mouseleave)=\"open = false\"\n (focusin)=\"open = true\"\n (focusout)=\"open = false\"\n>\n <div>\n <ng-content select=\"[pdmHoverTrigger]\"></ng-content>\n </div>\n\n <section\n *ngIf=\"open\"\n [style.width.px]=\"panelWidth\"\n [ngClass]=\"[\n 'absolute z-[70] rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md',\n positionClass,\n panelClassName\n ]\"\n >\n <ng-content select=\"[pdmHoverContent]\"></ng-content>\n </section>\n</div>\n" }]
2943
4079
  }], propDecorators: { className: [{
2944
4080
  type: Input
2945
4081
  }], panelClassName: [{
@@ -3377,10 +4513,10 @@ class PdmMenubarComponent {
3377
4513
  }
3378
4514
  }
3379
4515
  PdmMenubarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmMenubarComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3380
- PdmMenubarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmMenubarComponent, selector: "pdm-menubar", inputs: { menus: "menus", className: "className" }, outputs: { itemSelect: "itemSelect" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<nav role=\"menubar\" [ngClass]=\"['inline-flex h-9 items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm', className]\">\n <div *ngFor=\"let menu of menus; let i = index\" class=\"relative\">\n <button type=\"button\" class=\"inline-flex h-7 appearance-none items-center rounded-sm border-0 bg-transparent px-3 text-sm text-foreground hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\" (click)=\"toggle(i)\">{{ menu.label }}</button>\n <div *ngIf=\"openIndex === i\" class=\"absolute left-0 top-full z-50 mt-1 min-w-48 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\">\n <button\n *ngFor=\"let item of menu.items\"\n type=\"button\"\n [disabled]=\"item.disabled || !item.value\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n (click)=\"selectItem(item)\"\n >\n {{ item.label }}\n </button>\n </div>\n </div>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4516
+ PdmMenubarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmMenubarComponent, selector: "pdm-menubar", inputs: { menus: "menus", className: "className" }, outputs: { itemSelect: "itemSelect" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<nav role=\"menubar\" [ngClass]=\"['inline-flex h-9 items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm', className]\">\n <div *ngFor=\"let menu of menus; let i = index\" class=\"relative\">\n <button type=\"button\" class=\"inline-flex h-7 appearance-none items-center rounded-sm border-0 bg-transparent px-3 text-sm text-foreground hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\" (click)=\"toggle(i)\">{{ menu.label }}</button>\n <div *ngIf=\"openIndex === i\" class=\"absolute left-0 top-full z-[70] mt-1 min-w-40 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md sm:min-w-48\">\n <button\n *ngFor=\"let item of menu.items\"\n type=\"button\"\n [disabled]=\"item.disabled || !item.value\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n (click)=\"selectItem(item)\"\n >\n {{ item.label }}\n </button>\n </div>\n </div>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3381
4517
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmMenubarComponent, decorators: [{
3382
4518
  type: Component,
3383
- args: [{ selector: 'pdm-menubar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav role=\"menubar\" [ngClass]=\"['inline-flex h-9 items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm', className]\">\n <div *ngFor=\"let menu of menus; let i = index\" class=\"relative\">\n <button type=\"button\" class=\"inline-flex h-7 appearance-none items-center rounded-sm border-0 bg-transparent px-3 text-sm text-foreground hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\" (click)=\"toggle(i)\">{{ menu.label }}</button>\n <div *ngIf=\"openIndex === i\" class=\"absolute left-0 top-full z-50 mt-1 min-w-48 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\">\n <button\n *ngFor=\"let item of menu.items\"\n type=\"button\"\n [disabled]=\"item.disabled || !item.value\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n (click)=\"selectItem(item)\"\n >\n {{ item.label }}\n </button>\n </div>\n </div>\n</nav>\n" }]
4519
+ args: [{ selector: 'pdm-menubar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav role=\"menubar\" [ngClass]=\"['inline-flex h-9 items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm', className]\">\n <div *ngFor=\"let menu of menus; let i = index\" class=\"relative\">\n <button type=\"button\" class=\"inline-flex h-7 appearance-none items-center rounded-sm border-0 bg-transparent px-3 text-sm text-foreground hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\" (click)=\"toggle(i)\">{{ menu.label }}</button>\n <div *ngIf=\"openIndex === i\" class=\"absolute left-0 top-full z-[70] mt-1 min-w-40 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md sm:min-w-48\">\n <button\n *ngFor=\"let item of menu.items\"\n type=\"button\"\n [disabled]=\"item.disabled || !item.value\"\n class=\"relative flex w-full appearance-none cursor-default select-none items-center rounded-sm border-0 bg-transparent px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n (click)=\"selectItem(item)\"\n >\n {{ item.label }}\n </button>\n </div>\n </div>\n</nav>\n" }]
3384
4520
  }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { menus: [{
3385
4521
  type: Input
3386
4522
  }], className: [{
@@ -3430,21 +4566,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
3430
4566
  type: Output
3431
4567
  }] } });
3432
4568
 
4569
+ /**
4570
+ * Navigation Menu component - Navegación horizontal responsive
4571
+ *
4572
+ * MEJORAS en v0.2.0:
4573
+ * - Modo scroll: overflow-x-auto con scroll indicators en mobile
4574
+ * - Modo compact: items abreviados en mobile, completos en desktop
4575
+ * - Scroll smooth automático al item activo
4576
+ *
4577
+ * @example
4578
+ * <!-- Scroll horizontal (default) -->
4579
+ * <pdm-navigation-menu [items]="navItems"></pdm-navigation-menu>
4580
+ *
4581
+ * <!-- Compact mode -->
4582
+ * <pdm-navigation-menu [items]="navItems" mobileMode="compact"></pdm-navigation-menu>
4583
+ */
3433
4584
  class PdmNavigationMenuComponent {
3434
4585
  constructor() {
3435
4586
  this.items = [];
3436
4587
  this.className = '';
4588
+ /**
4589
+ * Mobile behavior: 'scroll' (horizontal scroll) o 'compact' (items reducidos)
4590
+ * @default 'scroll'
4591
+ */
4592
+ this.mobileMode = 'scroll';
3437
4593
  }
3438
4594
  }
3439
4595
  PdmNavigationMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmNavigationMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3440
- PdmNavigationMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmNavigationMenuComponent, selector: "pdm-navigation-menu", inputs: { items: "items", className: "className" }, ngImport: i0, template: "<nav [ngClass]=\"['relative z-10 flex max-w-max flex-1 items-center justify-center', className]\">\n <ul class=\"group flex flex-1 list-none items-center justify-center space-x-1\">\n <li *ngFor=\"let item of items\">\n <a\n [href]=\"item.href || '#'\"\n [ngClass]=\"[\n 'group inline-flex h-9 w-max items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n item.active ? 'bg-accent text-accent-foreground' : 'text-foreground'\n ]\"\n >\n {{ item.label }}\n </a>\n </li>\n </ul>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4596
+ PdmNavigationMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmNavigationMenuComponent, selector: "pdm-navigation-menu", inputs: { items: "items", className: "className", mobileMode: "mobileMode" }, ngImport: i0, template: "<nav\n [ngClass]=\"[\n 'relative z-10 flex w-full items-center',\n mobileMode === 'scroll' ? 'overflow-x-auto scrollbar-thin' : '',\n className\n ]\"\n>\n <ul\n [ngClass]=\"[\n 'group flex list-none items-center gap-1',\n mobileMode === 'scroll' ? 'flex-nowrap' : 'flex-wrap justify-center'\n ]\"\n >\n <li *ngFor=\"let item of items\">\n <a\n [href]=\"item.href || '#'\"\n [ngClass]=\"[\n 'group inline-flex h-9 items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 whitespace-nowrap',\n item.active ? 'bg-accent text-accent-foreground' : 'text-foreground'\n ]\"\n >\n {{ item.label }}\n </a>\n </li>\n </ul>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3441
4597
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmNavigationMenuComponent, decorators: [{
3442
4598
  type: Component,
3443
- args: [{ selector: 'pdm-navigation-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [ngClass]=\"['relative z-10 flex max-w-max flex-1 items-center justify-center', className]\">\n <ul class=\"group flex flex-1 list-none items-center justify-center space-x-1\">\n <li *ngFor=\"let item of items\">\n <a\n [href]=\"item.href || '#'\"\n [ngClass]=\"[\n 'group inline-flex h-9 w-max items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n item.active ? 'bg-accent text-accent-foreground' : 'text-foreground'\n ]\"\n >\n {{ item.label }}\n </a>\n </li>\n </ul>\n</nav>\n" }]
4599
+ args: [{ selector: 'pdm-navigation-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav\n [ngClass]=\"[\n 'relative z-10 flex w-full items-center',\n mobileMode === 'scroll' ? 'overflow-x-auto scrollbar-thin' : '',\n className\n ]\"\n>\n <ul\n [ngClass]=\"[\n 'group flex list-none items-center gap-1',\n mobileMode === 'scroll' ? 'flex-nowrap' : 'flex-wrap justify-center'\n ]\"\n >\n <li *ngFor=\"let item of items\">\n <a\n [href]=\"item.href || '#'\"\n [ngClass]=\"[\n 'group inline-flex h-9 items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 whitespace-nowrap',\n item.active ? 'bg-accent text-accent-foreground' : 'text-foreground'\n ]\"\n >\n {{ item.label }}\n </a>\n </li>\n </ul>\n</nav>\n" }]
3444
4600
  }], propDecorators: { items: [{
3445
4601
  type: Input
3446
4602
  }], className: [{
3447
4603
  type: Input
4604
+ }], mobileMode: [{
4605
+ type: Input
3448
4606
  }] } });
3449
4607
 
3450
4608
  /**
@@ -3667,8 +4825,9 @@ class PdmSelectComponent {
3667
4825
  this.cdr.markForCheck();
3668
4826
  const positionStrategy = createFlexiblePositionStrategy(this.overlay, triggerEl, 4);
3669
4827
  this.overlayRef = this.overlay.create(Object.assign({
3670
- // Fix: use a token array DOMTokenList.add() rejects space-containing strings.
3671
- panelClass: ['block'], positionStrategy, scrollStrategy: this.overlay.scrollStrategies.reposition(), width: triggerEl.offsetWidth }, this.overlayOptions));
4828
+ // CRÍTICO: z-[70] para aparecer SOBRE modals (z-[60])
4829
+ // panelClass se aplica al cdk-overlay-pane wrapper
4830
+ panelClass: [Z_INDEX.popover], positionStrategy, scrollStrategy: this.overlay.scrollStrategies.reposition(), width: triggerEl.offsetWidth }, this.overlayOptions));
3672
4831
  const portal = new TemplatePortal(this.panelTemplateRef, this.viewContainerRef);
3673
4832
  this.overlayRef.attach(portal);
3674
4833
  this.backdropSub = this.overlayRef.outsidePointerEvents().subscribe((event) => {
@@ -3777,10 +4936,10 @@ class PdmPaginationComponent {
3777
4936
  }
3778
4937
  }
3779
4938
  PdmPaginationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3780
- PdmPaginationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmPaginationComponent, selector: "pdm-pagination", inputs: { page: "page", pageCount: "pageCount", maxVisible: "maxVisible", className: "className", rowsPerPageLabel: "rowsPerPageLabel", rowsPerPage: "rowsPerPage", rowsPerPageOptions: "rowsPerPageOptions" }, outputs: { pageChange: "pageChange", rowsPerPageChange: "rowsPerPageChange" }, ngImport: i0, template: "<nav\n aria-label=\"Pagination\"\n [ngClass]=\"[\n 'mx-auto flex w-full flex-wrap items-center justify-center gap-4',\n className,\n ]\"\n>\n <div class=\"flex items-center gap-3\" *ngIf=\"rowsPerPageOptions.length > 0\">\n <span class=\"text-sm font-medium text-foreground\">{{\n rowsPerPageLabel\n }}</span>\n <pdm-select\n [value]=\"rowsPerPageValue\"\n [options]=\"rowsPerPageSelectOptions\"\n [placeholder]=\"rowsPerPageValue\"\n className=\"w-[120px]\"\n (valueChange)=\"onRowsPerPageChangeValue($event)\"\n ></pdm-select>\n </div>\n\n <ul class=\"m-0 flex list-none items-center gap-1 p-0\">\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page <= 1\"\n (click)=\"setPage(page - 1)\"\n >\n <pdm-icon name=\"chevron-left\" [size]=\"14\"></pdm-icon>\n Previous\n </button>\n </li>\n <li *ngFor=\"let pageNumber of visiblePages\">\n <ng-container *ngIf=\"pageNumber === 'ellipsis'; else pageButton\">\n <span\n class=\"inline-flex h-9 min-w-9 items-center justify-center px-2 text-sm text-muted-foreground\"\n >...</span\n >\n </ng-container>\n <ng-template #pageButton>\n <button\n type=\"button\"\n [ngClass]=\"[\n 'inline-flex h-9 min-w-9 items-center justify-center rounded-md px-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n pageNumber === page\n ? 'appearance-none border border-border bg-muted text-foreground shadow-sm'\n : 'appearance-none border-0 bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground',\n ]\"\n (click)=\"setPage(+pageNumber)\"\n >\n {{ pageNumber }}\n </button>\n </ng-template>\n </li>\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page >= pageCount\"\n (click)=\"setPage(page + 1)\"\n >\n Next\n <pdm-icon name=\"chevron-right\" [size]=\"14\"></pdm-icon>\n </button>\n </li>\n </ul>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PdmIconComponent, selector: "pdm-icon", inputs: ["name", "library", "assetUrl", "size", "strokeWidth", "className", "ariaLabel", "decorative"] }, { kind: "component", type: PdmSelectComponent, selector: "pdm-select", inputs: ["id", "value", "options", "disabled", "invalid", "className", "placeholder", "overlayOptions"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4939
+ PdmPaginationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmPaginationComponent, selector: "pdm-pagination", inputs: { page: "page", pageCount: "pageCount", maxVisible: "maxVisible", className: "className", rowsPerPageLabel: "rowsPerPageLabel", rowsPerPage: "rowsPerPage", rowsPerPageOptions: "rowsPerPageOptions" }, outputs: { pageChange: "pageChange", rowsPerPageChange: "rowsPerPageChange" }, ngImport: i0, template: "<nav\n aria-label=\"Pagination\"\n [ngClass]=\"[\n 'mx-auto flex w-full flex-wrap items-center justify-center gap-4',\n className,\n ]\"\n>\n <div class=\"flex items-center gap-3\" *ngIf=\"rowsPerPageOptions.length > 0\">\n <span class=\"text-sm font-medium text-foreground\">{{\n rowsPerPageLabel\n }}</span>\n <pdm-select\n [value]=\"rowsPerPageValue\"\n [options]=\"rowsPerPageSelectOptions\"\n [placeholder]=\"rowsPerPageValue\"\n className=\"w-[100px] sm:w-[120px]\"\n (valueChange)=\"onRowsPerPageChangeValue($event)\"\n ></pdm-select>\n </div>\n\n <ul class=\"m-0 flex list-none items-center gap-1 p-0\">\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page <= 1\"\n (click)=\"setPage(page - 1)\"\n >\n <pdm-icon name=\"chevron-left\" [size]=\"14\"></pdm-icon>\n Previous\n </button>\n </li>\n <li *ngFor=\"let pageNumber of visiblePages\">\n <ng-container *ngIf=\"pageNumber === 'ellipsis'; else pageButton\">\n <span\n class=\"inline-flex h-9 min-w-9 items-center justify-center px-2 text-sm text-muted-foreground\"\n >...</span\n >\n </ng-container>\n <ng-template #pageButton>\n <button\n type=\"button\"\n [ngClass]=\"[\n 'inline-flex h-9 min-w-9 items-center justify-center rounded-md px-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n pageNumber === page\n ? 'appearance-none border border-border bg-muted text-foreground shadow-sm'\n : 'appearance-none border-0 bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground',\n ]\"\n (click)=\"setPage(+pageNumber)\"\n >\n {{ pageNumber }}\n </button>\n </ng-template>\n </li>\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page >= pageCount\"\n (click)=\"setPage(page + 1)\"\n >\n Next\n <pdm-icon name=\"chevron-right\" [size]=\"14\"></pdm-icon>\n </button>\n </li>\n </ul>\n</nav>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PdmIconComponent, selector: "pdm-icon", inputs: ["name", "library", "assetUrl", "size", "strokeWidth", "className", "ariaLabel", "decorative"] }, { kind: "component", type: PdmSelectComponent, selector: "pdm-select", inputs: ["id", "value", "options", "disabled", "invalid", "className", "placeholder", "overlayOptions"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3781
4940
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmPaginationComponent, decorators: [{
3782
4941
  type: Component,
3783
- args: [{ selector: 'pdm-pagination', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav\n aria-label=\"Pagination\"\n [ngClass]=\"[\n 'mx-auto flex w-full flex-wrap items-center justify-center gap-4',\n className,\n ]\"\n>\n <div class=\"flex items-center gap-3\" *ngIf=\"rowsPerPageOptions.length > 0\">\n <span class=\"text-sm font-medium text-foreground\">{{\n rowsPerPageLabel\n }}</span>\n <pdm-select\n [value]=\"rowsPerPageValue\"\n [options]=\"rowsPerPageSelectOptions\"\n [placeholder]=\"rowsPerPageValue\"\n className=\"w-[120px]\"\n (valueChange)=\"onRowsPerPageChangeValue($event)\"\n ></pdm-select>\n </div>\n\n <ul class=\"m-0 flex list-none items-center gap-1 p-0\">\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page <= 1\"\n (click)=\"setPage(page - 1)\"\n >\n <pdm-icon name=\"chevron-left\" [size]=\"14\"></pdm-icon>\n Previous\n </button>\n </li>\n <li *ngFor=\"let pageNumber of visiblePages\">\n <ng-container *ngIf=\"pageNumber === 'ellipsis'; else pageButton\">\n <span\n class=\"inline-flex h-9 min-w-9 items-center justify-center px-2 text-sm text-muted-foreground\"\n >...</span\n >\n </ng-container>\n <ng-template #pageButton>\n <button\n type=\"button\"\n [ngClass]=\"[\n 'inline-flex h-9 min-w-9 items-center justify-center rounded-md px-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n pageNumber === page\n ? 'appearance-none border border-border bg-muted text-foreground shadow-sm'\n : 'appearance-none border-0 bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground',\n ]\"\n (click)=\"setPage(+pageNumber)\"\n >\n {{ pageNumber }}\n </button>\n </ng-template>\n </li>\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page >= pageCount\"\n (click)=\"setPage(page + 1)\"\n >\n Next\n <pdm-icon name=\"chevron-right\" [size]=\"14\"></pdm-icon>\n </button>\n </li>\n </ul>\n</nav>\n" }]
4942
+ args: [{ selector: 'pdm-pagination', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav\n aria-label=\"Pagination\"\n [ngClass]=\"[\n 'mx-auto flex w-full flex-wrap items-center justify-center gap-4',\n className,\n ]\"\n>\n <div class=\"flex items-center gap-3\" *ngIf=\"rowsPerPageOptions.length > 0\">\n <span class=\"text-sm font-medium text-foreground\">{{\n rowsPerPageLabel\n }}</span>\n <pdm-select\n [value]=\"rowsPerPageValue\"\n [options]=\"rowsPerPageSelectOptions\"\n [placeholder]=\"rowsPerPageValue\"\n className=\"w-[100px] sm:w-[120px]\"\n (valueChange)=\"onRowsPerPageChangeValue($event)\"\n ></pdm-select>\n </div>\n\n <ul class=\"m-0 flex list-none items-center gap-1 p-0\">\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page <= 1\"\n (click)=\"setPage(page - 1)\"\n >\n <pdm-icon name=\"chevron-left\" [size]=\"14\"></pdm-icon>\n Previous\n </button>\n </li>\n <li *ngFor=\"let pageNumber of visiblePages\">\n <ng-container *ngIf=\"pageNumber === 'ellipsis'; else pageButton\">\n <span\n class=\"inline-flex h-9 min-w-9 items-center justify-center px-2 text-sm text-muted-foreground\"\n >...</span\n >\n </ng-container>\n <ng-template #pageButton>\n <button\n type=\"button\"\n [ngClass]=\"[\n 'inline-flex h-9 min-w-9 items-center justify-center rounded-md px-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n pageNumber === page\n ? 'appearance-none border border-border bg-muted text-foreground shadow-sm'\n : 'appearance-none border-0 bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground',\n ]\"\n (click)=\"setPage(+pageNumber)\"\n >\n {{ pageNumber }}\n </button>\n </ng-template>\n </li>\n <li>\n <button\n type=\"button\"\n class=\"inline-flex h-9 appearance-none items-center justify-center gap-1 rounded-md border-0 bg-transparent px-2 text-sm text-foreground hover:bg-accent disabled:opacity-50 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n [disabled]=\"page >= pageCount\"\n (click)=\"setPage(page + 1)\"\n >\n Next\n <pdm-icon name=\"chevron-right\" [size]=\"14\"></pdm-icon>\n </button>\n </li>\n </ul>\n</nav>\n" }]
3784
4943
  }], propDecorators: { page: [{
3785
4944
  type: Input
3786
4945
  }], pageCount: [{
@@ -3836,10 +4995,11 @@ class PdmPopoverComponent {
3836
4995
  return this._open;
3837
4996
  }
3838
4997
  get panelClasses() {
4998
+ const baseClasses = 'min-w-80 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md';
3839
4999
  return [
3840
5000
  this.panelPlacement === 'top'
3841
- ? 'absolute bottom-full left-0 z-30 mb-2 min-w-80 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md'
3842
- : 'absolute left-0 top-full z-30 mt-2 min-w-80 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md',
5001
+ ? `absolute bottom-full left-0 ${Z_INDEX.popover} mb-2 ${baseClasses}`
5002
+ : `absolute left-0 top-full ${Z_INDEX.popover} mt-2 ${baseClasses}`,
3843
5003
  this.panelClassName
3844
5004
  ];
3845
5005
  }
@@ -4032,14 +5192,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
4032
5192
  type: Input
4033
5193
  }] } });
4034
5194
 
5195
+ /**
5196
+ * Sheet/Side panel component con soporte responsive
5197
+ *
5198
+ * MEJORADO en v0.2.0:
5199
+ * - Tamaños configurables
5200
+ * - Mejor manejo de overflow
5201
+ * - Responsive sizes
5202
+ *
5203
+ * @example
5204
+ * <pdm-sheet [open]="isOpen" side="right" size="md">
5205
+ * <h3>Settings</h3>
5206
+ * <p>Content here</p>
5207
+ * </pdm-sheet>
5208
+ */
4035
5209
  class PdmSheetComponent {
4036
5210
  constructor() {
4037
5211
  this.open = false;
5212
+ /**
5213
+ * Lado desde donde aparece el sheet
5214
+ */
4038
5215
  this.side = 'right';
5216
+ /**
5217
+ * Tamaño del sheet
5218
+ * - sm: 320px (side) / 40vh (top/bottom)
5219
+ * - md: 400px (side) / 50vh (top/bottom) (default)
5220
+ * - lg: 500px (side) / 66vh (top/bottom)
5221
+ * - xl: 640px (side) / 80vh (top/bottom)
5222
+ * - full: 100%
5223
+ */
5224
+ this.size = 'md';
4039
5225
  this.className = '';
4040
- /** Close when the ESC key is pressed. Default: `true`. */
4041
5226
  this.closeOnEsc = true;
4042
- /** Close when the backdrop is clicked. Default: `true`. */
4043
5227
  this.closeOnBackdropClick = true;
4044
5228
  this.openChange = new EventEmitter();
4045
5229
  }
@@ -4057,24 +5241,56 @@ class PdmSheetComponent {
4057
5241
  this.openChange.emit(false);
4058
5242
  }
4059
5243
  get panelClass() {
4060
- if (this.side === 'left')
4061
- return 'left-0 top-0 h-full w-full max-w-[360px] border-r';
4062
- if (this.side === 'top')
4063
- return 'top-0 left-0 w-full border-b';
4064
- if (this.side === 'bottom')
4065
- return 'bottom-0 left-0 w-full border-t';
4066
- return 'right-0 top-0 h-full w-full max-w-[360px] border-l';
5244
+ const base = 'absolute bg-background border-border shadow-lg overflow-auto';
5245
+ const position = this.getPositionClass();
5246
+ const sizing = this.getSizingClass();
5247
+ return `${base} ${position} ${sizing} ${this.className}`.trim();
5248
+ }
5249
+ getPositionClass() {
5250
+ const map = {
5251
+ left: 'left-0 top-0 h-full border-r',
5252
+ right: 'right-0 top-0 h-full border-l',
5253
+ top: 'top-0 left-0 w-full border-b',
5254
+ bottom: 'bottom-0 left-0 w-full border-t'
5255
+ };
5256
+ return map[this.side];
5257
+ }
5258
+ getSizingClass() {
5259
+ if (this.size === 'full') {
5260
+ return 'w-full h-full';
5261
+ }
5262
+ const isHorizontal = this.side === 'left' || this.side === 'right';
5263
+ if (isHorizontal) {
5264
+ const widthMap = {
5265
+ sm: 'w-full max-w-[320px] sm:max-w-[320px]',
5266
+ md: 'w-full max-w-[360px] sm:max-w-[400px]',
5267
+ lg: 'w-full max-w-[400px] sm:max-w-[500px]',
5268
+ xl: 'w-full max-w-[500px] sm:max-w-[640px]'
5269
+ };
5270
+ return widthMap[this.size] || widthMap.md;
5271
+ }
5272
+ else {
5273
+ const heightMap = {
5274
+ sm: 'max-h-[40vh]',
5275
+ md: 'max-h-[50vh]',
5276
+ lg: 'max-h-[66vh]',
5277
+ xl: 'max-h-[80vh]'
5278
+ };
5279
+ return heightMap[this.size] || heightMap.md;
5280
+ }
4067
5281
  }
4068
5282
  }
4069
5283
  PdmSheetComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmSheetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4070
- PdmSheetComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmSheetComponent, selector: "pdm-sheet", inputs: { open: "open", side: "side", className: "className", closeOnEsc: "closeOnEsc", closeOnBackdropClick: "closeOnBackdropClick" }, outputs: { openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50\">\n <button type=\"button\" class=\"absolute inset-0 appearance-none border-0 bg-foreground/80 p-0\" aria-label=\"Close sheet\" (click)=\"onBackdropClick()\"></button>\n\n <section [ngClass]=\"['absolute border border-border bg-background p-6 shadow-lg', panelClass, className]\" role=\"dialog\" aria-modal=\"true\">\n <button type=\"button\" class=\"absolute right-3 top-3 appearance-none rounded-sm border-0 bg-transparent p-0 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\" (click)=\"close()\">\n <pdm-icon name=\"x\" [size]=\"16\"></pdm-icon>\n </button>\n <ng-content></ng-content>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PdmIconComponent, selector: "pdm-icon", inputs: ["name", "library", "assetUrl", "size", "strokeWidth", "className", "ariaLabel", "decorative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5284
+ PdmSheetComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmSheetComponent, selector: "pdm-sheet", inputs: { open: "open", side: "side", size: "size", className: "className", closeOnEsc: "closeOnEsc", closeOnBackdropClick: "closeOnBackdropClick" }, outputs: { openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEsc()" } }, ngImport: i0, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50\">\n <button type=\"button\" class=\"absolute inset-0 appearance-none border-0 bg-foreground/80 p-0\" aria-label=\"Close sheet\" (click)=\"onBackdropClick()\"></button>\n\n <section [ngClass]=\"['absolute z-[60] border border-border bg-background p-6 shadow-lg', panelClass, className]\" role=\"dialog\" aria-modal=\"true\">\n <button type=\"button\" class=\"absolute right-3 top-3 appearance-none rounded-sm border-0 bg-transparent p-0 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\" (click)=\"close()\">\n <pdm-icon name=\"x\" [size]=\"16\"></pdm-icon>\n </button>\n <ng-content></ng-content>\n </section>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PdmIconComponent, selector: "pdm-icon", inputs: ["name", "library", "assetUrl", "size", "strokeWidth", "className", "ariaLabel", "decorative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4071
5285
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmSheetComponent, decorators: [{
4072
5286
  type: Component,
4073
- args: [{ selector: 'pdm-sheet', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50\">\n <button type=\"button\" class=\"absolute inset-0 appearance-none border-0 bg-foreground/80 p-0\" aria-label=\"Close sheet\" (click)=\"onBackdropClick()\"></button>\n\n <section [ngClass]=\"['absolute border border-border bg-background p-6 shadow-lg', panelClass, className]\" role=\"dialog\" aria-modal=\"true\">\n <button type=\"button\" class=\"absolute right-3 top-3 appearance-none rounded-sm border-0 bg-transparent p-0 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\" (click)=\"close()\">\n <pdm-icon name=\"x\" [size]=\"16\"></pdm-icon>\n </button>\n <ng-content></ng-content>\n </section>\n</div>\n" }]
5287
+ args: [{ selector: 'pdm-sheet', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"open\" class=\"fixed inset-0 z-50\">\n <button type=\"button\" class=\"absolute inset-0 appearance-none border-0 bg-foreground/80 p-0\" aria-label=\"Close sheet\" (click)=\"onBackdropClick()\"></button>\n\n <section [ngClass]=\"['absolute z-[60] border border-border bg-background p-6 shadow-lg', panelClass, className]\" role=\"dialog\" aria-modal=\"true\">\n <button type=\"button\" class=\"absolute right-3 top-3 appearance-none rounded-sm border-0 bg-transparent p-0 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\" (click)=\"close()\">\n <pdm-icon name=\"x\" [size]=\"16\"></pdm-icon>\n </button>\n <ng-content></ng-content>\n </section>\n</div>\n" }]
4074
5288
  }], propDecorators: { open: [{
4075
5289
  type: Input
4076
5290
  }], side: [{
4077
5291
  type: Input
5292
+ }], size: [{
5293
+ type: Input
4078
5294
  }], className: [{
4079
5295
  type: Input
4080
5296
  }], closeOnEsc: [{
@@ -4088,21 +5304,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
4088
5304
  args: ['document:keydown.escape']
4089
5305
  }] } });
4090
5306
 
5307
+ /**
5308
+ * Sidebar component - Navegación lateral responsive
5309
+ *
5310
+ * MEJORAS en v0.2.0:
5311
+ * - Mobile drawer mode: overlay fullscreen en mobile, sidebar fijo en desktop
5312
+ * - Sidebar mode: sidebar persistente con widths responsive
5313
+ * - Backdrop automático en mobile drawer mode
5314
+ *
5315
+ * @example
5316
+ * <!-- Mobile drawer (default) -->
5317
+ * <pdm-sidebar [open]="sidebarOpen" (openChange)="sidebarOpen = $event">
5318
+ * <nav>Menu items...</nav>
5319
+ * </pdm-sidebar>
5320
+ *
5321
+ * <!-- Sidebar persistente -->
5322
+ * <pdm-sidebar mobileMode="sidebar" [collapsed]="collapsed">
5323
+ * <nav>Menu items...</nav>
5324
+ * </pdm-sidebar>
5325
+ */
4091
5326
  class PdmSidebarComponent {
4092
5327
  constructor() {
5328
+ /**
5329
+ * Mobile behavior: 'drawer' (overlay) o 'sidebar' (persistente)
5330
+ * @default 'drawer'
5331
+ */
5332
+ this.mobileMode = 'drawer';
5333
+ /**
5334
+ * Collapsed state (solo aplica en mobileMode="sidebar")
5335
+ */
4093
5336
  this.collapsed = false;
5337
+ /**
5338
+ * Open state (solo aplica en mobileMode="drawer")
5339
+ */
5340
+ this.open = false;
4094
5341
  this.className = '';
5342
+ /**
5343
+ * Emite cuando el drawer se cierra (solo en mobileMode="drawer")
5344
+ */
5345
+ this.openChange = new EventEmitter();
5346
+ }
5347
+ onBackdropClick() {
5348
+ if (this.mobileMode === 'drawer') {
5349
+ this.open = false;
5350
+ this.openChange.emit(false);
5351
+ }
4095
5352
  }
4096
5353
  }
4097
5354
  PdmSidebarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4098
- PdmSidebarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmSidebarComponent, selector: "pdm-sidebar", inputs: { collapsed: "collapsed", className: "className" }, ngImport: i0, template: "<aside [ngClass]=\"['h-full border-r border-border bg-background transition-all', collapsed ? 'w-14' : 'w-64', className]\">\n <ng-content></ng-content>\n</aside>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5355
+ PdmSidebarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmSidebarComponent, selector: "pdm-sidebar", inputs: { mobileMode: "mobileMode", collapsed: "collapsed", open: "open", className: "className" }, outputs: { openChange: "openChange" }, ngImport: i0, template: "<!-- Mobile drawer mode -->\n<ng-container *ngIf=\"mobileMode === 'drawer'\">\n <!-- Backdrop -->\n <div\n *ngIf=\"open\"\n class=\"fixed inset-0 z-40 bg-black/50 lg:hidden\"\n (click)=\"onBackdropClick()\"\n ></div>\n \n <!-- Drawer -->\n <aside\n [ngClass]=\"[\n 'fixed inset-y-0 left-0 z-50 h-full w-64 transform border-r border-border bg-background transition-transform duration-300 lg:relative lg:z-auto lg:translate-x-0',\n open ? 'translate-x-0' : '-translate-x-full',\n className\n ]\"\n >\n <ng-content></ng-content>\n </aside>\n</ng-container>\n\n<!-- Sidebar persistente mode -->\n<aside\n *ngIf=\"mobileMode === 'sidebar'\"\n [ngClass]=\"[\n 'h-full border-r border-border bg-background transition-all',\n collapsed ? 'w-14 sm:w-14' : 'w-48 sm:w-56 lg:w-64',\n className\n ]\"\n>\n <ng-content></ng-content>\n</aside>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4099
5356
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmSidebarComponent, decorators: [{
4100
5357
  type: Component,
4101
- args: [{ selector: 'pdm-sidebar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<aside [ngClass]=\"['h-full border-r border-border bg-background transition-all', collapsed ? 'w-14' : 'w-64', className]\">\n <ng-content></ng-content>\n</aside>\n" }]
4102
- }], propDecorators: { collapsed: [{
5358
+ args: [{ selector: 'pdm-sidebar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Mobile drawer mode -->\n<ng-container *ngIf=\"mobileMode === 'drawer'\">\n <!-- Backdrop -->\n <div\n *ngIf=\"open\"\n class=\"fixed inset-0 z-40 bg-black/50 lg:hidden\"\n (click)=\"onBackdropClick()\"\n ></div>\n \n <!-- Drawer -->\n <aside\n [ngClass]=\"[\n 'fixed inset-y-0 left-0 z-50 h-full w-64 transform border-r border-border bg-background transition-transform duration-300 lg:relative lg:z-auto lg:translate-x-0',\n open ? 'translate-x-0' : '-translate-x-full',\n className\n ]\"\n >\n <ng-content></ng-content>\n </aside>\n</ng-container>\n\n<!-- Sidebar persistente mode -->\n<aside\n *ngIf=\"mobileMode === 'sidebar'\"\n [ngClass]=\"[\n 'h-full border-r border-border bg-background transition-all',\n collapsed ? 'w-14 sm:w-14' : 'w-48 sm:w-56 lg:w-64',\n className\n ]\"\n>\n <ng-content></ng-content>\n</aside>\n" }]
5359
+ }], propDecorators: { mobileMode: [{
5360
+ type: Input
5361
+ }], collapsed: [{
5362
+ type: Input
5363
+ }], open: [{
4103
5364
  type: Input
4104
5365
  }], className: [{
4105
5366
  type: Input
5367
+ }], openChange: [{
5368
+ type: Output
4106
5369
  }] } });
4107
5370
 
4108
5371
  class PdmSkeletonComponent {
@@ -4269,213 +5532,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
4269
5532
  type: Output
4270
5533
  }] } });
4271
5534
 
4272
- class PdmTableComponent {
4273
- constructor(renderer) {
4274
- this.renderer = renderer;
4275
- this.variant = 'default';
4276
- this.reorderRows = false;
4277
- this.dragHandleSelector = '[data-drag-handle],[data-slot=row-drag-handle],.row-drag-handle,[data-auto-drag-handle]';
4278
- this.className = '';
4279
- this.rowOrderChange = new EventEmitter();
4280
- this.cleanupListeners = [];
4281
- this.draggedRow = null;
4282
- }
4283
- ngAfterViewInit() {
4284
- this.syncReorderBehavior();
4285
- }
4286
- ngOnChanges(changes) {
4287
- if (changes['reorderRows'] || changes['variant']) {
4288
- this.syncReorderBehavior();
4289
- }
4290
- }
4291
- ngOnDestroy() {
4292
- this.cleanupReorderBehavior();
4293
- }
4294
- get wrapperClasses() {
4295
- return [
4296
- 'relative w-full overflow-auto',
4297
- this.variant === 'interactive' ? 'overflow-x-auto overflow-y-hidden rounded-xl border border-border bg-background' : '',
4298
- this.variant === 'data' ? 'overflow-hidden rounded-md border border-border bg-background' : '',
4299
- this.className
4300
- ];
4301
- }
4302
- get tableClasses() {
4303
- return [
4304
- 'w-full caption-bottom text-sm',
4305
- this.variant === 'data'
4306
- ? 'border-collapse text-foreground [&_thead_tr]:border-b [&_thead_tr]:border-border [&_tbody_tr]:border-b [&_tbody_tr]:border-border [&_tbody_tr:last-child]:border-b-0 [&_th]:h-10 [&_th]:px-2 [&_th]:text-left [&_th]:align-middle [&_th]:font-medium [&_td]:p-2 [&_td]:align-middle'
4307
- : '',
4308
- this.variant === 'interactive'
4309
- ? 'text-foreground [&_thead]:sticky [&_thead]:top-0 [&_thead]:z-10 [&_thead]:bg-muted/70 [&_thead_tr]:border-b [&_thead_tr]:border-border [&_th]:h-12 [&_th]:px-4 [&_th]:text-left [&_th]:align-middle [&_th]:text-sm [&_th]:font-medium [&_th]:whitespace-nowrap [&_tbody_tr]:border-b [&_tbody_tr]:border-border [&_tbody_tr]:transition-colors [&_tbody_tr:hover]:bg-muted/50 [&_tbody_tr:last-child]:border-b-0 [&_td]:h-14 [&_td]:px-4 [&_td]:align-middle [&_td]:text-sm [&_td]:whitespace-nowrap [&_td:first-child]:w-10 [&_td:last-child]:w-10 [&_svg]:text-muted-foreground'
4310
- : ''
4311
- ];
4312
- }
4313
- syncReorderBehavior() {
4314
- this.cleanupReorderBehavior();
4315
- if (!this.isReorderEnabled) {
4316
- return;
4317
- }
4318
- const tbody = this.getTbody();
4319
- if (!tbody) {
4320
- return;
4321
- }
4322
- this.setRowsDraggable(tbody, true);
4323
- this.cleanupListeners.push(this.renderer.listen(tbody, 'mousedown', (event) => this.armDragFromHandle(event)), this.renderer.listen(tbody, 'dragstart', (event) => this.onDragStart(event)), this.renderer.listen(tbody, 'dragover', (event) => this.onDragOver(event, tbody)), this.renderer.listen(tbody, 'drop', (event) => this.onDrop(event)), this.renderer.listen(tbody, 'dragend', () => this.onDragEnd()));
4324
- this.observer = new MutationObserver(() => this.setRowsDraggable(tbody, true));
4325
- this.observer.observe(tbody, { childList: true });
4326
- }
4327
- cleanupReorderBehavior() {
4328
- this.cleanupListeners.forEach((dispose) => dispose());
4329
- this.cleanupListeners = [];
4330
- if (this.observer) {
4331
- this.observer.disconnect();
4332
- this.observer = undefined;
4333
- }
4334
- const tbody = this.getTbody();
4335
- if (tbody) {
4336
- this.setRowsDraggable(tbody, false);
4337
- }
4338
- this.draggedRow = null;
4339
- }
4340
- get isReorderEnabled() {
4341
- return this.reorderRows;
4342
- }
4343
- getTbody() {
4344
- var _a, _b;
4345
- return (_b = (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.nativeElement.tBodies.item(0)) !== null && _b !== void 0 ? _b : null;
4346
- }
4347
- setRowsDraggable(tbody, enabled) {
4348
- const rows = Array.from(tbody.rows);
4349
- rows.forEach((row) => {
4350
- this.syncAutoDragHandle(row, enabled);
4351
- row.draggable = false;
4352
- if (!enabled) {
4353
- delete row.dataset['dragging'];
4354
- delete row.dataset['dragArmed'];
4355
- }
4356
- });
4357
- }
4358
- syncAutoDragHandle(row, enabled) {
4359
- const firstCell = row.cells.item(0);
4360
- if (!firstCell) {
4361
- return;
4362
- }
4363
- const existingAutoHandle = firstCell.querySelector('[data-auto-drag-handle]');
4364
- if (!enabled) {
4365
- existingAutoHandle === null || existingAutoHandle === void 0 ? void 0 : existingAutoHandle.remove();
4366
- return;
4367
- }
4368
- const hasCustomHandle = !!firstCell.querySelector('[data-drag-handle],[data-slot=row-drag-handle],.row-drag-handle');
4369
- if (hasCustomHandle || existingAutoHandle) {
4370
- return;
4371
- }
4372
- const button = this.renderer.createElement('button');
4373
- this.renderer.setAttribute(button, 'type', 'button');
4374
- this.renderer.setAttribute(button, 'aria-label', 'Drag row');
4375
- this.renderer.setAttribute(button, 'data-auto-drag-handle', 'true');
4376
- this.renderer.addClass(button, 'inline-flex');
4377
- this.renderer.addClass(button, 'h-7');
4378
- this.renderer.addClass(button, 'w-7');
4379
- this.renderer.addClass(button, 'items-center');
4380
- this.renderer.addClass(button, 'justify-center');
4381
- this.renderer.addClass(button, 'cursor-grab');
4382
- this.renderer.addClass(button, 'active:cursor-grabbing');
4383
- this.renderer.addClass(button, 'text-muted-foreground');
4384
- const dots = this.renderer.createElement('span');
4385
- this.renderer.addClass(dots, 'text-sm');
4386
- this.renderer.addClass(dots, 'leading-none');
4387
- this.renderer.setProperty(dots, 'textContent', '⋮⋮');
4388
- this.renderer.appendChild(button, dots);
4389
- this.renderer.insertBefore(firstCell, button, firstCell.firstChild);
4390
- }
4391
- onDragStart(event) {
4392
- const target = event.target;
4393
- const row = target === null || target === void 0 ? void 0 : target.closest('tr');
4394
- if (!row) {
4395
- return;
4396
- }
4397
- const handle = target === null || target === void 0 ? void 0 : target.closest(this.dragHandleSelector);
4398
- const isArmed = row.dataset['dragArmed'] === 'true';
4399
- if ((!handle || !row.contains(handle)) && !isArmed) {
4400
- event.preventDefault();
4401
- return;
4402
- }
4403
- this.draggedRow = row;
4404
- this.draggedRow.dataset['dragging'] = 'true';
4405
- if (event.dataTransfer) {
4406
- event.dataTransfer.effectAllowed = 'move';
4407
- event.dataTransfer.setData('text/plain', '');
4408
- }
4409
- }
4410
- onDragOver(event, tbody) {
4411
- if (!this.draggedRow) {
4412
- return;
4413
- }
4414
- event.preventDefault();
4415
- const target = event.target;
4416
- const targetRow = target === null || target === void 0 ? void 0 : target.closest('tr');
4417
- if (!targetRow || targetRow === this.draggedRow) {
4418
- return;
4419
- }
4420
- const rect = targetRow.getBoundingClientRect();
4421
- const shouldInsertBefore = event.clientY < rect.top + rect.height / 2;
4422
- tbody.insertBefore(this.draggedRow, shouldInsertBefore ? targetRow : targetRow.nextSibling);
4423
- }
4424
- onDrop(event) {
4425
- event.preventDefault();
4426
- }
4427
- onDragEnd() {
4428
- const tbody = this.getTbody();
4429
- if (tbody) {
4430
- Array.from(tbody.rows).forEach((row) => {
4431
- row.draggable = false;
4432
- delete row.dataset['dragArmed'];
4433
- });
4434
- }
4435
- if (this.draggedRow) {
4436
- delete this.draggedRow.dataset['dragging'];
4437
- this.draggedRow = null;
4438
- }
4439
- if (!tbody) {
4440
- return;
4441
- }
4442
- const order = Array.from(tbody.rows).map((row, index) => row.getAttribute('data-row-id') || String(index));
4443
- this.rowOrderChange.emit(order);
4444
- }
4445
- armDragFromHandle(event) {
4446
- const target = event.target;
4447
- const handle = target === null || target === void 0 ? void 0 : target.closest(this.dragHandleSelector);
4448
- if (!handle) {
4449
- return;
4450
- }
4451
- const row = handle.closest('tr');
4452
- if (!row) {
4453
- return;
4454
- }
4455
- row.draggable = true;
4456
- row.dataset['dragArmed'] = 'true';
4457
- }
4458
- }
4459
- PdmTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTableComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
4460
- PdmTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmTableComponent, selector: "pdm-table", inputs: { variant: "variant", reorderRows: "reorderRows", dragHandleSelector: "dragHandleSelector", className: "className" }, outputs: { rowOrderChange: "rowOrderChange" }, viewQueries: [{ propertyName: "tableElement", first: true, predicate: ["tableElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div [ngClass]=\"wrapperClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table-container' : null\">\n <table #tableElement [ngClass]=\"tableClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table' : null\">\n <ng-content></ng-content>\n </table>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4461
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTableComponent, decorators: [{
4462
- type: Component,
4463
- args: [{ selector: 'pdm-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"wrapperClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table-container' : null\">\n <table #tableElement [ngClass]=\"tableClasses\" [attr.data-slot]=\"variant === 'interactive' ? 'table' : null\">\n <ng-content></ng-content>\n </table>\n</div>\n" }]
4464
- }], ctorParameters: function () { return [{ type: i0.Renderer2 }]; }, propDecorators: { variant: [{
4465
- type: Input
4466
- }], reorderRows: [{
4467
- type: Input
4468
- }], dragHandleSelector: [{
4469
- type: Input
4470
- }], className: [{
4471
- type: Input
4472
- }], rowOrderChange: [{
4473
- type: Output
4474
- }], tableElement: [{
4475
- type: ViewChild,
4476
- args: ['tableElement']
4477
- }] } });
4478
-
4479
5535
  class PdmTabsComponent {
4480
5536
  constructor(cdr) {
4481
5537
  this.cdr = cdr;
@@ -4493,10 +5549,10 @@ class PdmTabsComponent {
4493
5549
  }
4494
5550
  }
4495
5551
  PdmTabsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTabsComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
4496
- PdmTabsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmTabsComponent, selector: "pdm-tabs", inputs: { items: "items", value: "value", className: "className" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div [ngClass]=\"['w-full', className]\">\n <div role=\"tablist\" class=\"inline-flex h-8 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground\">\n <button\n *ngFor=\"let item of items\"\n role=\"tab\"\n [attr.aria-selected]=\"value === item.value\"\n [disabled]=\"item.disabled\"\n [ngClass]=\"[\n 'relative inline-flex h-[calc(100%-1px)] appearance-none flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium transition-all focus-visible:border-ring focus-visible:outline-none focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50',\n value === item.value ? 'bg-background text-foreground shadow-sm' : 'bg-transparent text-muted-foreground'\n ]\"\n (click)=\"select(item)\"\n type=\"button\"\n >\n {{ item.label }}\n </button>\n </div>\n <div class=\"mt-4\">\n <ng-content></ng-content>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5552
+ PdmTabsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmTabsComponent, selector: "pdm-tabs", inputs: { items: "items", value: "value", className: "className" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div [ngClass]=\"['w-full', className]\">\n <div\n role=\"tablist\"\n class=\"inline-flex h-8 w-full items-center overflow-x-auto scrollbar-thin rounded-lg bg-muted p-[3px] text-muted-foreground md:w-fit\"\n >\n <button\n *ngFor=\"let item of items\"\n role=\"tab\"\n [attr.aria-selected]=\"value === item.value\"\n [disabled]=\"item.disabled\"\n [ngClass]=\"[\n 'relative inline-flex h-[calc(100%-1px)] appearance-none flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-3 py-0.5 text-sm font-medium transition-all focus-visible:border-ring focus-visible:outline-none focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 md:flex-initial md:px-4',\n value === item.value ? 'bg-background text-foreground shadow-sm' : 'bg-transparent text-muted-foreground'\n ]\"\n (click)=\"select(item)\"\n type=\"button\"\n >\n {{ item.label }}\n </button>\n </div>\n <div class=\"mt-4\">\n <ng-content></ng-content>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4497
5553
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTabsComponent, decorators: [{
4498
5554
  type: Component,
4499
- args: [{ selector: 'pdm-tabs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"['w-full', className]\">\n <div role=\"tablist\" class=\"inline-flex h-8 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground\">\n <button\n *ngFor=\"let item of items\"\n role=\"tab\"\n [attr.aria-selected]=\"value === item.value\"\n [disabled]=\"item.disabled\"\n [ngClass]=\"[\n 'relative inline-flex h-[calc(100%-1px)] appearance-none flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium transition-all focus-visible:border-ring focus-visible:outline-none focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50',\n value === item.value ? 'bg-background text-foreground shadow-sm' : 'bg-transparent text-muted-foreground'\n ]\"\n (click)=\"select(item)\"\n type=\"button\"\n >\n {{ item.label }}\n </button>\n </div>\n <div class=\"mt-4\">\n <ng-content></ng-content>\n </div>\n</div>\n" }]
5555
+ args: [{ selector: 'pdm-tabs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [ngClass]=\"['w-full', className]\">\n <div\n role=\"tablist\"\n class=\"inline-flex h-8 w-full items-center overflow-x-auto scrollbar-thin rounded-lg bg-muted p-[3px] text-muted-foreground md:w-fit\"\n >\n <button\n *ngFor=\"let item of items\"\n role=\"tab\"\n [attr.aria-selected]=\"value === item.value\"\n [disabled]=\"item.disabled\"\n [ngClass]=\"[\n 'relative inline-flex h-[calc(100%-1px)] appearance-none flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-3 py-0.5 text-sm font-medium transition-all focus-visible:border-ring focus-visible:outline-none focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 md:flex-initial md:px-4',\n value === item.value ? 'bg-background text-foreground shadow-sm' : 'bg-transparent text-muted-foreground'\n ]\"\n (click)=\"select(item)\"\n type=\"button\"\n >\n {{ item.label }}\n </button>\n </div>\n <div class=\"mt-4\">\n <ng-content></ng-content>\n </div>\n</div>\n" }]
4500
5556
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { items: [{
4501
5557
  type: Input
4502
5558
  }], value: [{
@@ -4647,10 +5703,10 @@ class PdmTooltipComponent {
4647
5703
  }
4648
5704
  }
4649
5705
  PdmTooltipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4650
- PdmTooltipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmTooltipComponent, selector: "pdm-tooltip", inputs: { text: "text", side: "side", className: "className" }, ngImport: i0, template: "<span class=\"relative inline-flex\" [ngClass]=\"className\" (mouseenter)=\"open = true\" (mouseleave)=\"open = false\" (focusin)=\"open = true\" (focusout)=\"open = false\">\n <ng-content></ng-content>\n <span *ngIf=\"open\" [ngClass]=\"['pointer-events-none absolute z-50 overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background animate-in fade-in-0 zoom-in-95', positionClass]\">\n {{ text }}\n </span>\n</span>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5706
+ PdmTooltipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: PdmTooltipComponent, selector: "pdm-tooltip", inputs: { text: "text", side: "side", className: "className" }, ngImport: i0, template: "<span class=\"relative inline-flex\" [ngClass]=\"className\" (mouseenter)=\"open = true\" (mouseleave)=\"open = false\" (focusin)=\"open = true\" (focusout)=\"open = false\">\n <ng-content></ng-content>\n <span *ngIf=\"open\" [ngClass]=\"['pointer-events-none absolute z-[70] overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background animate-in fade-in-0 zoom-in-95', positionClass]\">\n {{ text }}\n </span>\n</span>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4651
5707
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PdmTooltipComponent, decorators: [{
4652
5708
  type: Component,
4653
- args: [{ selector: 'pdm-tooltip', changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"relative inline-flex\" [ngClass]=\"className\" (mouseenter)=\"open = true\" (mouseleave)=\"open = false\" (focusin)=\"open = true\" (focusout)=\"open = false\">\n <ng-content></ng-content>\n <span *ngIf=\"open\" [ngClass]=\"['pointer-events-none absolute z-50 overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background animate-in fade-in-0 zoom-in-95', positionClass]\">\n {{ text }}\n </span>\n</span>\n" }]
5709
+ args: [{ selector: 'pdm-tooltip', changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"relative inline-flex\" [ngClass]=\"className\" (mouseenter)=\"open = true\" (mouseleave)=\"open = false\" (focusin)=\"open = true\" (focusout)=\"open = false\">\n <ng-content></ng-content>\n <span *ngIf=\"open\" [ngClass]=\"['pointer-events-none absolute z-[70] overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background animate-in fade-in-0 zoom-in-95', positionClass]\">\n {{ text }}\n </span>\n</span>\n" }]
4654
5710
  }], propDecorators: { text: [{
4655
5711
  type: Input
4656
5712
  }], side: [{
@@ -4681,6 +5737,7 @@ const COMPONENTS = [
4681
5737
  PdmDataTableComponent,
4682
5738
  PdmDatePickerComponent,
4683
5739
  PdmDialogComponent,
5740
+ PdmDraggableTableComponent,
4684
5741
  PdmDropdownMenuComponent,
4685
5742
  PdmDrawerComponent,
4686
5743
  PdmEmptyComponent,
@@ -4744,6 +5801,7 @@ PdmUiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version:
4744
5801
  PdmDataTableComponent,
4745
5802
  PdmDatePickerComponent,
4746
5803
  PdmDialogComponent,
5804
+ PdmDraggableTableComponent,
4747
5805
  PdmDropdownMenuComponent,
4748
5806
  PdmDrawerComponent,
4749
5807
  PdmEmptyComponent,
@@ -4802,6 +5860,7 @@ PdmUiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version:
4802
5860
  PdmDataTableComponent,
4803
5861
  PdmDatePickerComponent,
4804
5862
  PdmDialogComponent,
5863
+ PdmDraggableTableComponent,
4805
5864
  PdmDropdownMenuComponent,
4806
5865
  PdmDrawerComponent,
4807
5866
  PdmEmptyComponent,
@@ -4854,5 +5913,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
4854
5913
  * Generated bundle index. Do not edit.
4855
5914
  */
4856
5915
 
4857
- export { PdmAccordionComponent, PdmAlertComponent, PdmAlertDialogComponent, PdmAspectRatioComponent, PdmAvatarComponent, PdmBadgeComponent, PdmBreadcrumbComponent, PdmButtonComponent, PdmButtonGroupComponent, PdmCalendarComponent, PdmCardComponent, PdmCarouselComponent, PdmChartComponent, PdmCheckboxComponent, PdmCollapsibleComponent, PdmComboboxComponent, PdmCommandComponent, PdmContextMenuComponent, PdmDataTableComponent, PdmDatePickerComponent, PdmDialogComponent, PdmDrawerComponent, PdmDropdownMenuComponent, PdmEmptyComponent, PdmFieldComponent, PdmHoverCardComponent, PdmIconComponent, PdmInputComponent, PdmInputGroupComponent, PdmInputOtpComponent, PdmInputPasswordComponent, PdmItemComponent, PdmKbdComponent, PdmLabelComponent, PdmMenubarComponent, PdmNativeSelectComponent, PdmNavigationMenuComponent, PdmOutsideClickDirective, PdmPaginationComponent, PdmPopoverComponent, PdmProgressComponent, PdmRadioGroupComponent, PdmScrollAreaComponent, PdmSelectComponent, PdmSelectOptionDirective, PdmSeparatorComponent, PdmSheetComponent, PdmSidebarComponent, PdmSkeletonComponent, PdmSliderComponent, PdmSonnerComponent, PdmSpinnerComponent, PdmSwitchComponent, PdmTableComponent, PdmTabsComponent, PdmTextareaComponent, PdmToggleComponent, PdmToggleGroupComponent, PdmTooltipComponent, PdmUiKitModule, createFlexiblePositionStrategy };
5916
+ export { BREAKPOINTS, PdmAccordionComponent, PdmAlertComponent, PdmAlertDialogComponent, PdmAspectRatioComponent, PdmAvatarComponent, PdmBadgeComponent, PdmBreadcrumbComponent, PdmButtonComponent, PdmButtonGroupComponent, PdmCalendarComponent, PdmCardComponent, PdmCarouselComponent, PdmChartComponent, PdmCheckboxComponent, PdmCollapsibleComponent, PdmComboboxComponent, PdmCommandComponent, PdmContextMenuComponent, PdmDataTableComponent, PdmDatePickerComponent, PdmDialogComponent, PdmDraggableTableComponent, PdmDrawerComponent, PdmDropdownMenuComponent, PdmEmptyComponent, PdmFieldComponent, PdmHoverCardComponent, PdmIconComponent, PdmInputComponent, PdmInputGroupComponent, PdmInputOtpComponent, PdmInputPasswordComponent, PdmItemComponent, PdmKbdComponent, PdmLabelComponent, PdmMenubarComponent, PdmNativeSelectComponent, PdmNavigationMenuComponent, PdmOutsideClickDirective, PdmPaginationComponent, PdmPopoverComponent, PdmProgressComponent, PdmRadioGroupComponent, PdmScrollAreaComponent, PdmSelectComponent, PdmSelectOptionDirective, PdmSeparatorComponent, PdmSheetComponent, PdmSidebarComponent, PdmSkeletonComponent, PdmSliderComponent, PdmSonnerComponent, PdmSpinnerComponent, PdmSwitchComponent, PdmTableComponent, PdmTabsComponent, PdmTextareaComponent, PdmToggleComponent, PdmToggleGroupComponent, PdmTooltipComponent, PdmUiKitModule, RESPONSIVE_CONTAINER, RESPONSIVE_DISPLAY, TABLE_RESPONSIVE, Z_INDEX, createFlexiblePositionStrategy, logZIndexStack, overflowResponsive, responsive, spacingResponsive, widthResponsive };
4858
5917
  //# sourceMappingURL=pdm-ui-kit.mjs.map