@avora-labs/meta-forge 1.0.5 → 1.0.6

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 (20) hide show
  1. package/README.md +112 -63
  2. package/fesm2022/{avora-labs-meta-forge-amf-auth-shell.component-BWSdjBUS.mjs → avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs} +57 -57
  3. package/fesm2022/avora-labs-meta-forge-amf-auth-shell.component-FCubZyZ1.mjs.map +1 -0
  4. package/fesm2022/{avora-labs-meta-forge-contact-support.page-BAUiKm3P.mjs → avora-labs-meta-forge-contact-support.page-CgcSAr0x.mjs} +146 -146
  5. package/fesm2022/avora-labs-meta-forge-contact-support.page-CgcSAr0x.mjs.map +1 -0
  6. package/fesm2022/{avora-labs-meta-forge-forgot-password.page-0XLiBrV1.mjs → avora-labs-meta-forge-forgot-password.page-CWdWX-mj.mjs} +238 -238
  7. package/fesm2022/avora-labs-meta-forge-forgot-password.page-CWdWX-mj.mjs.map +1 -0
  8. package/fesm2022/{avora-labs-meta-forge-login.page-etTr5NqJ.mjs → avora-labs-meta-forge-login.page-LCW-ofz1.mjs} +74 -74
  9. package/fesm2022/avora-labs-meta-forge-login.page-LCW-ofz1.mjs.map +1 -0
  10. package/fesm2022/avora-labs-meta-forge.mjs +1995 -1995
  11. package/fesm2022/avora-labs-meta-forge.mjs.map +1 -1
  12. package/package.json +3 -1
  13. package/styles/_palettes.scss +84 -84
  14. package/styles/_themes.scss +96 -96
  15. package/styles/_variables.scss +56 -56
  16. package/styles/styles.scss +295 -295
  17. package/fesm2022/avora-labs-meta-forge-amf-auth-shell.component-BWSdjBUS.mjs.map +0 -1
  18. package/fesm2022/avora-labs-meta-forge-contact-support.page-BAUiKm3P.mjs.map +0 -1
  19. package/fesm2022/avora-labs-meta-forge-forgot-password.page-0XLiBrV1.mjs.map +0 -1
  20. package/fesm2022/avora-labs-meta-forge-login.page-etTr5NqJ.mjs.map +0 -1
@@ -1526,10 +1526,10 @@ class ActionDispatcherService {
1526
1526
  if (el) {
1527
1527
  const printWindow = window.open('', '_blank');
1528
1528
  if (printWindow) {
1529
- printWindow.document.write(`
1530
- <html><head><title>${config.title || 'Print'}</title>
1531
- <style>body { font-family: system-ui, sans-serif; padding: 20px; }</style>
1532
- </head><body>${el.innerHTML}</body></html>
1529
+ printWindow.document.write(`
1530
+ <html><head><title>${config.title || 'Print'}</title>
1531
+ <style>body { font-family: system-ui, sans-serif; padding: 20px; }</style>
1532
+ </head><body>${el.innerHTML}</body></html>
1533
1533
  `);
1534
1534
  printWindow.document.close();
1535
1535
  printWindow.print();
@@ -1831,32 +1831,32 @@ class MetaPageComponent {
1831
1831
  return true;
1832
1832
  }
1833
1833
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MetaPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1834
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: MetaPageComponent, isStandalone: true, selector: "amf-page", ngImport: i0, template: `
1835
- @if (pageMeta()) {
1836
- <div class="amf-page-wrapper" [class]="pageMeta()!.cssClass || ''"
1837
- [class.amf-animate-fade]="pageMeta()!.animation === 'fade'"
1838
- [class.amf-animate-slide-up]="pageMeta()!.animation === 'slide-up'"
1839
- [class.amf-animate-zoom]="pageMeta()!.animation === 'zoom'">
1840
- @for (section of pageMeta()!.sections; track $index) {
1841
- <amf-renderer [section]="section" [context]="context()" class="amf-section"></amf-renderer>
1842
- }
1843
- </div>
1844
- }
1834
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: MetaPageComponent, isStandalone: true, selector: "amf-page", ngImport: i0, template: `
1835
+ @if (pageMeta()) {
1836
+ <div class="amf-page-wrapper" [class]="pageMeta()!.cssClass || ''"
1837
+ [class.amf-animate-fade]="pageMeta()!.animation === 'fade'"
1838
+ [class.amf-animate-slide-up]="pageMeta()!.animation === 'slide-up'"
1839
+ [class.amf-animate-zoom]="pageMeta()!.animation === 'zoom'">
1840
+ @for (section of pageMeta()!.sections; track $index) {
1841
+ <amf-renderer [section]="section" [context]="context()" class="amf-section"></amf-renderer>
1842
+ }
1843
+ </div>
1844
+ }
1845
1845
  `, isInline: true, styles: [".amf-page-wrapper{display:flex;flex-direction:column;gap:24px;width:100%}.amf-section{display:block;width:100%}.amf-animate-fade{animation:amfFadeIn .3s ease-out}.amf-animate-slide-up{animation:amfSlideUp .3s ease-out}.amf-animate-zoom{animation:amfZoom .3s ease-out}@keyframes amfFadeIn{0%{opacity:0}to{opacity:1}}@keyframes amfSlideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes amfZoom{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}\n"], dependencies: [{ kind: "component", type: MetaRendererComponent, selector: "amf-renderer", inputs: ["section", "context"] }] });
1846
1846
  }
1847
1847
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MetaPageComponent, decorators: [{
1848
1848
  type: Component,
1849
- args: [{ selector: 'amf-page', standalone: true, imports: [MetaRendererComponent], template: `
1850
- @if (pageMeta()) {
1851
- <div class="amf-page-wrapper" [class]="pageMeta()!.cssClass || ''"
1852
- [class.amf-animate-fade]="pageMeta()!.animation === 'fade'"
1853
- [class.amf-animate-slide-up]="pageMeta()!.animation === 'slide-up'"
1854
- [class.amf-animate-zoom]="pageMeta()!.animation === 'zoom'">
1855
- @for (section of pageMeta()!.sections; track $index) {
1856
- <amf-renderer [section]="section" [context]="context()" class="amf-section"></amf-renderer>
1857
- }
1858
- </div>
1859
- }
1849
+ args: [{ selector: 'amf-page', standalone: true, imports: [MetaRendererComponent], template: `
1850
+ @if (pageMeta()) {
1851
+ <div class="amf-page-wrapper" [class]="pageMeta()!.cssClass || ''"
1852
+ [class.amf-animate-fade]="pageMeta()!.animation === 'fade'"
1853
+ [class.amf-animate-slide-up]="pageMeta()!.animation === 'slide-up'"
1854
+ [class.amf-animate-zoom]="pageMeta()!.animation === 'zoom'">
1855
+ @for (section of pageMeta()!.sections; track $index) {
1856
+ <amf-renderer [section]="section" [context]="context()" class="amf-section"></amf-renderer>
1857
+ }
1858
+ </div>
1859
+ }
1860
1860
  `, styles: [".amf-page-wrapper{display:flex;flex-direction:column;gap:24px;width:100%}.amf-section{display:block;width:100%}.amf-animate-fade{animation:amfFadeIn .3s ease-out}.amf-animate-slide-up{animation:amfSlideUp .3s ease-out}.amf-animate-zoom{animation:amfZoom .3s ease-out}@keyframes amfFadeIn{0%{opacity:0}to{opacity:1}}@keyframes amfSlideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes amfZoom{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}\n"] }]
1861
1861
  }], ctorParameters: () => [] });
1862
1862
 
@@ -2277,21 +2277,21 @@ function getAmfAuthRoutes(meta) {
2277
2277
  if (pages.includes('login')) {
2278
2278
  routes.push({
2279
2279
  path: 'login',
2280
- loadComponent: () => import('./avora-labs-meta-forge-login.page-etTr5NqJ.mjs').then(m => m.LoginComponent),
2280
+ loadComponent: () => import('./avora-labs-meta-forge-login.page-LCW-ofz1.mjs').then(m => m.LoginComponent),
2281
2281
  data: { layout: 'empty' },
2282
2282
  });
2283
2283
  }
2284
2284
  if (pages.includes('forgot-password')) {
2285
2285
  routes.push({
2286
2286
  path: 'forgot-password',
2287
- loadComponent: () => import('./avora-labs-meta-forge-forgot-password.page-0XLiBrV1.mjs').then(m => m.ForgotPasswordComponent),
2287
+ loadComponent: () => import('./avora-labs-meta-forge-forgot-password.page-CWdWX-mj.mjs').then(m => m.ForgotPasswordComponent),
2288
2288
  data: { layout: 'empty' },
2289
2289
  });
2290
2290
  }
2291
2291
  if (pages.includes('contact-support')) {
2292
2292
  routes.push({
2293
2293
  path: 'contact-support',
2294
- loadComponent: () => import('./avora-labs-meta-forge-contact-support.page-BAUiKm3P.mjs').then(m => m.ContactSupportComponent),
2294
+ loadComponent: () => import('./avora-labs-meta-forge-contact-support.page-CgcSAr0x.mjs').then(m => m.ContactSupportComponent),
2295
2295
  data: { layout: 'empty' },
2296
2296
  });
2297
2297
  }
@@ -2347,100 +2347,100 @@ class AccordionSectionComponent {
2347
2347
  this.openPanels.set(current);
2348
2348
  }
2349
2349
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AccordionSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2350
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AccordionSectionComponent, isStandalone: true, selector: "amf-accordion-section", inputs: { config: "config", context: "context" }, usesOnChanges: true, ngImport: i0, template: `
2351
- <div class="amf-accordion"
2352
- [class]="'variant-' + (config.variant || 'default')"
2353
- [class.accordion-bordered]="config.variant === 'bordered'">
2354
- @for (panel of visiblePanels(); track $index) {
2355
- <div class="accordion-panel"
2356
- [class.open]="isOpen($index)"
2357
- [class.disabled]="panel.disabled">
2358
-
2359
- <!-- Panel Header -->
2360
- <button
2361
- type="button"
2362
- class="accordion-header"
2363
- [attr.aria-expanded]="isOpen($index)"
2364
- [disabled]="panel.disabled"
2365
- (click)="togglePanel($index)">
2366
-
2367
- <div class="accordion-header-left">
2368
- @if (panel.icon) {
2369
- <svg class="panel-icon" viewBox="0 0 24 24">
2370
- <path [attr.d]="panel.icon"/>
2371
- </svg>
2372
- }
2373
- <span class="panel-title">{{ panel.title }}</span>
2374
- </div>
2375
-
2376
- <div class="accordion-header-right">
2377
- <svg class="chevron-icon" viewBox="0 0 24 24">
2378
- <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>
2379
- </svg>
2380
- </div>
2381
- </button>
2382
-
2383
- <!-- Panel Content -->
2384
- <div class="accordion-body" [class.open]="isOpen($index)">
2385
- <div class="accordion-body-inner">
2386
- @for (section of panel.sections; track $index) {
2387
- <amf-renderer [section]="section" [context]="context" class="amf-section">
2388
- </amf-renderer>
2389
- }
2390
- </div>
2391
- </div>
2392
- </div>
2393
- }
2394
- </div>
2350
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AccordionSectionComponent, isStandalone: true, selector: "amf-accordion-section", inputs: { config: "config", context: "context" }, usesOnChanges: true, ngImport: i0, template: `
2351
+ <div class="amf-accordion"
2352
+ [class]="'variant-' + (config.variant || 'default')"
2353
+ [class.accordion-bordered]="config.variant === 'bordered'">
2354
+ @for (panel of visiblePanels(); track $index) {
2355
+ <div class="accordion-panel"
2356
+ [class.open]="isOpen($index)"
2357
+ [class.disabled]="panel.disabled">
2358
+
2359
+ <!-- Panel Header -->
2360
+ <button
2361
+ type="button"
2362
+ class="accordion-header"
2363
+ [attr.aria-expanded]="isOpen($index)"
2364
+ [disabled]="panel.disabled"
2365
+ (click)="togglePanel($index)">
2366
+
2367
+ <div class="accordion-header-left">
2368
+ @if (panel.icon) {
2369
+ <svg class="panel-icon" viewBox="0 0 24 24">
2370
+ <path [attr.d]="panel.icon"/>
2371
+ </svg>
2372
+ }
2373
+ <span class="panel-title">{{ panel.title }}</span>
2374
+ </div>
2375
+
2376
+ <div class="accordion-header-right">
2377
+ <svg class="chevron-icon" viewBox="0 0 24 24">
2378
+ <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>
2379
+ </svg>
2380
+ </div>
2381
+ </button>
2382
+
2383
+ <!-- Panel Content -->
2384
+ <div class="accordion-body" [class.open]="isOpen($index)">
2385
+ <div class="accordion-body-inner">
2386
+ @for (section of panel.sections; track $index) {
2387
+ <amf-renderer [section]="section" [context]="context" class="amf-section">
2388
+ </amf-renderer>
2389
+ }
2390
+ </div>
2391
+ </div>
2392
+ </div>
2393
+ }
2394
+ </div>
2395
2395
  `, isInline: true, styles: [".amf-accordion{display:flex;flex-direction:column;border-radius:16px;overflow:hidden;border:1px solid var(--app-border);background:var(--app-surface)}.amf-accordion.variant-flush{border:none;border-radius:0;gap:0}.amf-accordion.variant-bordered{gap:8px;border:none;background:transparent;overflow:visible}.accordion-panel{overflow:hidden;transition:box-shadow .2s}.variant-default .accordion-panel+.accordion-panel{border-top:1px solid var(--app-border)}.variant-bordered .accordion-panel{border:1px solid var(--app-border);border-radius:12px;overflow:hidden;background:var(--app-surface);transition:box-shadow .25s}.variant-bordered .accordion-panel.open{box-shadow:0 4px 20px #0000001f;border-color:var(--app-primary)}.accordion-panel.disabled{opacity:.5;pointer-events:none}.accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:16px 20px;background:transparent;border:none;cursor:pointer;text-align:left;transition:background .2s;gap:12px}.accordion-header:hover{background:var(--glass-bg)}.accordion-header:disabled{cursor:not-allowed}.accordion-panel.open .accordion-header{background:var(--glass-bg)}.accordion-header-left{display:flex;align-items:center;gap:10px;flex:1;min-width:0}.panel-icon{width:18px;height:18px;fill:var(--app-primary);flex-shrink:0}.panel-title{font-size:.9375rem;font-weight:600;color:var(--app-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.accordion-header-right{flex-shrink:0}.chevron-icon{width:20px;height:20px;fill:var(--app-text-muted);transition:transform .3s cubic-bezier(.4,0,.2,1)}.accordion-panel.open .chevron-icon{transform:rotate(180deg);fill:var(--app-primary)}.accordion-body{max-height:0;overflow:hidden;transition:max-height .45s cubic-bezier(.4,0,.2,1)}.accordion-body.open{max-height:4000px}.accordion-body-inner{display:flex;flex-direction:column;gap:16px;padding:16px 20px 20px;border-top:1px solid var(--app-border);animation:accordionFadeIn .3s ease-out}@keyframes accordionFadeIn{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}:host{display:block}.amf-section{display:block}\n"], dependencies: [{ kind: "component", type: MetaRendererComponent, selector: "amf-renderer", inputs: ["section", "context"] }] });
2396
2396
  }
2397
2397
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AccordionSectionComponent, decorators: [{
2398
2398
  type: Component,
2399
- args: [{ selector: 'amf-accordion-section', standalone: true, imports: [MetaRendererComponent], template: `
2400
- <div class="amf-accordion"
2401
- [class]="'variant-' + (config.variant || 'default')"
2402
- [class.accordion-bordered]="config.variant === 'bordered'">
2403
- @for (panel of visiblePanels(); track $index) {
2404
- <div class="accordion-panel"
2405
- [class.open]="isOpen($index)"
2406
- [class.disabled]="panel.disabled">
2407
-
2408
- <!-- Panel Header -->
2409
- <button
2410
- type="button"
2411
- class="accordion-header"
2412
- [attr.aria-expanded]="isOpen($index)"
2413
- [disabled]="panel.disabled"
2414
- (click)="togglePanel($index)">
2415
-
2416
- <div class="accordion-header-left">
2417
- @if (panel.icon) {
2418
- <svg class="panel-icon" viewBox="0 0 24 24">
2419
- <path [attr.d]="panel.icon"/>
2420
- </svg>
2421
- }
2422
- <span class="panel-title">{{ panel.title }}</span>
2423
- </div>
2424
-
2425
- <div class="accordion-header-right">
2426
- <svg class="chevron-icon" viewBox="0 0 24 24">
2427
- <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>
2428
- </svg>
2429
- </div>
2430
- </button>
2431
-
2432
- <!-- Panel Content -->
2433
- <div class="accordion-body" [class.open]="isOpen($index)">
2434
- <div class="accordion-body-inner">
2435
- @for (section of panel.sections; track $index) {
2436
- <amf-renderer [section]="section" [context]="context" class="amf-section">
2437
- </amf-renderer>
2438
- }
2439
- </div>
2440
- </div>
2441
- </div>
2442
- }
2443
- </div>
2399
+ args: [{ selector: 'amf-accordion-section', standalone: true, imports: [MetaRendererComponent], template: `
2400
+ <div class="amf-accordion"
2401
+ [class]="'variant-' + (config.variant || 'default')"
2402
+ [class.accordion-bordered]="config.variant === 'bordered'">
2403
+ @for (panel of visiblePanels(); track $index) {
2404
+ <div class="accordion-panel"
2405
+ [class.open]="isOpen($index)"
2406
+ [class.disabled]="panel.disabled">
2407
+
2408
+ <!-- Panel Header -->
2409
+ <button
2410
+ type="button"
2411
+ class="accordion-header"
2412
+ [attr.aria-expanded]="isOpen($index)"
2413
+ [disabled]="panel.disabled"
2414
+ (click)="togglePanel($index)">
2415
+
2416
+ <div class="accordion-header-left">
2417
+ @if (panel.icon) {
2418
+ <svg class="panel-icon" viewBox="0 0 24 24">
2419
+ <path [attr.d]="panel.icon"/>
2420
+ </svg>
2421
+ }
2422
+ <span class="panel-title">{{ panel.title }}</span>
2423
+ </div>
2424
+
2425
+ <div class="accordion-header-right">
2426
+ <svg class="chevron-icon" viewBox="0 0 24 24">
2427
+ <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>
2428
+ </svg>
2429
+ </div>
2430
+ </button>
2431
+
2432
+ <!-- Panel Content -->
2433
+ <div class="accordion-body" [class.open]="isOpen($index)">
2434
+ <div class="accordion-body-inner">
2435
+ @for (section of panel.sections; track $index) {
2436
+ <amf-renderer [section]="section" [context]="context" class="amf-section">
2437
+ </amf-renderer>
2438
+ }
2439
+ </div>
2440
+ </div>
2441
+ </div>
2442
+ }
2443
+ </div>
2444
2444
  `, styles: [".amf-accordion{display:flex;flex-direction:column;border-radius:16px;overflow:hidden;border:1px solid var(--app-border);background:var(--app-surface)}.amf-accordion.variant-flush{border:none;border-radius:0;gap:0}.amf-accordion.variant-bordered{gap:8px;border:none;background:transparent;overflow:visible}.accordion-panel{overflow:hidden;transition:box-shadow .2s}.variant-default .accordion-panel+.accordion-panel{border-top:1px solid var(--app-border)}.variant-bordered .accordion-panel{border:1px solid var(--app-border);border-radius:12px;overflow:hidden;background:var(--app-surface);transition:box-shadow .25s}.variant-bordered .accordion-panel.open{box-shadow:0 4px 20px #0000001f;border-color:var(--app-primary)}.accordion-panel.disabled{opacity:.5;pointer-events:none}.accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:16px 20px;background:transparent;border:none;cursor:pointer;text-align:left;transition:background .2s;gap:12px}.accordion-header:hover{background:var(--glass-bg)}.accordion-header:disabled{cursor:not-allowed}.accordion-panel.open .accordion-header{background:var(--glass-bg)}.accordion-header-left{display:flex;align-items:center;gap:10px;flex:1;min-width:0}.panel-icon{width:18px;height:18px;fill:var(--app-primary);flex-shrink:0}.panel-title{font-size:.9375rem;font-weight:600;color:var(--app-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.accordion-header-right{flex-shrink:0}.chevron-icon{width:20px;height:20px;fill:var(--app-text-muted);transition:transform .3s cubic-bezier(.4,0,.2,1)}.accordion-panel.open .chevron-icon{transform:rotate(180deg);fill:var(--app-primary)}.accordion-body{max-height:0;overflow:hidden;transition:max-height .45s cubic-bezier(.4,0,.2,1)}.accordion-body.open{max-height:4000px}.accordion-body-inner{display:flex;flex-direction:column;gap:16px;padding:16px 20px 20px;border-top:1px solid var(--app-border);animation:accordionFadeIn .3s ease-out}@keyframes accordionFadeIn{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}:host{display:block}.amf-section{display:block}\n"] }]
2445
2445
  }], propDecorators: { config: [{
2446
2446
  type: Input
@@ -2480,60 +2480,60 @@ class MetaModalHostComponent {
2480
2480
  this.dispatcher.dispatch(actionMeta, {});
2481
2481
  }
2482
2482
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MetaModalHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2483
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: MetaModalHostComponent, isStandalone: true, selector: "amf-modal-host", ngImport: i0, template: `
2484
- @if (isOpen()) {
2485
- <div class="amf-modal-backdrop" (click)="closeOnBackdrop($event)">
2486
- <div class="amf-modal-dialog" [ngClass]="['size-' + (config()?.size || 'md')]" (click)="$event.stopPropagation()">
2487
- <div class="amf-modal-header">
2488
- <h3>{{ config()?.title }}</h3>
2489
- <button class="amf-modal-close" (click)="close()">&times;</button>
2490
- </div>
2491
- <div class="amf-modal-content">
2492
- @if (config()?.content) {
2493
- <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2494
- }
2495
- </div>
2496
- @if (config()?.actions?.length) {
2497
- <div class="amf-modal-footer">
2498
- @for (action of config()!.actions; track action.label) {
2499
- <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2500
- {{ action.label }}
2501
- </button>
2502
- }
2503
- </div>
2504
- }
2505
- </div>
2506
- </div>
2507
- }
2483
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: MetaModalHostComponent, isStandalone: true, selector: "amf-modal-host", ngImport: i0, template: `
2484
+ @if (isOpen()) {
2485
+ <div class="amf-modal-backdrop" (click)="closeOnBackdrop($event)">
2486
+ <div class="amf-modal-dialog" [ngClass]="['size-' + (config()?.size || 'md')]" (click)="$event.stopPropagation()">
2487
+ <div class="amf-modal-header">
2488
+ <h3>{{ config()?.title }}</h3>
2489
+ <button class="amf-modal-close" (click)="close()">&times;</button>
2490
+ </div>
2491
+ <div class="amf-modal-content">
2492
+ @if (config()?.content) {
2493
+ <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2494
+ }
2495
+ </div>
2496
+ @if (config()?.actions?.length) {
2497
+ <div class="amf-modal-footer">
2498
+ @for (action of config()!.actions; track action.label) {
2499
+ <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2500
+ {{ action.label }}
2501
+ </button>
2502
+ }
2503
+ </div>
2504
+ }
2505
+ </div>
2506
+ </div>
2507
+ }
2508
2508
  `, isInline: true, styles: [".amf-modal-backdrop{position:fixed;inset:0;background:#0009;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:9999;display:flex;align-items:center;justify-content:center;padding:20px;animation:fadeIn .2s ease-out}.amf-modal-dialog{background:var(--glass-bg, rgba(20,25,40,.9));border:1px solid var(--app-border, rgba(255,255,255,.1));border-radius:16px;box-shadow:0 25px 50px -12px #00000080;width:100%;max-height:90vh;overflow-y:auto;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}.size-sm{max-width:400px}.size-md{max-width:600px}.size-lg{max-width:800px}.size-full{max-width:95vw;height:95vh}.amf-modal-header{padding:20px 24px;border-bottom:1px solid var(--app-border, rgba(255,255,255,.1));display:flex;justify-content:space-between;align-items:center}.amf-modal-header h3{font-size:1.25rem;margin:0;color:#fff}.amf-modal-close{background:transparent;border:none;color:#94a3b8;font-size:1.5rem;cursor:pointer;line-height:1;padding:0 4px}.amf-modal-close:hover{color:#fff}.amf-modal-content{padding:24px;flex-grow:1;color:#94a3b8}.amf-modal-footer{padding:16px 24px;border-top:1px solid var(--app-border, rgba(255,255,255,.1));display:flex;justify-content:flex-end;gap:12px}.btn-primary{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600}.btn-outline{background:transparent;border:1px solid #475569;color:#e2e8f0;padding:10px 20px;border-radius:8px;cursor:pointer;font-weight:600}.btn-danger{background:#ef4444;color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MetaRendererComponent, selector: "amf-renderer", inputs: ["section", "context"] }] });
2509
2509
  }
2510
2510
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MetaModalHostComponent, decorators: [{
2511
2511
  type: Component,
2512
- args: [{ selector: 'amf-modal-host', standalone: true, imports: [CommonModule, MetaRendererComponent], template: `
2513
- @if (isOpen()) {
2514
- <div class="amf-modal-backdrop" (click)="closeOnBackdrop($event)">
2515
- <div class="amf-modal-dialog" [ngClass]="['size-' + (config()?.size || 'md')]" (click)="$event.stopPropagation()">
2516
- <div class="amf-modal-header">
2517
- <h3>{{ config()?.title }}</h3>
2518
- <button class="amf-modal-close" (click)="close()">&times;</button>
2519
- </div>
2520
- <div class="amf-modal-content">
2521
- @if (config()?.content) {
2522
- <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2523
- }
2524
- </div>
2525
- @if (config()?.actions?.length) {
2526
- <div class="amf-modal-footer">
2527
- @for (action of config()!.actions; track action.label) {
2528
- <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2529
- {{ action.label }}
2530
- </button>
2531
- }
2532
- </div>
2533
- }
2534
- </div>
2535
- </div>
2536
- }
2512
+ args: [{ selector: 'amf-modal-host', standalone: true, imports: [CommonModule, MetaRendererComponent], template: `
2513
+ @if (isOpen()) {
2514
+ <div class="amf-modal-backdrop" (click)="closeOnBackdrop($event)">
2515
+ <div class="amf-modal-dialog" [ngClass]="['size-' + (config()?.size || 'md')]" (click)="$event.stopPropagation()">
2516
+ <div class="amf-modal-header">
2517
+ <h3>{{ config()?.title }}</h3>
2518
+ <button class="amf-modal-close" (click)="close()">&times;</button>
2519
+ </div>
2520
+ <div class="amf-modal-content">
2521
+ @if (config()?.content) {
2522
+ <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2523
+ }
2524
+ </div>
2525
+ @if (config()?.actions?.length) {
2526
+ <div class="amf-modal-footer">
2527
+ @for (action of config()!.actions; track action.label) {
2528
+ <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2529
+ {{ action.label }}
2530
+ </button>
2531
+ }
2532
+ </div>
2533
+ }
2534
+ </div>
2535
+ </div>
2536
+ }
2537
2537
  `, styles: [".amf-modal-backdrop{position:fixed;inset:0;background:#0009;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:9999;display:flex;align-items:center;justify-content:center;padding:20px;animation:fadeIn .2s ease-out}.amf-modal-dialog{background:var(--glass-bg, rgba(20,25,40,.9));border:1px solid var(--app-border, rgba(255,255,255,.1));border-radius:16px;box-shadow:0 25px 50px -12px #00000080;width:100%;max-height:90vh;overflow-y:auto;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}.size-sm{max-width:400px}.size-md{max-width:600px}.size-lg{max-width:800px}.size-full{max-width:95vw;height:95vh}.amf-modal-header{padding:20px 24px;border-bottom:1px solid var(--app-border, rgba(255,255,255,.1));display:flex;justify-content:space-between;align-items:center}.amf-modal-header h3{font-size:1.25rem;margin:0;color:#fff}.amf-modal-close{background:transparent;border:none;color:#94a3b8;font-size:1.5rem;cursor:pointer;line-height:1;padding:0 4px}.amf-modal-close:hover{color:#fff}.amf-modal-content{padding:24px;flex-grow:1;color:#94a3b8}.amf-modal-footer{padding:16px 24px;border-top:1px solid var(--app-border, rgba(255,255,255,.1));display:flex;justify-content:flex-end;gap:12px}.btn-primary{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600}.btn-outline{background:transparent;border:1px solid #475569;color:#e2e8f0;padding:10px 20px;border-radius:8px;cursor:pointer;font-weight:600}.btn-danger{background:#ef4444;color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}\n"] }]
2538
2538
  }] });
2539
2539
 
@@ -2635,84 +2635,84 @@ class AmfDialogHostComponent {
2635
2635
  }
2636
2636
  }
2637
2637
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AmfDialogHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2638
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AmfDialogHostComponent, isStandalone: true, selector: "amf-dialog-host", ngImport: i0, template: `
2639
- @if (currentDialog()) {
2640
- <div class="amf-dialog-backdrop" (click)="onBackdropClick()">
2641
- <div class="amf-dialog-box" (click)="$event.stopPropagation()">
2642
-
2643
- <div class="dialog-header">
2644
- <div class="dialog-icon-wrapper" [ngClass]="'variant-' + (currentDialog()?.config?.variant || 'info')">
2645
- @if (currentDialog()?.config?.icon) {
2646
- <svg viewBox="0 0 24 24" class="icon-element">
2647
- <path [attr.d]="iconPath"></path>
2648
- </svg>
2649
- } @else {
2650
- <span class="icon-fallback">!</span>
2651
- }
2652
- </div>
2653
- @if (currentDialog()?.config?.title) {
2654
- <h3 class="dialog-title">{{ currentDialog()!.config!.title }}</h3>
2655
- }
2656
- </div>
2657
-
2658
- <div class="dialog-content">
2659
- <p class="dialog-message">{{ currentDialog()!.config!.message }}</p>
2660
- </div>
2661
-
2662
- <div class="dialog-actions">
2663
- @if (currentDialog()?.config?.showCancel) {
2664
- <button class="btn btn-cancel" (click)="close(false)">
2665
- {{ currentDialog()?.config?.cancelLabel || 'Cancel' }}
2666
- </button>
2667
- }
2668
- <button class="btn btn-confirm" [ngClass]="'btn-variant-' + (currentDialog()?.config?.variant || 'info')" (click)="close(true)">
2669
- {{ currentDialog()?.config?.confirmLabel || 'OK' }}
2670
- </button>
2671
- </div>
2672
- </div>
2673
- </div>
2674
- }
2638
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AmfDialogHostComponent, isStandalone: true, selector: "amf-dialog-host", ngImport: i0, template: `
2639
+ @if (currentDialog()) {
2640
+ <div class="amf-dialog-backdrop" (click)="onBackdropClick()">
2641
+ <div class="amf-dialog-box" (click)="$event.stopPropagation()">
2642
+
2643
+ <div class="dialog-header">
2644
+ <div class="dialog-icon-wrapper" [ngClass]="'variant-' + (currentDialog()?.config?.variant || 'info')">
2645
+ @if (currentDialog()?.config?.icon) {
2646
+ <svg viewBox="0 0 24 24" class="icon-element">
2647
+ <path [attr.d]="iconPath"></path>
2648
+ </svg>
2649
+ } @else {
2650
+ <span class="icon-fallback">!</span>
2651
+ }
2652
+ </div>
2653
+ @if (currentDialog()?.config?.title) {
2654
+ <h3 class="dialog-title">{{ currentDialog()!.config!.title }}</h3>
2655
+ }
2656
+ </div>
2657
+
2658
+ <div class="dialog-content">
2659
+ <p class="dialog-message">{{ currentDialog()!.config!.message }}</p>
2660
+ </div>
2661
+
2662
+ <div class="dialog-actions">
2663
+ @if (currentDialog()?.config?.showCancel) {
2664
+ <button class="btn btn-cancel" (click)="close(false)">
2665
+ {{ currentDialog()?.config?.cancelLabel || 'Cancel' }}
2666
+ </button>
2667
+ }
2668
+ <button class="btn btn-confirm" [ngClass]="'btn-variant-' + (currentDialog()?.config?.variant || 'info')" (click)="close(true)">
2669
+ {{ currentDialog()?.config?.confirmLabel || 'OK' }}
2670
+ </button>
2671
+ </div>
2672
+ </div>
2673
+ </div>
2674
+ }
2675
2675
  `, isInline: true, styles: [".amf-dialog-backdrop{position:fixed;inset:0;background:#0a0f1ebf;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);z-index:10000;display:flex;align-items:center;justify-content:center;padding:20px;animation:fadeIn .25s ease-out}.amf-dialog-box{background:var(--glass-bg, rgba(20,25,40,.9));border:1px solid var(--app-border, rgba(255,255,255,.1));border-radius:20px;box-shadow:0 25px 50px -12px #0009,0 0 0 1px #ffffff0d inset;width:100%;max-width:420px;display:flex;flex-direction:column;animation:popIn .3s cubic-bezier(.16,1,.3,1);overflow:hidden}.dialog-header{padding:32px 32px 16px;display:flex;flex-direction:column;align-items:center;text-align:center;gap:16px}.dialog-icon-wrapper{width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:32px;color:#fff;box-shadow:0 8px 16px -4px #0000004d}.dialog-icon-wrapper.variant-info{background:linear-gradient(135deg,#3b82f6,#2563eb);box-shadow:0 8px 24px -6px #3b82f680}.dialog-icon-wrapper.variant-success{background:linear-gradient(135deg,#10b981,#059669);box-shadow:0 8px 24px -6px #10b98180}.dialog-icon-wrapper.variant-warning{background:linear-gradient(135deg,#f59e0b,#d97706);box-shadow:0 8px 24px -6px #f59e0b80}.dialog-icon-wrapper.variant-danger{background:linear-gradient(135deg,#ef4444,#dc2626);box-shadow:0 8px 24px -6px #ef444480}.icon-element{width:32px;height:32px;display:block;filter:drop-shadow(0 2px 2px rgba(0,0,0,.2))}.icon-fallback{font-family:monospace;font-weight:700}.dialog-title{margin:0;color:var(--app-text, #ffffff);font-size:1.25rem;font-weight:700;letter-spacing:-.02em}.dialog-content{padding:0 32px 32px;text-align:center}.dialog-message{margin:0;color:var(--app-text-muted, #94a3b8);font-size:.95rem;line-height:1.5}.dialog-actions{display:flex;gap:12px;padding:24px 32px;background:#0003;border-top:1px solid var(--app-border, rgba(255,255,255,.05))}.btn{flex:1;padding:12px 20px;border-radius:12px;font-size:.9rem;font-weight:600;cursor:pointer;transition:all .2s;border:none;display:inline-flex;align-items:center;justify-content:center}.btn-cancel{background:#ffffff0d;color:var(--app-text, #ffffff);border:1px solid rgba(255,255,255,.1)}.btn-cancel:hover{background:#ffffff1a}.btn-confirm{color:#fff;box-shadow:0 4px 12px transparent}.btn-confirm:hover{transform:translateY(-1px)}.btn-variant-info{background:#3b82f6;box-shadow:0 4px 12px #3b82f64d}.btn-variant-info:hover{background:#60a5fa;box-shadow:0 6px 16px #3b82f666}.btn-variant-success{background:#10b981;box-shadow:0 4px 12px #10b9814d}.btn-variant-success:hover{background:#34d399;box-shadow:0 6px 16px #10b98166}.btn-variant-warning{background:#f59e0b;box-shadow:0 4px 12px #f59e0b4d}.btn-variant-warning:hover{background:#fbbf24;box-shadow:0 6px 16px #f59e0b66}.btn-variant-danger{background:#ef4444;box-shadow:0 4px 12px #ef44444d}.btn-variant-danger:hover{background:#f87171;box-shadow:0 6px 16px #ef444466}@keyframes fadeIn{0%{opacity:0;-webkit-backdrop-filter:blur(0px);backdrop-filter:blur(0px)}to{opacity:1;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}}@keyframes popIn{0%{opacity:0;transform:scale(.9) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
2676
2676
  }
2677
2677
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AmfDialogHostComponent, decorators: [{
2678
2678
  type: Component,
2679
- args: [{ selector: 'amf-dialog-host', standalone: true, imports: [CommonModule], template: `
2680
- @if (currentDialog()) {
2681
- <div class="amf-dialog-backdrop" (click)="onBackdropClick()">
2682
- <div class="amf-dialog-box" (click)="$event.stopPropagation()">
2683
-
2684
- <div class="dialog-header">
2685
- <div class="dialog-icon-wrapper" [ngClass]="'variant-' + (currentDialog()?.config?.variant || 'info')">
2686
- @if (currentDialog()?.config?.icon) {
2687
- <svg viewBox="0 0 24 24" class="icon-element">
2688
- <path [attr.d]="iconPath"></path>
2689
- </svg>
2690
- } @else {
2691
- <span class="icon-fallback">!</span>
2692
- }
2693
- </div>
2694
- @if (currentDialog()?.config?.title) {
2695
- <h3 class="dialog-title">{{ currentDialog()!.config!.title }}</h3>
2696
- }
2697
- </div>
2698
-
2699
- <div class="dialog-content">
2700
- <p class="dialog-message">{{ currentDialog()!.config!.message }}</p>
2701
- </div>
2702
-
2703
- <div class="dialog-actions">
2704
- @if (currentDialog()?.config?.showCancel) {
2705
- <button class="btn btn-cancel" (click)="close(false)">
2706
- {{ currentDialog()?.config?.cancelLabel || 'Cancel' }}
2707
- </button>
2708
- }
2709
- <button class="btn btn-confirm" [ngClass]="'btn-variant-' + (currentDialog()?.config?.variant || 'info')" (click)="close(true)">
2710
- {{ currentDialog()?.config?.confirmLabel || 'OK' }}
2711
- </button>
2712
- </div>
2713
- </div>
2714
- </div>
2715
- }
2679
+ args: [{ selector: 'amf-dialog-host', standalone: true, imports: [CommonModule], template: `
2680
+ @if (currentDialog()) {
2681
+ <div class="amf-dialog-backdrop" (click)="onBackdropClick()">
2682
+ <div class="amf-dialog-box" (click)="$event.stopPropagation()">
2683
+
2684
+ <div class="dialog-header">
2685
+ <div class="dialog-icon-wrapper" [ngClass]="'variant-' + (currentDialog()?.config?.variant || 'info')">
2686
+ @if (currentDialog()?.config?.icon) {
2687
+ <svg viewBox="0 0 24 24" class="icon-element">
2688
+ <path [attr.d]="iconPath"></path>
2689
+ </svg>
2690
+ } @else {
2691
+ <span class="icon-fallback">!</span>
2692
+ }
2693
+ </div>
2694
+ @if (currentDialog()?.config?.title) {
2695
+ <h3 class="dialog-title">{{ currentDialog()!.config!.title }}</h3>
2696
+ }
2697
+ </div>
2698
+
2699
+ <div class="dialog-content">
2700
+ <p class="dialog-message">{{ currentDialog()!.config!.message }}</p>
2701
+ </div>
2702
+
2703
+ <div class="dialog-actions">
2704
+ @if (currentDialog()?.config?.showCancel) {
2705
+ <button class="btn btn-cancel" (click)="close(false)">
2706
+ {{ currentDialog()?.config?.cancelLabel || 'Cancel' }}
2707
+ </button>
2708
+ }
2709
+ <button class="btn btn-confirm" [ngClass]="'btn-variant-' + (currentDialog()?.config?.variant || 'info')" (click)="close(true)">
2710
+ {{ currentDialog()?.config?.confirmLabel || 'OK' }}
2711
+ </button>
2712
+ </div>
2713
+ </div>
2714
+ </div>
2715
+ }
2716
2716
  `, styles: [".amf-dialog-backdrop{position:fixed;inset:0;background:#0a0f1ebf;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);z-index:10000;display:flex;align-items:center;justify-content:center;padding:20px;animation:fadeIn .25s ease-out}.amf-dialog-box{background:var(--glass-bg, rgba(20,25,40,.9));border:1px solid var(--app-border, rgba(255,255,255,.1));border-radius:20px;box-shadow:0 25px 50px -12px #0009,0 0 0 1px #ffffff0d inset;width:100%;max-width:420px;display:flex;flex-direction:column;animation:popIn .3s cubic-bezier(.16,1,.3,1);overflow:hidden}.dialog-header{padding:32px 32px 16px;display:flex;flex-direction:column;align-items:center;text-align:center;gap:16px}.dialog-icon-wrapper{width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:32px;color:#fff;box-shadow:0 8px 16px -4px #0000004d}.dialog-icon-wrapper.variant-info{background:linear-gradient(135deg,#3b82f6,#2563eb);box-shadow:0 8px 24px -6px #3b82f680}.dialog-icon-wrapper.variant-success{background:linear-gradient(135deg,#10b981,#059669);box-shadow:0 8px 24px -6px #10b98180}.dialog-icon-wrapper.variant-warning{background:linear-gradient(135deg,#f59e0b,#d97706);box-shadow:0 8px 24px -6px #f59e0b80}.dialog-icon-wrapper.variant-danger{background:linear-gradient(135deg,#ef4444,#dc2626);box-shadow:0 8px 24px -6px #ef444480}.icon-element{width:32px;height:32px;display:block;filter:drop-shadow(0 2px 2px rgba(0,0,0,.2))}.icon-fallback{font-family:monospace;font-weight:700}.dialog-title{margin:0;color:var(--app-text, #ffffff);font-size:1.25rem;font-weight:700;letter-spacing:-.02em}.dialog-content{padding:0 32px 32px;text-align:center}.dialog-message{margin:0;color:var(--app-text-muted, #94a3b8);font-size:.95rem;line-height:1.5}.dialog-actions{display:flex;gap:12px;padding:24px 32px;background:#0003;border-top:1px solid var(--app-border, rgba(255,255,255,.05))}.btn{flex:1;padding:12px 20px;border-radius:12px;font-size:.9rem;font-weight:600;cursor:pointer;transition:all .2s;border:none;display:inline-flex;align-items:center;justify-content:center}.btn-cancel{background:#ffffff0d;color:var(--app-text, #ffffff);border:1px solid rgba(255,255,255,.1)}.btn-cancel:hover{background:#ffffff1a}.btn-confirm{color:#fff;box-shadow:0 4px 12px transparent}.btn-confirm:hover{transform:translateY(-1px)}.btn-variant-info{background:#3b82f6;box-shadow:0 4px 12px #3b82f64d}.btn-variant-info:hover{background:#60a5fa;box-shadow:0 6px 16px #3b82f666}.btn-variant-success{background:#10b981;box-shadow:0 4px 12px #10b9814d}.btn-variant-success:hover{background:#34d399;box-shadow:0 6px 16px #10b98166}.btn-variant-warning{background:#f59e0b;box-shadow:0 4px 12px #f59e0b4d}.btn-variant-warning:hover{background:#fbbf24;box-shadow:0 6px 16px #f59e0b66}.btn-variant-danger{background:#ef4444;box-shadow:0 4px 12px #ef44444d}.btn-variant-danger:hover{background:#f87171;box-shadow:0 6px 16px #ef444466}@keyframes fadeIn{0%{opacity:0;-webkit-backdrop-filter:blur(0px);backdrop-filter:blur(0px)}to{opacity:1;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}}@keyframes popIn{0%{opacity:0;transform:scale(.9) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"] }]
2717
2717
  }] });
2718
2718
 
@@ -2750,74 +2750,74 @@ class AmfDrawerHostComponent {
2750
2750
  this.dispatcher.dispatch(actionMeta, {});
2751
2751
  }
2752
2752
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AmfDrawerHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2753
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AmfDrawerHostComponent, isStandalone: true, selector: "amf-drawer-host", ngImport: i0, template: `
2754
- @if (isOpen()) {
2755
- <!-- Backdrop -->
2756
- <div class="amf-drawer-backdrop" (click)="closeOnBackdrop()"></div>
2757
- }
2758
- <!-- Drawer panel — always in DOM so the CSS slide animation works -->
2759
- <div class="amf-drawer-panel"
2760
- [class.is-open]="isOpen()"
2761
- [style.width]="config()?.size || '420px'"
2762
- [class.position-left]="config()?.position === 'left'"
2763
- (click)="$event.stopPropagation()">
2764
- @if (isOpen() && config()) {
2765
- <div class="amf-drawer-header">
2766
- <h3>{{ config()?.title }}</h3>
2767
- <button class="amf-drawer-close" (click)="close()" aria-label="Close drawer">&times;</button>
2768
- </div>
2769
- <div class="amf-drawer-content">
2770
- @if (config()?.content) {
2771
- <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2772
- }
2773
- </div>
2774
- @if (config()?.actions?.length) {
2775
- <div class="amf-drawer-footer">
2776
- @for (action of config()!.actions; track action.label) {
2777
- <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2778
- {{ action.label }}
2779
- </button>
2780
- }
2781
- </div>
2782
- }
2783
- }
2784
- </div>
2753
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AmfDrawerHostComponent, isStandalone: true, selector: "amf-drawer-host", ngImport: i0, template: `
2754
+ @if (isOpen()) {
2755
+ <!-- Backdrop -->
2756
+ <div class="amf-drawer-backdrop" (click)="closeOnBackdrop()"></div>
2757
+ }
2758
+ <!-- Drawer panel — always in DOM so the CSS slide animation works -->
2759
+ <div class="amf-drawer-panel"
2760
+ [class.is-open]="isOpen()"
2761
+ [style.width]="config()?.size || '420px'"
2762
+ [class.position-left]="config()?.position === 'left'"
2763
+ (click)="$event.stopPropagation()">
2764
+ @if (isOpen() && config()) {
2765
+ <div class="amf-drawer-header">
2766
+ <h3>{{ config()?.title }}</h3>
2767
+ <button class="amf-drawer-close" (click)="close()" aria-label="Close drawer">&times;</button>
2768
+ </div>
2769
+ <div class="amf-drawer-content">
2770
+ @if (config()?.content) {
2771
+ <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2772
+ }
2773
+ </div>
2774
+ @if (config()?.actions?.length) {
2775
+ <div class="amf-drawer-footer">
2776
+ @for (action of config()!.actions; track action.label) {
2777
+ <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2778
+ {{ action.label }}
2779
+ </button>
2780
+ }
2781
+ </div>
2782
+ }
2783
+ }
2784
+ </div>
2785
2785
  `, isInline: true, styles: [".amf-drawer-backdrop{position:fixed;inset:0;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1200;animation:fadeIn .25s ease-out}.amf-drawer-panel{position:fixed;top:0;right:0;height:100%;max-width:95vw;background:var(--glass-bg, rgba(15, 20, 40, .97));border-left:1px solid var(--app-border, rgba(255,255,255,.08));box-shadow:-20px 0 60px #00000080;z-index:1201;display:flex;flex-direction:column;transform:translate(100%);transition:transform .35s cubic-bezier(.16,1,.3,1);will-change:transform;overflow:hidden}.amf-drawer-panel.position-left{right:auto;left:0;border-left:none;border-right:1px solid var(--app-border, rgba(255,255,255,.08));transform:translate(-100%)}.amf-drawer-panel.is-open{transform:translate(0)}.amf-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid var(--app-border, rgba(255,255,255,.08));flex-shrink:0}.amf-drawer-header h3{margin:0;font-size:1.125rem;font-weight:700;color:var(--app-text, #f1f5f9);letter-spacing:-.01em}.amf-drawer-close{background:#ffffff0f;border:1px solid rgba(255,255,255,.08);color:var(--app-text-muted, #94a3b8);font-size:1.25rem;line-height:1;width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;flex-shrink:0}.amf-drawer-close:hover{background:#ffffff1f;color:var(--app-text, #f1f5f9)}.amf-drawer-content{flex:1;overflow-y:auto;padding:24px}.amf-drawer-footer{flex-shrink:0;padding:16px 24px;border-top:1px solid var(--app-border, rgba(255,255,255,.08));display:flex;justify-content:flex-end;gap:12px;background:#00000026}.btn-primary{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600;transition:all .2s}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 6px 20px var(--app-glow)}.btn-outline{background:transparent;border:1px solid #475569;color:#e2e8f0;padding:10px 20px;border-radius:8px;cursor:pointer;font-weight:600;transition:all .2s}.btn-outline:hover{background:#ffffff0f}.btn-danger{background:#ef4444;color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "component", type: MetaRendererComponent, selector: "amf-renderer", inputs: ["section", "context"] }] });
2786
2786
  }
2787
2787
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AmfDrawerHostComponent, decorators: [{
2788
2788
  type: Component,
2789
- args: [{ selector: 'amf-drawer-host', standalone: true, imports: [MetaRendererComponent], template: `
2790
- @if (isOpen()) {
2791
- <!-- Backdrop -->
2792
- <div class="amf-drawer-backdrop" (click)="closeOnBackdrop()"></div>
2793
- }
2794
- <!-- Drawer panel — always in DOM so the CSS slide animation works -->
2795
- <div class="amf-drawer-panel"
2796
- [class.is-open]="isOpen()"
2797
- [style.width]="config()?.size || '420px'"
2798
- [class.position-left]="config()?.position === 'left'"
2799
- (click)="$event.stopPropagation()">
2800
- @if (isOpen() && config()) {
2801
- <div class="amf-drawer-header">
2802
- <h3>{{ config()?.title }}</h3>
2803
- <button class="amf-drawer-close" (click)="close()" aria-label="Close drawer">&times;</button>
2804
- </div>
2805
- <div class="amf-drawer-content">
2806
- @if (config()?.content) {
2807
- <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2808
- }
2809
- </div>
2810
- @if (config()?.actions?.length) {
2811
- <div class="amf-drawer-footer">
2812
- @for (action of config()!.actions; track action.label) {
2813
- <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2814
- {{ action.label }}
2815
- </button>
2816
- }
2817
- </div>
2818
- }
2819
- }
2820
- </div>
2789
+ args: [{ selector: 'amf-drawer-host', standalone: true, imports: [MetaRendererComponent], template: `
2790
+ @if (isOpen()) {
2791
+ <!-- Backdrop -->
2792
+ <div class="amf-drawer-backdrop" (click)="closeOnBackdrop()"></div>
2793
+ }
2794
+ <!-- Drawer panel — always in DOM so the CSS slide animation works -->
2795
+ <div class="amf-drawer-panel"
2796
+ [class.is-open]="isOpen()"
2797
+ [style.width]="config()?.size || '420px'"
2798
+ [class.position-left]="config()?.position === 'left'"
2799
+ (click)="$event.stopPropagation()">
2800
+ @if (isOpen() && config()) {
2801
+ <div class="amf-drawer-header">
2802
+ <h3>{{ config()?.title }}</h3>
2803
+ <button class="amf-drawer-close" (click)="close()" aria-label="Close drawer">&times;</button>
2804
+ </div>
2805
+ <div class="amf-drawer-content">
2806
+ @if (config()?.content) {
2807
+ <amf-renderer [section]="config()!.content" [context]="{}"></amf-renderer>
2808
+ }
2809
+ </div>
2810
+ @if (config()?.actions?.length) {
2811
+ <div class="amf-drawer-footer">
2812
+ @for (action of config()!.actions; track action.label) {
2813
+ <button [class]="'btn-' + (action.color || 'primary')" (click)="dispatchAction(action.action)">
2814
+ {{ action.label }}
2815
+ </button>
2816
+ }
2817
+ </div>
2818
+ }
2819
+ }
2820
+ </div>
2821
2821
  `, styles: [".amf-drawer-backdrop{position:fixed;inset:0;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1200;animation:fadeIn .25s ease-out}.amf-drawer-panel{position:fixed;top:0;right:0;height:100%;max-width:95vw;background:var(--glass-bg, rgba(15, 20, 40, .97));border-left:1px solid var(--app-border, rgba(255,255,255,.08));box-shadow:-20px 0 60px #00000080;z-index:1201;display:flex;flex-direction:column;transform:translate(100%);transition:transform .35s cubic-bezier(.16,1,.3,1);will-change:transform;overflow:hidden}.amf-drawer-panel.position-left{right:auto;left:0;border-left:none;border-right:1px solid var(--app-border, rgba(255,255,255,.08));transform:translate(-100%)}.amf-drawer-panel.is-open{transform:translate(0)}.amf-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid var(--app-border, rgba(255,255,255,.08));flex-shrink:0}.amf-drawer-header h3{margin:0;font-size:1.125rem;font-weight:700;color:var(--app-text, #f1f5f9);letter-spacing:-.01em}.amf-drawer-close{background:#ffffff0f;border:1px solid rgba(255,255,255,.08);color:var(--app-text-muted, #94a3b8);font-size:1.25rem;line-height:1;width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;flex-shrink:0}.amf-drawer-close:hover{background:#ffffff1f;color:var(--app-text, #f1f5f9)}.amf-drawer-content{flex:1;overflow-y:auto;padding:24px}.amf-drawer-footer{flex-shrink:0;padding:16px 24px;border-top:1px solid var(--app-border, rgba(255,255,255,.08));display:flex;justify-content:flex-end;gap:12px;background:#00000026}.btn-primary{background:linear-gradient(135deg,var(--app-primary, #6366f1),var(--app-accent, #c084fc));color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600;transition:all .2s}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 6px 20px var(--app-glow)}.btn-outline{background:transparent;border:1px solid #475569;color:#e2e8f0;padding:10px 20px;border-radius:8px;cursor:pointer;font-weight:600;transition:all .2s}.btn-outline:hover{background:#ffffff0f}.btn-danger{background:#ef4444;color:#fff;padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:600}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"] }]
2822
2822
  }] });
2823
2823
 
@@ -3148,118 +3148,118 @@ class RepeaterFieldComponent {
3148
3148
  this.formArray.removeAt(index);
3149
3149
  }
3150
3150
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RepeaterFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3151
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: RepeaterFieldComponent, isStandalone: true, selector: "amf-repeater-field", inputs: { field: "field", formArray: "formArray", formDisabled: "formDisabled", actionDispatcher: "actionDispatcher", context: "context" }, ngImport: i0, template: `
3152
- <div class="amf-repeater" [class]="field.cssClass">
3153
- <!-- ── Header & Global Add ── -->
3154
- <div class="repeater-header">
3155
- <label class="repeater-label">{{ field.label }}</label>
3156
- @if (canAdd) {
3157
- <button type="button" class="btn-repeater-add" (click)="addItem()" [disabled]="formDisabled">
3158
- <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3159
- {{ field.addLabel || 'Add Item' }}
3160
- </button>
3161
- }
3162
- </div>
3163
-
3164
- @if (field.description) {
3165
- <p class="repeater-description">{{ field.description }}</p>
3166
- }
3167
-
3168
- <div class="repeater-list">
3169
- @for (ctrl of formArray.controls; track $index) {
3170
- <div class="repeater-item-card">
3171
- <div class="repeater-item-header">
3172
- <span class="item-title">Item {{ $index + 1 }}</span>
3173
- @if (canRemove) {
3174
- <button type="button" class="btn-repeater-remove" (click)="removeItem($index)" [disabled]="formDisabled" title="Remove Item">
3175
- <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.12-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/></svg>
3176
- </button>
3177
- }
3178
- </div>
3179
-
3180
- <div class="repeater-item-body">
3181
- <div class="repeater-fields-grid" [style.grid-template-columns]="getGridStyle(field)">
3182
- @for (child of field.children || []; track child.key) {
3183
- <amf-field-renderer
3184
- [field]="child"
3185
- [form]="getFormGroup(ctrl)"
3186
- [formDisabled]="formDisabled"
3187
- [actionDispatcher]="actionDispatcher"
3188
- [context]="context"
3189
- [style.grid-column]="child.colSpan ? 'span ' + child.colSpan : null">
3190
- </amf-field-renderer>
3191
- }
3192
- </div>
3193
- </div>
3194
- </div>
3195
- }
3196
-
3197
- @if (formArray.controls.length === 0) {
3198
- <div class="repeater-empty-state">
3199
- <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3200
- <p>No items added yet. Click "{{ field.addLabel || 'Add Item' }}" to begin.</p>
3201
- </div>
3202
- }
3203
- </div>
3204
- </div>
3151
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: RepeaterFieldComponent, isStandalone: true, selector: "amf-repeater-field", inputs: { field: "field", formArray: "formArray", formDisabled: "formDisabled", actionDispatcher: "actionDispatcher", context: "context" }, ngImport: i0, template: `
3152
+ <div class="amf-repeater" [class]="field.cssClass">
3153
+ <!-- ── Header & Global Add ── -->
3154
+ <div class="repeater-header">
3155
+ <label class="repeater-label">{{ field.label }}</label>
3156
+ @if (canAdd) {
3157
+ <button type="button" class="btn-repeater-add" (click)="addItem()" [disabled]="formDisabled">
3158
+ <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3159
+ {{ field.addLabel || 'Add Item' }}
3160
+ </button>
3161
+ }
3162
+ </div>
3163
+
3164
+ @if (field.description) {
3165
+ <p class="repeater-description">{{ field.description }}</p>
3166
+ }
3167
+
3168
+ <div class="repeater-list">
3169
+ @for (ctrl of formArray.controls; track $index) {
3170
+ <div class="repeater-item-card">
3171
+ <div class="repeater-item-header">
3172
+ <span class="item-title">Item {{ $index + 1 }}</span>
3173
+ @if (canRemove) {
3174
+ <button type="button" class="btn-repeater-remove" (click)="removeItem($index)" [disabled]="formDisabled" title="Remove Item">
3175
+ <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.12-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/></svg>
3176
+ </button>
3177
+ }
3178
+ </div>
3179
+
3180
+ <div class="repeater-item-body">
3181
+ <div class="repeater-fields-grid" [style.grid-template-columns]="getGridStyle(field)">
3182
+ @for (child of field.children || []; track child.key) {
3183
+ <amf-field-renderer
3184
+ [field]="child"
3185
+ [form]="getFormGroup(ctrl)"
3186
+ [formDisabled]="formDisabled"
3187
+ [actionDispatcher]="actionDispatcher"
3188
+ [context]="context"
3189
+ [style.grid-column]="child.colSpan ? 'span ' + child.colSpan : null">
3190
+ </amf-field-renderer>
3191
+ }
3192
+ </div>
3193
+ </div>
3194
+ </div>
3195
+ }
3196
+
3197
+ @if (formArray.controls.length === 0) {
3198
+ <div class="repeater-empty-state">
3199
+ <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3200
+ <p>No items added yet. Click "{{ field.addLabel || 'Add Item' }}" to begin.</p>
3201
+ </div>
3202
+ }
3203
+ </div>
3204
+ </div>
3205
3205
  `, isInline: true, styles: [".amf-repeater{margin-bottom:24px}.repeater-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.repeater-label{font-size:.9375rem;font-weight:600;color:var(--app-text);margin:0}.repeater-description{font-size:.8125rem;color:var(--app-text-muted);margin:0 0 16px}.btn-repeater-add{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;font-size:.8125rem;font-weight:500;font-family:inherit;cursor:pointer;border:1px solid rgba(59,130,246,.3);border-radius:6px;background:#3b82f61a;color:#3b82f6;transition:all .2s}.btn-repeater-add svg{width:14px;height:14px;fill:currentColor}.btn-repeater-add:hover:not(:disabled){background:#3b82f633}.btn-repeater-add:disabled{opacity:.5;cursor:not-allowed}.repeater-list{display:flex;flex-direction:column;gap:16px}.repeater-item-card{background:var(--app-surface-hover);border:1px solid var(--app-border);border-radius:8px;overflow:hidden;transition:box-shadow .2s}.repeater-item-card:hover{border-color:#3b82f64d}.repeater-item-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--app-border);background:#00000005}:host-context(body.amf-dark) .repeater-item-header{background:#ffffff05}.item-title{font-size:.8125rem;font-weight:600;color:var(--app-text);text-transform:uppercase;letter-spacing:.5px}.btn-repeater-remove{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:4px;background:transparent;color:#ef4444;cursor:pointer;transition:background .2s}.btn-repeater-remove svg{width:18px;height:18px;fill:currentColor}.btn-repeater-remove:hover:not(:disabled){background:#ef44441a}.btn-repeater-remove:disabled{opacity:.5;cursor:not-allowed}.repeater-item-body{padding:16px}.repeater-fields-grid{display:grid;gap:16px}.repeater-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px 16px;text-align:center;border:1.5px dashed var(--app-border);border-radius:8px;color:var(--app-text-muted);background:var(--app-surface-hover)}.repeater-empty-state svg{width:32px;height:32px;fill:currentColor;opacity:.5;margin-bottom:12px}.repeater-empty-state p{font-size:.875rem;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "component", type: i0.forwardRef(() => FieldRendererComponent), selector: "amf-field-renderer", inputs: ["field", "form", "formDisabled", "actionDispatcher", "context"] }] });
3206
3206
  }
3207
3207
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RepeaterFieldComponent, decorators: [{
3208
3208
  type: Component,
3209
- args: [{ selector: 'amf-repeater-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => FieldRendererComponent)], template: `
3210
- <div class="amf-repeater" [class]="field.cssClass">
3211
- <!-- ── Header & Global Add ── -->
3212
- <div class="repeater-header">
3213
- <label class="repeater-label">{{ field.label }}</label>
3214
- @if (canAdd) {
3215
- <button type="button" class="btn-repeater-add" (click)="addItem()" [disabled]="formDisabled">
3216
- <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3217
- {{ field.addLabel || 'Add Item' }}
3218
- </button>
3219
- }
3220
- </div>
3221
-
3222
- @if (field.description) {
3223
- <p class="repeater-description">{{ field.description }}</p>
3224
- }
3225
-
3226
- <div class="repeater-list">
3227
- @for (ctrl of formArray.controls; track $index) {
3228
- <div class="repeater-item-card">
3229
- <div class="repeater-item-header">
3230
- <span class="item-title">Item {{ $index + 1 }}</span>
3231
- @if (canRemove) {
3232
- <button type="button" class="btn-repeater-remove" (click)="removeItem($index)" [disabled]="formDisabled" title="Remove Item">
3233
- <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.12-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/></svg>
3234
- </button>
3235
- }
3236
- </div>
3237
-
3238
- <div class="repeater-item-body">
3239
- <div class="repeater-fields-grid" [style.grid-template-columns]="getGridStyle(field)">
3240
- @for (child of field.children || []; track child.key) {
3241
- <amf-field-renderer
3242
- [field]="child"
3243
- [form]="getFormGroup(ctrl)"
3244
- [formDisabled]="formDisabled"
3245
- [actionDispatcher]="actionDispatcher"
3246
- [context]="context"
3247
- [style.grid-column]="child.colSpan ? 'span ' + child.colSpan : null">
3248
- </amf-field-renderer>
3249
- }
3250
- </div>
3251
- </div>
3252
- </div>
3253
- }
3254
-
3255
- @if (formArray.controls.length === 0) {
3256
- <div class="repeater-empty-state">
3257
- <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3258
- <p>No items added yet. Click "{{ field.addLabel || 'Add Item' }}" to begin.</p>
3259
- </div>
3260
- }
3261
- </div>
3262
- </div>
3209
+ args: [{ selector: 'amf-repeater-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => FieldRendererComponent)], template: `
3210
+ <div class="amf-repeater" [class]="field.cssClass">
3211
+ <!-- ── Header & Global Add ── -->
3212
+ <div class="repeater-header">
3213
+ <label class="repeater-label">{{ field.label }}</label>
3214
+ @if (canAdd) {
3215
+ <button type="button" class="btn-repeater-add" (click)="addItem()" [disabled]="formDisabled">
3216
+ <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3217
+ {{ field.addLabel || 'Add Item' }}
3218
+ </button>
3219
+ }
3220
+ </div>
3221
+
3222
+ @if (field.description) {
3223
+ <p class="repeater-description">{{ field.description }}</p>
3224
+ }
3225
+
3226
+ <div class="repeater-list">
3227
+ @for (ctrl of formArray.controls; track $index) {
3228
+ <div class="repeater-item-card">
3229
+ <div class="repeater-item-header">
3230
+ <span class="item-title">Item {{ $index + 1 }}</span>
3231
+ @if (canRemove) {
3232
+ <button type="button" class="btn-repeater-remove" (click)="removeItem($index)" [disabled]="formDisabled" title="Remove Item">
3233
+ <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.12-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/></svg>
3234
+ </button>
3235
+ }
3236
+ </div>
3237
+
3238
+ <div class="repeater-item-body">
3239
+ <div class="repeater-fields-grid" [style.grid-template-columns]="getGridStyle(field)">
3240
+ @for (child of field.children || []; track child.key) {
3241
+ <amf-field-renderer
3242
+ [field]="child"
3243
+ [form]="getFormGroup(ctrl)"
3244
+ [formDisabled]="formDisabled"
3245
+ [actionDispatcher]="actionDispatcher"
3246
+ [context]="context"
3247
+ [style.grid-column]="child.colSpan ? 'span ' + child.colSpan : null">
3248
+ </amf-field-renderer>
3249
+ }
3250
+ </div>
3251
+ </div>
3252
+ </div>
3253
+ }
3254
+
3255
+ @if (formArray.controls.length === 0) {
3256
+ <div class="repeater-empty-state">
3257
+ <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
3258
+ <p>No items added yet. Click "{{ field.addLabel || 'Add Item' }}" to begin.</p>
3259
+ </div>
3260
+ }
3261
+ </div>
3262
+ </div>
3263
3263
  `, styles: [".amf-repeater{margin-bottom:24px}.repeater-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.repeater-label{font-size:.9375rem;font-weight:600;color:var(--app-text);margin:0}.repeater-description{font-size:.8125rem;color:var(--app-text-muted);margin:0 0 16px}.btn-repeater-add{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;font-size:.8125rem;font-weight:500;font-family:inherit;cursor:pointer;border:1px solid rgba(59,130,246,.3);border-radius:6px;background:#3b82f61a;color:#3b82f6;transition:all .2s}.btn-repeater-add svg{width:14px;height:14px;fill:currentColor}.btn-repeater-add:hover:not(:disabled){background:#3b82f633}.btn-repeater-add:disabled{opacity:.5;cursor:not-allowed}.repeater-list{display:flex;flex-direction:column;gap:16px}.repeater-item-card{background:var(--app-surface-hover);border:1px solid var(--app-border);border-radius:8px;overflow:hidden;transition:box-shadow .2s}.repeater-item-card:hover{border-color:#3b82f64d}.repeater-item-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--app-border);background:#00000005}:host-context(body.amf-dark) .repeater-item-header{background:#ffffff05}.item-title{font-size:.8125rem;font-weight:600;color:var(--app-text);text-transform:uppercase;letter-spacing:.5px}.btn-repeater-remove{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:4px;background:transparent;color:#ef4444;cursor:pointer;transition:background .2s}.btn-repeater-remove svg{width:18px;height:18px;fill:currentColor}.btn-repeater-remove:hover:not(:disabled){background:#ef44441a}.btn-repeater-remove:disabled{opacity:.5;cursor:not-allowed}.repeater-item-body{padding:16px}.repeater-fields-grid{display:grid;gap:16px}.repeater-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px 16px;text-align:center;border:1.5px dashed var(--app-border);border-radius:8px;color:var(--app-text-muted);background:var(--app-surface-hover)}.repeater-empty-state svg{width:32px;height:32px;fill:currentColor;opacity:.5;margin-bottom:12px}.repeater-empty-state p{font-size:.875rem;margin:0}\n"] }]
3264
3264
  }], propDecorators: { field: [{
3265
3265
  type: Input
@@ -3389,230 +3389,230 @@ class FieldRendererComponent {
3389
3389
  }
3390
3390
  }
3391
3391
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FieldRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3392
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FieldRendererComponent, isStandalone: true, selector: "amf-field-renderer", inputs: { field: "field", form: "form", formDisabled: "formDisabled", actionDispatcher: "actionDispatcher", context: "context" }, ngImport: i0, template: `
3393
- @if (field.type !== 'hidden') {
3394
- <div class="amf-field" [class]="field.cssClass" [class.has-error]="hasError" [class.field-disabled]="isFieldDisabled">
3395
- @if (field.type === 'heading') { <h3 class="field-heading">{{ field.text || field.label }}</h3> }
3396
- @else if (field.type === 'divider') { <hr class="field-divider" /> }
3397
- @else {
3398
- @if (field.label && field.type !== 'repeater') { <label class="field-label" [for]="field.key">{{ field.label }} @if (isRequired) { <span class="required-mark">*</span> } </label> }
3399
- <div class="field-input-wrapper" [class.has-prefix]="!!field.prefix" [class.has-suffix]="!!field.suffix">
3400
- @if (field.prefix) { <span class="field-prefix">{{ field.prefix }}</span> }
3401
- @switch (field.type) {
3402
- @case ('button') {
3403
- <button type="button" class="field-button" [class]="'btn-' + (field.color || 'primary')" [disabled]="isFieldDisabled" (click)="handleButtonClick()">
3404
- {{ field.label }}
3405
- </button>
3406
- }
3407
- @case ('textarea') { <textarea class="field-input field-textarea" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [rows]="field.rows || 3" [readOnly]="field.readOnly || false"></textarea> }
3408
- @case ('select') {
3409
- <select class="field-input field-select" [id]="field.key" [formControl]="control">
3410
- <option value="" disabled>{{ field.placeholder || 'Select...' }}</option>
3411
- @for (opt of field.options || []; track opt.value) { <option [value]="opt.value" [disabled]="opt.disabled || false">{{ opt.label }}</option> }
3412
- </select>
3413
- }
3414
- @case ('checkbox') {
3415
- <label class="field-checkbox-label"><input type="checkbox" class="field-checkbox" [id]="field.key" [formControl]="control" /><span>{{ field.placeholder || field.label }}</span></label>
3416
- }
3417
- @case ('toggle') {
3418
- <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3419
- }
3420
- @case ('switch') {
3421
- <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3422
- }
3423
- @case ('radio') {
3424
- <div class="field-radio-group">
3425
- @for (opt of field.options || []; track opt.value) {
3426
- <label class="field-radio-label"><input type="radio" [name]="field.key" [value]="opt.value" [formControl]="control" [attr.disabled]="opt.disabled ? '' : null" /><span>{{ opt.label }}</span></label>
3427
- }
3428
- </div>
3429
- }
3430
- @case ('otp') {
3431
- <div class="field-otp-group">
3432
- @for (val of otpArray; track $index) {
3433
- <input class="field-input otp-digit" type="text" inputmode="numeric" [value]="val" (input)="onOtpInput($event, $index)" (keydown)="onOtpKeydown($event, $index)" [disabled]="isFieldDisabled" placeholder="•" />
3434
- }
3435
- </div>
3436
- }
3437
- @case ('repeater') {
3438
- <amf-repeater-field
3439
- [field]="field"
3440
- [formArray]="getFormArray(field.key)"
3441
- [formDisabled]="isFieldDisabled"
3442
- [actionDispatcher]="actionDispatcher"
3443
- [context]="context">
3444
- </amf-repeater-field>
3445
- }
3446
- @case ('password') {
3447
- <div class="password-wrapper">
3448
- <input
3449
- class="field-input password-input"
3450
- [type]="showPassword() ? 'text' : 'password'"
3451
- [id]="field.key"
3452
- [formControl]="control"
3453
- [placeholder]="field.placeholder || ''"
3454
- [readOnly]="field.readOnly || false"
3455
- [attr.autocomplete]="field.autocomplete" />
3456
- <button
3457
- type="button"
3458
- class="pwd-toggle-btn"
3459
- [attr.aria-label]="showPassword() ? 'Hide password' : 'Show password'"
3460
- (click)="togglePasswordVisibility()">
3461
- @if (showPassword()) {
3462
- <!-- Eye-slash: password visible -->
3463
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3464
- <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/>
3465
- <path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>
3466
- <line x1="1" y1="1" x2="23" y2="23"/>
3467
- </svg>
3468
- } @else {
3469
- <!-- Eye: password hidden -->
3470
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3471
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
3472
- <circle cx="12" cy="12" r="3"/>
3473
- </svg>
3474
- }
3475
- </button>
3476
- </div>
3477
- }
3478
- @case ('currency') {
3479
- <div class="currency-wrapper">
3480
- <span class="currency-symbol">{{ currencySymbol }}</span>
3481
- <input
3482
- class="field-input currency-input"
3483
- type="text"
3484
- inputmode="decimal"
3485
- [id]="field.key"
3486
- [value]="formattedCurrencyValue"
3487
- [placeholder]="field.placeholder || '0.00'"
3488
- [disabled]="isFieldDisabled"
3489
- (input)="onCurrencyInput($event)"
3490
- (blur)="onCurrencyBlur($event)" />
3491
- </div>
3492
- }
3493
- @default { <input class="field-input" [type]="field.type" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [readOnly]="field.readOnly || false" [attr.min]="field.min" [attr.max]="field.max" [attr.step]="field.step" [attr.accept]="field.accept" [attr.multiple]="field.multiple ? '' : null" [attr.autocomplete]="field.autocomplete" /> }
3494
- }
3495
- @if (field.suffix) { <span class="field-suffix">{{ field.suffix }}</span> }
3496
- </div>
3497
- @if (field.hint && !hasError) { <span class="field-hint">{{ field.hint }}</span> }
3498
- @if (hasError) { <span class="field-error">{{ errorMessage }}</span> }
3499
- }
3500
- </div>
3501
- }
3392
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FieldRendererComponent, isStandalone: true, selector: "amf-field-renderer", inputs: { field: "field", form: "form", formDisabled: "formDisabled", actionDispatcher: "actionDispatcher", context: "context" }, ngImport: i0, template: `
3393
+ @if (field.type !== 'hidden') {
3394
+ <div class="amf-field" [class]="field.cssClass" [class.has-error]="hasError" [class.field-disabled]="isFieldDisabled">
3395
+ @if (field.type === 'heading') { <h3 class="field-heading">{{ field.text || field.label }}</h3> }
3396
+ @else if (field.type === 'divider') { <hr class="field-divider" /> }
3397
+ @else {
3398
+ @if (field.label && field.type !== 'repeater') { <label class="field-label" [for]="field.key">{{ field.label }} @if (isRequired) { <span class="required-mark">*</span> } </label> }
3399
+ <div class="field-input-wrapper" [class.has-prefix]="!!field.prefix" [class.has-suffix]="!!field.suffix">
3400
+ @if (field.prefix) { <span class="field-prefix">{{ field.prefix }}</span> }
3401
+ @switch (field.type) {
3402
+ @case ('button') {
3403
+ <button type="button" class="field-button" [class]="'btn-' + (field.color || 'primary')" [disabled]="isFieldDisabled" (click)="handleButtonClick()">
3404
+ {{ field.label }}
3405
+ </button>
3406
+ }
3407
+ @case ('textarea') { <textarea class="field-input field-textarea" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [rows]="field.rows || 3" [readOnly]="field.readOnly || false"></textarea> }
3408
+ @case ('select') {
3409
+ <select class="field-input field-select" [id]="field.key" [formControl]="control">
3410
+ <option value="" disabled>{{ field.placeholder || 'Select...' }}</option>
3411
+ @for (opt of field.options || []; track opt.value) { <option [value]="opt.value" [disabled]="opt.disabled || false">{{ opt.label }}</option> }
3412
+ </select>
3413
+ }
3414
+ @case ('checkbox') {
3415
+ <label class="field-checkbox-label"><input type="checkbox" class="field-checkbox" [id]="field.key" [formControl]="control" /><span>{{ field.placeholder || field.label }}</span></label>
3416
+ }
3417
+ @case ('toggle') {
3418
+ <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3419
+ }
3420
+ @case ('switch') {
3421
+ <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3422
+ }
3423
+ @case ('radio') {
3424
+ <div class="field-radio-group">
3425
+ @for (opt of field.options || []; track opt.value) {
3426
+ <label class="field-radio-label"><input type="radio" [name]="field.key" [value]="opt.value" [formControl]="control" [attr.disabled]="opt.disabled ? '' : null" /><span>{{ opt.label }}</span></label>
3427
+ }
3428
+ </div>
3429
+ }
3430
+ @case ('otp') {
3431
+ <div class="field-otp-group">
3432
+ @for (val of otpArray; track $index) {
3433
+ <input class="field-input otp-digit" type="text" inputmode="numeric" [value]="val" (input)="onOtpInput($event, $index)" (keydown)="onOtpKeydown($event, $index)" [disabled]="isFieldDisabled" placeholder="•" />
3434
+ }
3435
+ </div>
3436
+ }
3437
+ @case ('repeater') {
3438
+ <amf-repeater-field
3439
+ [field]="field"
3440
+ [formArray]="getFormArray(field.key)"
3441
+ [formDisabled]="isFieldDisabled"
3442
+ [actionDispatcher]="actionDispatcher"
3443
+ [context]="context">
3444
+ </amf-repeater-field>
3445
+ }
3446
+ @case ('password') {
3447
+ <div class="password-wrapper">
3448
+ <input
3449
+ class="field-input password-input"
3450
+ [type]="showPassword() ? 'text' : 'password'"
3451
+ [id]="field.key"
3452
+ [formControl]="control"
3453
+ [placeholder]="field.placeholder || ''"
3454
+ [readOnly]="field.readOnly || false"
3455
+ [attr.autocomplete]="field.autocomplete" />
3456
+ <button
3457
+ type="button"
3458
+ class="pwd-toggle-btn"
3459
+ [attr.aria-label]="showPassword() ? 'Hide password' : 'Show password'"
3460
+ (click)="togglePasswordVisibility()">
3461
+ @if (showPassword()) {
3462
+ <!-- Eye-slash: password visible -->
3463
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3464
+ <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/>
3465
+ <path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>
3466
+ <line x1="1" y1="1" x2="23" y2="23"/>
3467
+ </svg>
3468
+ } @else {
3469
+ <!-- Eye: password hidden -->
3470
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3471
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
3472
+ <circle cx="12" cy="12" r="3"/>
3473
+ </svg>
3474
+ }
3475
+ </button>
3476
+ </div>
3477
+ }
3478
+ @case ('currency') {
3479
+ <div class="currency-wrapper">
3480
+ <span class="currency-symbol">{{ currencySymbol }}</span>
3481
+ <input
3482
+ class="field-input currency-input"
3483
+ type="text"
3484
+ inputmode="decimal"
3485
+ [id]="field.key"
3486
+ [value]="formattedCurrencyValue"
3487
+ [placeholder]="field.placeholder || '0.00'"
3488
+ [disabled]="isFieldDisabled"
3489
+ (input)="onCurrencyInput($event)"
3490
+ (blur)="onCurrencyBlur($event)" />
3491
+ </div>
3492
+ }
3493
+ @default { <input class="field-input" [type]="field.type" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [readOnly]="field.readOnly || false" [attr.min]="field.min" [attr.max]="field.max" [attr.step]="field.step" [attr.accept]="field.accept" [attr.multiple]="field.multiple ? '' : null" [attr.autocomplete]="field.autocomplete" /> }
3494
+ }
3495
+ @if (field.suffix) { <span class="field-suffix">{{ field.suffix }}</span> }
3496
+ </div>
3497
+ @if (field.hint && !hasError) { <span class="field-hint">{{ field.hint }}</span> }
3498
+ @if (hasError) { <span class="field-error">{{ errorMessage }}</span> }
3499
+ }
3500
+ </div>
3501
+ }
3502
3502
  `, isInline: true, styles: [".amf-field{display:flex;flex-direction:column;gap:6px}.amf-field.field-disabled{opacity:.5;pointer-events:none}.field-label{font-size:.875rem;font-weight:600;color:var(--app-text)}.required-mark{color:#f43f5e;margin-left:2px}.field-input-wrapper{display:flex;align-items:stretch;position:relative}.field-prefix,.field-suffix{padding:10px 12px;font-size:.875rem;color:var(--app-text-muted);background:var(--glass-bg);border:1px solid var(--app-border);display:flex;align-items:center;justify-content:center;white-space:nowrap;box-sizing:border-box}.field-prefix{border-right:none;border-radius:8px 0 0 8px}.field-suffix{border-left:none;border-radius:0 8px 8px 0}.field-input{flex:1;width:100%;padding:10px 14px;border:1px solid var(--app-border);border-radius:8px;background:var(--glass-bg);color:var(--app-text);font-size:.875rem;font-family:inherit;outline:none;transition:border-color .2s,box-shadow .2s;box-sizing:border-box}.has-prefix .field-input{border-top-left-radius:0;border-bottom-left-radius:0}.has-suffix .field-input{border-top-right-radius:0;border-bottom-right-radius:0}.field-input:focus{border-color:var(--app-primary);box-shadow:0 0 0 3px var(--app-primary-light);z-index:3;position:relative}.field-input::placeholder{color:var(--app-text-muted);opacity:.6}.field-input[readonly]{opacity:.7;cursor:not-allowed}.field-input:disabled{opacity:.5;cursor:not-allowed}.has-error .field-input{border-color:#f43f5e}.has-error .field-input:focus{box-shadow:0 0 0 3px #f43f5e26}.field-select{appearance:none;cursor:pointer;padding-right:36px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'%3E%3Cpath fill='%2394a3b8' d='M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 12px center;color-scheme:dark}.field-select option{background-color:#1e1e2d;color:#fff}:host-context([data-color-scheme=\"light\"]) .field-select{color-scheme:light}:host-context([data-color-scheme=\"light\"]) .field-select option{background-color:#fff;color:#000}.field-textarea{resize:vertical;min-height:80px}.field-checkbox-label,.field-radio-label{display:flex;align-items:center;gap:8px;font-size:.875rem;color:var(--app-text);cursor:pointer}.field-radio-group{display:flex;flex-direction:column;gap:8px}.field-otp-group{display:flex;gap:8px;justify-content:center;width:100%}.otp-digit{width:44px;height:50px;text-align:center;font-size:1.25rem;font-weight:600;padding:0;letter-spacing:0}.field-toggle-label{display:flex;align-items:center;gap:10px;cursor:pointer}.field-toggle-input{display:none}.field-toggle-track{width:44px;height:24px;background:var(--app-border);border-radius:12px;position:relative;transition:background .2s}.field-toggle-input:checked+.field-toggle-track{background:var(--app-primary)}.field-toggle-thumb{position:absolute;top:2px;left:2px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s}.field-toggle-input:checked+.field-toggle-track .field-toggle-thumb{transform:translate(20px)}.field-toggle-text{font-size:.875rem;color:var(--app-text)}.field-hint{font-size:.75rem;color:var(--app-text-muted)}.field-error{font-size:.75rem;color:#f43f5e;font-weight:500}.field-heading{font-size:1.125rem;margin-top:8px;color:var(--app-text)}.field-divider{border:none;border-top:1px solid var(--app-border);margin:8px 0}.field-button{padding:10px 20px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);border:none;width:100%}.field-button.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff}.field-button.btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.field-button.btn-secondary{background:var(--glass-bg);color:var(--app-text);border:1px solid var(--app-border)}.field-button.btn-secondary:hover:not(:disabled){background:var(--glass-bg-hover);border-color:var(--glass-border-light)}.field-button.btn-outline{background:transparent;color:var(--app-text);border:1px solid var(--app-border)}.field-button.btn-outline:hover:not(:disabled){background:var(--glass-bg-hover)}.field-button.btn-success{background:linear-gradient(135deg,#10b981,#34d399);color:#fff}.field-button.btn-success:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px #10b9814d}.field-button.btn-accent{background:linear-gradient(135deg,var(--app-accent),var(--app-primary));color:#fff}.field-button.btn-accent:hover:not(:disabled){transform:translateY(-2px)}.field-button:disabled{opacity:.5;cursor:not-allowed;transform:none}.password-wrapper{position:relative;display:flex;align-items:stretch;width:100%}.password-input{padding-right:44px!important}.pwd-toggle-btn{position:absolute;right:0;top:0;bottom:0;width:42px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;color:var(--app-text-muted);border-radius:0 8px 8px 0;transition:color .2s;z-index:2}.pwd-toggle-btn:hover{color:var(--app-primary)}.pwd-toggle-btn svg{width:18px;height:18px}.currency-wrapper{display:flex;align-items:stretch;width:100%}.currency-symbol{padding:10px 12px;font-size:.875rem;font-weight:600;color:var(--app-text-muted);background:var(--glass-bg);border:1px solid var(--app-border);border-right:none;border-radius:8px 0 0 8px;display:flex;align-items:center;white-space:nowrap;box-sizing:border-box}.currency-input{border-top-left-radius:0!important;border-bottom-left-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormArrayDirective, selector: "[formArray]", inputs: ["formArray"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: RepeaterFieldComponent, selector: "amf-repeater-field", inputs: ["field", "formArray", "formDisabled", "actionDispatcher", "context"] }] });
3503
3503
  }
3504
3504
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FieldRendererComponent, decorators: [{
3505
3505
  type: Component,
3506
- args: [{ selector: 'amf-field-renderer', standalone: true, imports: [ReactiveFormsModule, RepeaterFieldComponent], template: `
3507
- @if (field.type !== 'hidden') {
3508
- <div class="amf-field" [class]="field.cssClass" [class.has-error]="hasError" [class.field-disabled]="isFieldDisabled">
3509
- @if (field.type === 'heading') { <h3 class="field-heading">{{ field.text || field.label }}</h3> }
3510
- @else if (field.type === 'divider') { <hr class="field-divider" /> }
3511
- @else {
3512
- @if (field.label && field.type !== 'repeater') { <label class="field-label" [for]="field.key">{{ field.label }} @if (isRequired) { <span class="required-mark">*</span> } </label> }
3513
- <div class="field-input-wrapper" [class.has-prefix]="!!field.prefix" [class.has-suffix]="!!field.suffix">
3514
- @if (field.prefix) { <span class="field-prefix">{{ field.prefix }}</span> }
3515
- @switch (field.type) {
3516
- @case ('button') {
3517
- <button type="button" class="field-button" [class]="'btn-' + (field.color || 'primary')" [disabled]="isFieldDisabled" (click)="handleButtonClick()">
3518
- {{ field.label }}
3519
- </button>
3520
- }
3521
- @case ('textarea') { <textarea class="field-input field-textarea" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [rows]="field.rows || 3" [readOnly]="field.readOnly || false"></textarea> }
3522
- @case ('select') {
3523
- <select class="field-input field-select" [id]="field.key" [formControl]="control">
3524
- <option value="" disabled>{{ field.placeholder || 'Select...' }}</option>
3525
- @for (opt of field.options || []; track opt.value) { <option [value]="opt.value" [disabled]="opt.disabled || false">{{ opt.label }}</option> }
3526
- </select>
3527
- }
3528
- @case ('checkbox') {
3529
- <label class="field-checkbox-label"><input type="checkbox" class="field-checkbox" [id]="field.key" [formControl]="control" /><span>{{ field.placeholder || field.label }}</span></label>
3530
- }
3531
- @case ('toggle') {
3532
- <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3533
- }
3534
- @case ('switch') {
3535
- <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3536
- }
3537
- @case ('radio') {
3538
- <div class="field-radio-group">
3539
- @for (opt of field.options || []; track opt.value) {
3540
- <label class="field-radio-label"><input type="radio" [name]="field.key" [value]="opt.value" [formControl]="control" [attr.disabled]="opt.disabled ? '' : null" /><span>{{ opt.label }}</span></label>
3541
- }
3542
- </div>
3543
- }
3544
- @case ('otp') {
3545
- <div class="field-otp-group">
3546
- @for (val of otpArray; track $index) {
3547
- <input class="field-input otp-digit" type="text" inputmode="numeric" [value]="val" (input)="onOtpInput($event, $index)" (keydown)="onOtpKeydown($event, $index)" [disabled]="isFieldDisabled" placeholder="•" />
3548
- }
3549
- </div>
3550
- }
3551
- @case ('repeater') {
3552
- <amf-repeater-field
3553
- [field]="field"
3554
- [formArray]="getFormArray(field.key)"
3555
- [formDisabled]="isFieldDisabled"
3556
- [actionDispatcher]="actionDispatcher"
3557
- [context]="context">
3558
- </amf-repeater-field>
3559
- }
3560
- @case ('password') {
3561
- <div class="password-wrapper">
3562
- <input
3563
- class="field-input password-input"
3564
- [type]="showPassword() ? 'text' : 'password'"
3565
- [id]="field.key"
3566
- [formControl]="control"
3567
- [placeholder]="field.placeholder || ''"
3568
- [readOnly]="field.readOnly || false"
3569
- [attr.autocomplete]="field.autocomplete" />
3570
- <button
3571
- type="button"
3572
- class="pwd-toggle-btn"
3573
- [attr.aria-label]="showPassword() ? 'Hide password' : 'Show password'"
3574
- (click)="togglePasswordVisibility()">
3575
- @if (showPassword()) {
3576
- <!-- Eye-slash: password visible -->
3577
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3578
- <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/>
3579
- <path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>
3580
- <line x1="1" y1="1" x2="23" y2="23"/>
3581
- </svg>
3582
- } @else {
3583
- <!-- Eye: password hidden -->
3584
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3585
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
3586
- <circle cx="12" cy="12" r="3"/>
3587
- </svg>
3588
- }
3589
- </button>
3590
- </div>
3591
- }
3592
- @case ('currency') {
3593
- <div class="currency-wrapper">
3594
- <span class="currency-symbol">{{ currencySymbol }}</span>
3595
- <input
3596
- class="field-input currency-input"
3597
- type="text"
3598
- inputmode="decimal"
3599
- [id]="field.key"
3600
- [value]="formattedCurrencyValue"
3601
- [placeholder]="field.placeholder || '0.00'"
3602
- [disabled]="isFieldDisabled"
3603
- (input)="onCurrencyInput($event)"
3604
- (blur)="onCurrencyBlur($event)" />
3605
- </div>
3606
- }
3607
- @default { <input class="field-input" [type]="field.type" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [readOnly]="field.readOnly || false" [attr.min]="field.min" [attr.max]="field.max" [attr.step]="field.step" [attr.accept]="field.accept" [attr.multiple]="field.multiple ? '' : null" [attr.autocomplete]="field.autocomplete" /> }
3608
- }
3609
- @if (field.suffix) { <span class="field-suffix">{{ field.suffix }}</span> }
3610
- </div>
3611
- @if (field.hint && !hasError) { <span class="field-hint">{{ field.hint }}</span> }
3612
- @if (hasError) { <span class="field-error">{{ errorMessage }}</span> }
3613
- }
3614
- </div>
3615
- }
3506
+ args: [{ selector: 'amf-field-renderer', standalone: true, imports: [ReactiveFormsModule, RepeaterFieldComponent], template: `
3507
+ @if (field.type !== 'hidden') {
3508
+ <div class="amf-field" [class]="field.cssClass" [class.has-error]="hasError" [class.field-disabled]="isFieldDisabled">
3509
+ @if (field.type === 'heading') { <h3 class="field-heading">{{ field.text || field.label }}</h3> }
3510
+ @else if (field.type === 'divider') { <hr class="field-divider" /> }
3511
+ @else {
3512
+ @if (field.label && field.type !== 'repeater') { <label class="field-label" [for]="field.key">{{ field.label }} @if (isRequired) { <span class="required-mark">*</span> } </label> }
3513
+ <div class="field-input-wrapper" [class.has-prefix]="!!field.prefix" [class.has-suffix]="!!field.suffix">
3514
+ @if (field.prefix) { <span class="field-prefix">{{ field.prefix }}</span> }
3515
+ @switch (field.type) {
3516
+ @case ('button') {
3517
+ <button type="button" class="field-button" [class]="'btn-' + (field.color || 'primary')" [disabled]="isFieldDisabled" (click)="handleButtonClick()">
3518
+ {{ field.label }}
3519
+ </button>
3520
+ }
3521
+ @case ('textarea') { <textarea class="field-input field-textarea" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [rows]="field.rows || 3" [readOnly]="field.readOnly || false"></textarea> }
3522
+ @case ('select') {
3523
+ <select class="field-input field-select" [id]="field.key" [formControl]="control">
3524
+ <option value="" disabled>{{ field.placeholder || 'Select...' }}</option>
3525
+ @for (opt of field.options || []; track opt.value) { <option [value]="opt.value" [disabled]="opt.disabled || false">{{ opt.label }}</option> }
3526
+ </select>
3527
+ }
3528
+ @case ('checkbox') {
3529
+ <label class="field-checkbox-label"><input type="checkbox" class="field-checkbox" [id]="field.key" [formControl]="control" /><span>{{ field.placeholder || field.label }}</span></label>
3530
+ }
3531
+ @case ('toggle') {
3532
+ <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3533
+ }
3534
+ @case ('switch') {
3535
+ <label class="field-toggle-label"><input type="checkbox" class="field-toggle-input" [id]="field.key" [formControl]="control" /><span class="field-toggle-track"><span class="field-toggle-thumb"></span></span>@if (field.placeholder) { <span class="field-toggle-text">{{ field.placeholder }}</span> }</label>
3536
+ }
3537
+ @case ('radio') {
3538
+ <div class="field-radio-group">
3539
+ @for (opt of field.options || []; track opt.value) {
3540
+ <label class="field-radio-label"><input type="radio" [name]="field.key" [value]="opt.value" [formControl]="control" [attr.disabled]="opt.disabled ? '' : null" /><span>{{ opt.label }}</span></label>
3541
+ }
3542
+ </div>
3543
+ }
3544
+ @case ('otp') {
3545
+ <div class="field-otp-group">
3546
+ @for (val of otpArray; track $index) {
3547
+ <input class="field-input otp-digit" type="text" inputmode="numeric" [value]="val" (input)="onOtpInput($event, $index)" (keydown)="onOtpKeydown($event, $index)" [disabled]="isFieldDisabled" placeholder="•" />
3548
+ }
3549
+ </div>
3550
+ }
3551
+ @case ('repeater') {
3552
+ <amf-repeater-field
3553
+ [field]="field"
3554
+ [formArray]="getFormArray(field.key)"
3555
+ [formDisabled]="isFieldDisabled"
3556
+ [actionDispatcher]="actionDispatcher"
3557
+ [context]="context">
3558
+ </amf-repeater-field>
3559
+ }
3560
+ @case ('password') {
3561
+ <div class="password-wrapper">
3562
+ <input
3563
+ class="field-input password-input"
3564
+ [type]="showPassword() ? 'text' : 'password'"
3565
+ [id]="field.key"
3566
+ [formControl]="control"
3567
+ [placeholder]="field.placeholder || ''"
3568
+ [readOnly]="field.readOnly || false"
3569
+ [attr.autocomplete]="field.autocomplete" />
3570
+ <button
3571
+ type="button"
3572
+ class="pwd-toggle-btn"
3573
+ [attr.aria-label]="showPassword() ? 'Hide password' : 'Show password'"
3574
+ (click)="togglePasswordVisibility()">
3575
+ @if (showPassword()) {
3576
+ <!-- Eye-slash: password visible -->
3577
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3578
+ <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/>
3579
+ <path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>
3580
+ <line x1="1" y1="1" x2="23" y2="23"/>
3581
+ </svg>
3582
+ } @else {
3583
+ <!-- Eye: password hidden -->
3584
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3585
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
3586
+ <circle cx="12" cy="12" r="3"/>
3587
+ </svg>
3588
+ }
3589
+ </button>
3590
+ </div>
3591
+ }
3592
+ @case ('currency') {
3593
+ <div class="currency-wrapper">
3594
+ <span class="currency-symbol">{{ currencySymbol }}</span>
3595
+ <input
3596
+ class="field-input currency-input"
3597
+ type="text"
3598
+ inputmode="decimal"
3599
+ [id]="field.key"
3600
+ [value]="formattedCurrencyValue"
3601
+ [placeholder]="field.placeholder || '0.00'"
3602
+ [disabled]="isFieldDisabled"
3603
+ (input)="onCurrencyInput($event)"
3604
+ (blur)="onCurrencyBlur($event)" />
3605
+ </div>
3606
+ }
3607
+ @default { <input class="field-input" [type]="field.type" [id]="field.key" [formControl]="control" [placeholder]="field.placeholder || ''" [readOnly]="field.readOnly || false" [attr.min]="field.min" [attr.max]="field.max" [attr.step]="field.step" [attr.accept]="field.accept" [attr.multiple]="field.multiple ? '' : null" [attr.autocomplete]="field.autocomplete" /> }
3608
+ }
3609
+ @if (field.suffix) { <span class="field-suffix">{{ field.suffix }}</span> }
3610
+ </div>
3611
+ @if (field.hint && !hasError) { <span class="field-hint">{{ field.hint }}</span> }
3612
+ @if (hasError) { <span class="field-error">{{ errorMessage }}</span> }
3613
+ }
3614
+ </div>
3615
+ }
3616
3616
  `, styles: [".amf-field{display:flex;flex-direction:column;gap:6px}.amf-field.field-disabled{opacity:.5;pointer-events:none}.field-label{font-size:.875rem;font-weight:600;color:var(--app-text)}.required-mark{color:#f43f5e;margin-left:2px}.field-input-wrapper{display:flex;align-items:stretch;position:relative}.field-prefix,.field-suffix{padding:10px 12px;font-size:.875rem;color:var(--app-text-muted);background:var(--glass-bg);border:1px solid var(--app-border);display:flex;align-items:center;justify-content:center;white-space:nowrap;box-sizing:border-box}.field-prefix{border-right:none;border-radius:8px 0 0 8px}.field-suffix{border-left:none;border-radius:0 8px 8px 0}.field-input{flex:1;width:100%;padding:10px 14px;border:1px solid var(--app-border);border-radius:8px;background:var(--glass-bg);color:var(--app-text);font-size:.875rem;font-family:inherit;outline:none;transition:border-color .2s,box-shadow .2s;box-sizing:border-box}.has-prefix .field-input{border-top-left-radius:0;border-bottom-left-radius:0}.has-suffix .field-input{border-top-right-radius:0;border-bottom-right-radius:0}.field-input:focus{border-color:var(--app-primary);box-shadow:0 0 0 3px var(--app-primary-light);z-index:3;position:relative}.field-input::placeholder{color:var(--app-text-muted);opacity:.6}.field-input[readonly]{opacity:.7;cursor:not-allowed}.field-input:disabled{opacity:.5;cursor:not-allowed}.has-error .field-input{border-color:#f43f5e}.has-error .field-input:focus{box-shadow:0 0 0 3px #f43f5e26}.field-select{appearance:none;cursor:pointer;padding-right:36px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'%3E%3Cpath fill='%2394a3b8' d='M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 12px center;color-scheme:dark}.field-select option{background-color:#1e1e2d;color:#fff}:host-context([data-color-scheme=\"light\"]) .field-select{color-scheme:light}:host-context([data-color-scheme=\"light\"]) .field-select option{background-color:#fff;color:#000}.field-textarea{resize:vertical;min-height:80px}.field-checkbox-label,.field-radio-label{display:flex;align-items:center;gap:8px;font-size:.875rem;color:var(--app-text);cursor:pointer}.field-radio-group{display:flex;flex-direction:column;gap:8px}.field-otp-group{display:flex;gap:8px;justify-content:center;width:100%}.otp-digit{width:44px;height:50px;text-align:center;font-size:1.25rem;font-weight:600;padding:0;letter-spacing:0}.field-toggle-label{display:flex;align-items:center;gap:10px;cursor:pointer}.field-toggle-input{display:none}.field-toggle-track{width:44px;height:24px;background:var(--app-border);border-radius:12px;position:relative;transition:background .2s}.field-toggle-input:checked+.field-toggle-track{background:var(--app-primary)}.field-toggle-thumb{position:absolute;top:2px;left:2px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s}.field-toggle-input:checked+.field-toggle-track .field-toggle-thumb{transform:translate(20px)}.field-toggle-text{font-size:.875rem;color:var(--app-text)}.field-hint{font-size:.75rem;color:var(--app-text-muted)}.field-error{font-size:.75rem;color:#f43f5e;font-weight:500}.field-heading{font-size:1.125rem;margin-top:8px;color:var(--app-text)}.field-divider{border:none;border-top:1px solid var(--app-border);margin:8px 0}.field-button{padding:10px 20px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);border:none;width:100%}.field-button.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff}.field-button.btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.field-button.btn-secondary{background:var(--glass-bg);color:var(--app-text);border:1px solid var(--app-border)}.field-button.btn-secondary:hover:not(:disabled){background:var(--glass-bg-hover);border-color:var(--glass-border-light)}.field-button.btn-outline{background:transparent;color:var(--app-text);border:1px solid var(--app-border)}.field-button.btn-outline:hover:not(:disabled){background:var(--glass-bg-hover)}.field-button.btn-success{background:linear-gradient(135deg,#10b981,#34d399);color:#fff}.field-button.btn-success:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px #10b9814d}.field-button.btn-accent{background:linear-gradient(135deg,var(--app-accent),var(--app-primary));color:#fff}.field-button.btn-accent:hover:not(:disabled){transform:translateY(-2px)}.field-button:disabled{opacity:.5;cursor:not-allowed;transform:none}.password-wrapper{position:relative;display:flex;align-items:stretch;width:100%}.password-input{padding-right:44px!important}.pwd-toggle-btn{position:absolute;right:0;top:0;bottom:0;width:42px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;color:var(--app-text-muted);border-radius:0 8px 8px 0;transition:color .2s;z-index:2}.pwd-toggle-btn:hover{color:var(--app-primary)}.pwd-toggle-btn svg{width:18px;height:18px}.currency-wrapper{display:flex;align-items:stretch;width:100%}.currency-symbol{padding:10px 12px;font-size:.875rem;font-weight:600;color:var(--app-text-muted);background:var(--glass-bg);border:1px solid var(--app-border);border-right:none;border-radius:8px 0 0 8px;display:flex;align-items:center;white-space:nowrap;box-sizing:border-box}.currency-input{border-top-left-radius:0!important;border-bottom-left-radius:0!important}\n"] }]
3617
3617
  }], propDecorators: { field: [{
3618
3618
  type: Input
@@ -3758,40 +3758,40 @@ class FormRendererComponent {
3758
3758
  }
3759
3759
  markAllTouched() { Object.values(this.formGroup.controls).forEach(c => c.markAsTouched()); }
3760
3760
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3761
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FormRendererComponent, isStandalone: true, selector: "amf-form-renderer", inputs: { config: "config", context: "context" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formChange: "formChange" }, usesOnChanges: true, ngImport: i0, template: `
3762
- <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="amf-form" [class]="config.cssClass" [class.form-disabled]="config.disabled">
3763
- <div class="amf-form-fields" [class]="layoutClass" [style.grid-template-columns]="gridColumns">
3764
- @for (field of visibleFields; track field.key) {
3765
- <amf-field-renderer [field]="field" [form]="formGroup" [formDisabled]="!!config.disabled" [actionDispatcher]="actionDispatcher" [context]="context" [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null"></amf-field-renderer>
3766
- }
3767
- </div>
3768
- @if (!config.hideSubmit) {
3769
- <div class="amf-form-actions">
3770
- @if (config.showCancel) { <button type="button" class="btn-secondary" (click)="handleCancel()" [disabled]="config.disabled">{{ config.cancelLabel || 'Cancel' }}</button> }
3771
- @if (config.showReset) { <button type="button" class="btn-secondary" (click)="formGroup.reset()" [disabled]="config.disabled">Reset</button> }
3772
- <button type="submit" class="btn-primary" [disabled]="formGroup.invalid || config.disabled">{{ config.submitLabel || 'Submit' }}</button>
3773
- </div>
3774
- }
3775
- </form>
3761
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FormRendererComponent, isStandalone: true, selector: "amf-form-renderer", inputs: { config: "config", context: "context" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formChange: "formChange" }, usesOnChanges: true, ngImport: i0, template: `
3762
+ <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="amf-form" [class]="config.cssClass" [class.form-disabled]="config.disabled">
3763
+ <div class="amf-form-fields" [class]="layoutClass" [style.grid-template-columns]="gridColumns">
3764
+ @for (field of visibleFields; track field.key) {
3765
+ <amf-field-renderer [field]="field" [form]="formGroup" [formDisabled]="!!config.disabled" [actionDispatcher]="actionDispatcher" [context]="context" [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null"></amf-field-renderer>
3766
+ }
3767
+ </div>
3768
+ @if (!config.hideSubmit) {
3769
+ <div class="amf-form-actions">
3770
+ @if (config.showCancel) { <button type="button" class="btn-secondary" (click)="handleCancel()" [disabled]="config.disabled">{{ config.cancelLabel || 'Cancel' }}</button> }
3771
+ @if (config.showReset) { <button type="button" class="btn-secondary" (click)="formGroup.reset()" [disabled]="config.disabled">Reset</button> }
3772
+ <button type="submit" class="btn-primary" [disabled]="formGroup.invalid || config.disabled">{{ config.submitLabel || 'Submit' }}</button>
3773
+ </div>
3774
+ }
3775
+ </form>
3776
3776
  `, isInline: true, styles: [".amf-form{display:flex;flex-direction:column;gap:24px}.amf-form.form-disabled{opacity:.6;pointer-events:none}.amf-form-fields{display:flex;flex-direction:column;gap:20px}.amf-form-fields.layout-grid{display:grid;gap:20px}.amf-form-fields.layout-horizontal{flex-direction:row;flex-wrap:wrap;gap:16px}.amf-form-fields.layout-horizontal>*{flex:1;min-width:200px}.amf-form-fields.layout-inline{flex-direction:row;align-items:flex-end;gap:12px}.amf-form-actions{display:flex;justify-content:flex-end;gap:12px;padding-top:8px;border-top:1px solid var(--app-border)}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:var(--app-on-primary, #fff);border:none;padding:10px 24px;border-radius:10px;font-weight:600;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1)}.btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.btn-primary:disabled{opacity:.5;cursor:not-allowed;transform:none}.btn-secondary{background:var(--glass-bg);color:var(--app-text);border:1px solid var(--app-border);padding:10px 24px;border-radius:10px;font-weight:600;cursor:pointer;transition:all .2s}.btn-secondary:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FieldRendererComponent, selector: "amf-field-renderer", inputs: ["field", "form", "formDisabled", "actionDispatcher", "context"] }] });
3777
3777
  }
3778
3778
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormRendererComponent, decorators: [{
3779
3779
  type: Component,
3780
- args: [{ selector: 'amf-form-renderer', standalone: true, imports: [ReactiveFormsModule, FieldRendererComponent], template: `
3781
- <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="amf-form" [class]="config.cssClass" [class.form-disabled]="config.disabled">
3782
- <div class="amf-form-fields" [class]="layoutClass" [style.grid-template-columns]="gridColumns">
3783
- @for (field of visibleFields; track field.key) {
3784
- <amf-field-renderer [field]="field" [form]="formGroup" [formDisabled]="!!config.disabled" [actionDispatcher]="actionDispatcher" [context]="context" [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null"></amf-field-renderer>
3785
- }
3786
- </div>
3787
- @if (!config.hideSubmit) {
3788
- <div class="amf-form-actions">
3789
- @if (config.showCancel) { <button type="button" class="btn-secondary" (click)="handleCancel()" [disabled]="config.disabled">{{ config.cancelLabel || 'Cancel' }}</button> }
3790
- @if (config.showReset) { <button type="button" class="btn-secondary" (click)="formGroup.reset()" [disabled]="config.disabled">Reset</button> }
3791
- <button type="submit" class="btn-primary" [disabled]="formGroup.invalid || config.disabled">{{ config.submitLabel || 'Submit' }}</button>
3792
- </div>
3793
- }
3794
- </form>
3780
+ args: [{ selector: 'amf-form-renderer', standalone: true, imports: [ReactiveFormsModule, FieldRendererComponent], template: `
3781
+ <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="amf-form" [class]="config.cssClass" [class.form-disabled]="config.disabled">
3782
+ <div class="amf-form-fields" [class]="layoutClass" [style.grid-template-columns]="gridColumns">
3783
+ @for (field of visibleFields; track field.key) {
3784
+ <amf-field-renderer [field]="field" [form]="formGroup" [formDisabled]="!!config.disabled" [actionDispatcher]="actionDispatcher" [context]="context" [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null"></amf-field-renderer>
3785
+ }
3786
+ </div>
3787
+ @if (!config.hideSubmit) {
3788
+ <div class="amf-form-actions">
3789
+ @if (config.showCancel) { <button type="button" class="btn-secondary" (click)="handleCancel()" [disabled]="config.disabled">{{ config.cancelLabel || 'Cancel' }}</button> }
3790
+ @if (config.showReset) { <button type="button" class="btn-secondary" (click)="formGroup.reset()" [disabled]="config.disabled">Reset</button> }
3791
+ <button type="submit" class="btn-primary" [disabled]="formGroup.invalid || config.disabled">{{ config.submitLabel || 'Submit' }}</button>
3792
+ </div>
3793
+ }
3794
+ </form>
3795
3795
  `, styles: [".amf-form{display:flex;flex-direction:column;gap:24px}.amf-form.form-disabled{opacity:.6;pointer-events:none}.amf-form-fields{display:flex;flex-direction:column;gap:20px}.amf-form-fields.layout-grid{display:grid;gap:20px}.amf-form-fields.layout-horizontal{flex-direction:row;flex-wrap:wrap;gap:16px}.amf-form-fields.layout-horizontal>*{flex:1;min-width:200px}.amf-form-fields.layout-inline{flex-direction:row;align-items:flex-end;gap:12px}.amf-form-actions{display:flex;justify-content:flex-end;gap:12px;padding-top:8px;border-top:1px solid var(--app-border)}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:var(--app-on-primary, #fff);border:none;padding:10px 24px;border-radius:10px;font-weight:600;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1)}.btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.btn-primary:disabled{opacity:.5;cursor:not-allowed;transform:none}.btn-secondary{background:var(--glass-bg);color:var(--app-text);border:1px solid var(--app-border);padding:10px 24px;border-radius:10px;font-weight:600;cursor:pointer;transition:all .2s}.btn-secondary:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light)}\n"] }]
3796
3796
  }], propDecorators: { config: [{
3797
3797
  type: Input
@@ -4046,214 +4046,214 @@ class StepperFormRendererComponent {
4046
4046
  return controls;
4047
4047
  }
4048
4048
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperFormRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4049
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: StepperFormRendererComponent, isStandalone: true, selector: "amf-stepper-form-renderer", inputs: { config: "config", context: "context" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel" }, usesOnChanges: true, ngImport: i0, template: `
4050
- <div class="amf-stepper" [class]="config.cssClass" [class.stepper-disabled]="config.disabled">
4051
-
4052
- <!-- ─── Step Header ──────────────────────────────────── -->
4053
- <div class="stepper-header">
4054
- @for (step of resolvedSteps(); track $index) {
4055
- <div class="step-item"
4056
- [class.active]="$index === currentStep()"
4057
- [class.completed]="isCompleted($index)"
4058
- [class.skipped]="isSkipped($index)"
4059
- [class.navigable]="canNavigateTo($index)"
4060
- (click)="canNavigateTo($index) && goToStep($index)">
4061
- <div class="step-indicator">
4062
- @if (isCompleted($index)) {
4063
- <svg class="check-icon" viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4064
- } @else if (isSkipped($index)) {
4065
- <svg class="skip-icon" viewBox="0 0 24 24"><path d="M6 18l8.5-6L6 6v12zm2-8.14L11.03 12 8 14.14V9.86zM16 6h2v12h-2z"/></svg>
4066
- } @else {
4067
- <span class="step-number">{{ $index + 1 }}</span>
4068
- }
4069
- </div>
4070
- <div class="step-label-group">
4071
- <span class="step-title">{{ step.title }}</span>
4072
- @if (step.description) { <span class="step-description">{{ step.description }}</span> }
4073
- </div>
4074
- @if ($index < resolvedSteps().length - 1) {
4075
- <div class="step-connector" [class.completed]="isCompleted($index)"></div>
4076
- }
4077
- </div>
4078
- }
4079
- </div>
4080
-
4081
- <!-- ─── Mobile Progress Bar ───────────────────────────── -->
4082
- <div class="stepper-progress-mobile">
4083
- <span class="progress-label">Step {{ currentStep() + 1 }} of {{ resolvedSteps().length }}: {{ resolvedSteps()[currentStep()]?.title }}</span>
4084
- <div class="progress-bar-track">
4085
- <div class="progress-bar-fill" [style.width.%]="progressPercent()"></div>
4086
- </div>
4087
- </div>
4088
-
4089
- <!-- ─── Step Content ─────────────────────────────────── -->
4090
- <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="stepper-form-body">
4091
- <div class="step-content">
4092
- <div class="step-fields" [style.grid-template-columns]="currentGridColumns()">
4093
- @for (field of currentStepVisibleFields(); track field.key) {
4094
- <amf-field-renderer
4095
- [field]="field"
4096
- [form]="formGroup"
4097
- [formDisabled]="!!config.disabled"
4098
- [actionDispatcher]="actionDispatcher"
4099
- [context]="context"
4100
- [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null">
4101
- </amf-field-renderer>
4102
- }
4103
- </div>
4104
-
4105
- <!-- Step-level validation error summary -->
4106
- @if (stepErrors().length) {
4107
- <div class="step-error-summary">
4108
- <svg viewBox="0 0 24 24" class="error-summary-icon"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>
4109
- <span>Please fix {{ stepErrors().length }} error{{ stepErrors().length > 1 ? 's' : '' }} before continuing.</span>
4110
- </div>
4111
- }
4112
- </div>
4113
-
4114
- <!-- ─── Navigation Actions ────────────────────────────── -->
4115
- <div class="stepper-actions">
4116
- <div class="stepper-actions-left">
4117
- @if (config.showReset) {
4118
- <button type="button" class="btn-reset" (click)="resetForm()" [disabled]="config.disabled">
4119
- <svg viewBox="0 0 24 24"><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>
4120
- {{ config.resetLabel || 'Start Over' }}
4121
- </button>
4122
- }
4123
- @if (currentStep() > 0) {
4124
- <button type="button" class="btn-back" (click)="goBack()" [disabled]="config.disabled">
4125
- <svg viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
4126
- Back
4127
- </button>
4128
- }
4129
- </div>
4130
- <div class="stepper-actions-right">
4131
- @if (resolvedSteps()[currentStep()]?.optional) {
4132
- <button type="button" class="btn-skip" (click)="skipStep()" [disabled]="config.disabled">Skip</button>
4133
- }
4134
- @if (currentStep() < resolvedSteps().length - 1) {
4135
- <button type="button" class="btn-next" (click)="goNext()" [disabled]="config.disabled">
4136
- {{ resolvedSteps()[currentStep() + 1] ? 'Next' : 'Review' }}
4137
- <svg viewBox="0 0 24 24"><path d="M4 11v2h12l-5.59 5.59L12 20l8-8-8-8-1.41 1.41L16 11H4z"/></svg>
4138
- </button>
4139
- } @else {
4140
- @if (!config.hideSubmit) {
4141
- <button type="submit" class="btn-submit" [disabled]="formGroup.invalid || config.disabled">
4142
- {{ config.submitLabel || 'Submit' }}
4143
- <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4144
- </button>
4145
- }
4146
- }
4147
- </div>
4148
- </div>
4149
- </form>
4150
- </div>
4049
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: StepperFormRendererComponent, isStandalone: true, selector: "amf-stepper-form-renderer", inputs: { config: "config", context: "context" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel" }, usesOnChanges: true, ngImport: i0, template: `
4050
+ <div class="amf-stepper" [class]="config.cssClass" [class.stepper-disabled]="config.disabled">
4051
+
4052
+ <!-- ─── Step Header ──────────────────────────────────── -->
4053
+ <div class="stepper-header">
4054
+ @for (step of resolvedSteps(); track $index) {
4055
+ <div class="step-item"
4056
+ [class.active]="$index === currentStep()"
4057
+ [class.completed]="isCompleted($index)"
4058
+ [class.skipped]="isSkipped($index)"
4059
+ [class.navigable]="canNavigateTo($index)"
4060
+ (click)="canNavigateTo($index) && goToStep($index)">
4061
+ <div class="step-indicator">
4062
+ @if (isCompleted($index)) {
4063
+ <svg class="check-icon" viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4064
+ } @else if (isSkipped($index)) {
4065
+ <svg class="skip-icon" viewBox="0 0 24 24"><path d="M6 18l8.5-6L6 6v12zm2-8.14L11.03 12 8 14.14V9.86zM16 6h2v12h-2z"/></svg>
4066
+ } @else {
4067
+ <span class="step-number">{{ $index + 1 }}</span>
4068
+ }
4069
+ </div>
4070
+ <div class="step-label-group">
4071
+ <span class="step-title">{{ step.title }}</span>
4072
+ @if (step.description) { <span class="step-description">{{ step.description }}</span> }
4073
+ </div>
4074
+ @if ($index < resolvedSteps().length - 1) {
4075
+ <div class="step-connector" [class.completed]="isCompleted($index)"></div>
4076
+ }
4077
+ </div>
4078
+ }
4079
+ </div>
4080
+
4081
+ <!-- ─── Mobile Progress Bar ───────────────────────────── -->
4082
+ <div class="stepper-progress-mobile">
4083
+ <span class="progress-label">Step {{ currentStep() + 1 }} of {{ resolvedSteps().length }}: {{ resolvedSteps()[currentStep()]?.title }}</span>
4084
+ <div class="progress-bar-track">
4085
+ <div class="progress-bar-fill" [style.width.%]="progressPercent()"></div>
4086
+ </div>
4087
+ </div>
4088
+
4089
+ <!-- ─── Step Content ─────────────────────────────────── -->
4090
+ <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="stepper-form-body">
4091
+ <div class="step-content">
4092
+ <div class="step-fields" [style.grid-template-columns]="currentGridColumns()">
4093
+ @for (field of currentStepVisibleFields(); track field.key) {
4094
+ <amf-field-renderer
4095
+ [field]="field"
4096
+ [form]="formGroup"
4097
+ [formDisabled]="!!config.disabled"
4098
+ [actionDispatcher]="actionDispatcher"
4099
+ [context]="context"
4100
+ [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null">
4101
+ </amf-field-renderer>
4102
+ }
4103
+ </div>
4104
+
4105
+ <!-- Step-level validation error summary -->
4106
+ @if (stepErrors().length) {
4107
+ <div class="step-error-summary">
4108
+ <svg viewBox="0 0 24 24" class="error-summary-icon"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>
4109
+ <span>Please fix {{ stepErrors().length }} error{{ stepErrors().length > 1 ? 's' : '' }} before continuing.</span>
4110
+ </div>
4111
+ }
4112
+ </div>
4113
+
4114
+ <!-- ─── Navigation Actions ────────────────────────────── -->
4115
+ <div class="stepper-actions">
4116
+ <div class="stepper-actions-left">
4117
+ @if (config.showReset) {
4118
+ <button type="button" class="btn-reset" (click)="resetForm()" [disabled]="config.disabled">
4119
+ <svg viewBox="0 0 24 24"><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>
4120
+ {{ config.resetLabel || 'Start Over' }}
4121
+ </button>
4122
+ }
4123
+ @if (currentStep() > 0) {
4124
+ <button type="button" class="btn-back" (click)="goBack()" [disabled]="config.disabled">
4125
+ <svg viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
4126
+ Back
4127
+ </button>
4128
+ }
4129
+ </div>
4130
+ <div class="stepper-actions-right">
4131
+ @if (resolvedSteps()[currentStep()]?.optional) {
4132
+ <button type="button" class="btn-skip" (click)="skipStep()" [disabled]="config.disabled">Skip</button>
4133
+ }
4134
+ @if (currentStep() < resolvedSteps().length - 1) {
4135
+ <button type="button" class="btn-next" (click)="goNext()" [disabled]="config.disabled">
4136
+ {{ resolvedSteps()[currentStep() + 1] ? 'Next' : 'Review' }}
4137
+ <svg viewBox="0 0 24 24"><path d="M4 11v2h12l-5.59 5.59L12 20l8-8-8-8-1.41 1.41L16 11H4z"/></svg>
4138
+ </button>
4139
+ } @else {
4140
+ @if (!config.hideSubmit) {
4141
+ <button type="submit" class="btn-submit" [disabled]="formGroup.invalid || config.disabled">
4142
+ {{ config.submitLabel || 'Submit' }}
4143
+ <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4144
+ </button>
4145
+ }
4146
+ }
4147
+ </div>
4148
+ </div>
4149
+ </form>
4150
+ </div>
4151
4151
  `, isInline: true, styles: [".amf-stepper{display:flex;flex-direction:column;gap:0}.amf-stepper.stepper-disabled{opacity:.6;pointer-events:none}.stepper-header{display:flex;align-items:flex-start;gap:0;padding:20px 24px 0;overflow-x:auto;scrollbar-width:none}.stepper-header::-webkit-scrollbar{display:none}.step-item{display:flex;align-items:center;flex:1;min-width:0;cursor:default;position:relative}.step-item.navigable{cursor:pointer}.step-item.navigable:hover .step-indicator{border-color:var(--app-primary)}.step-item.navigable:hover .step-title{color:var(--app-text)}.step-indicator{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:2px solid var(--app-border);background:var(--app-surface);display:flex;align-items:center;justify-content:center;transition:all .35s cubic-bezier(.4,0,.2,1);position:relative;z-index:1}.step-item.active .step-indicator{border-color:var(--app-primary);background:var(--app-primary);box-shadow:0 0 0 4px rgba(var(--app-primary-rgb, 99 102 241),.18)}.step-item.completed .step-indicator{border-color:#22c55e;background:#22c55e}.step-item.skipped .step-indicator{border-color:var(--app-text-muted);background:var(--glass-bg)}.step-number{font-size:.8125rem;font-weight:700;color:var(--app-text-muted)}.step-item.active .step-number{color:#fff}.check-icon,.skip-icon{width:18px;height:18px;fill:#fff}.skip-icon{fill:var(--app-text-muted)}.step-label-group{display:flex;flex-direction:column;margin-left:10px;min-width:0;flex-shrink:0}.step-title{font-size:.8125rem;font-weight:600;color:var(--app-text-muted);white-space:nowrap;transition:color .2s}.step-item.active .step-title{color:var(--app-text)}.step-item.completed .step-title{color:var(--app-text-muted)}.step-description{font-size:.6875rem;color:var(--app-text-muted);opacity:.7;white-space:nowrap;margin-top:1px}.step-connector{flex:1;height:2px;background:var(--app-border);margin:0 10px 14px;border-radius:1px;transition:background .4s ease;align-self:center}.step-connector.completed{background:linear-gradient(90deg,#22c55e,var(--app-primary))}.stepper-progress-mobile{display:none;flex-direction:column;gap:8px;padding:16px 24px 0}@media(max-width:640px){.stepper-header{display:none}.stepper-progress-mobile{display:flex}}.progress-label{font-size:.8125rem;font-weight:600;color:var(--app-text)}.progress-bar-track{width:100%;height:6px;background:var(--app-border);border-radius:3px;overflow:hidden}.progress-bar-fill{height:100%;background:linear-gradient(90deg,var(--app-primary),var(--app-accent));border-radius:3px;transition:width .4s cubic-bezier(.4,0,.2,1)}.stepper-form-body{display:flex;flex-direction:column;gap:24px;padding:24px}.step-content{animation:stepFadeIn .3s ease-out}@keyframes stepFadeIn{0%{opacity:0;transform:translate(12px)}to{opacity:1;transform:translate(0)}}.step-fields{display:grid;grid-template-columns:1fr;gap:20px}.step-error-summary{display:flex;align-items:center;gap:10px;padding:12px 16px;background:#f43f5e14;border:1px solid rgba(244,63,94,.25);border-radius:10px;margin-top:8px;animation:stepFadeIn .2s ease-out}.error-summary-icon{width:18px;height:18px;fill:#f43f5e;flex-shrink:0}.step-error-summary span{font-size:.8125rem;color:#f43f5e;font-weight:500}.stepper-actions{display:flex;justify-content:space-between;align-items:center;padding-top:8px;border-top:1px solid var(--app-border)}.stepper-actions-left,.stepper-actions-right{display:flex;gap:10px;align-items:center}.btn-reset{display:flex;align-items:center;gap:6px;background:transparent;color:#ef4444;border:1px solid rgba(239,68,68,.3);padding:10px 20px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .2s}.btn-reset svg{width:16px;height:16px;fill:currentColor}.btn-reset:hover{background:#ef44441a;border-color:#ef444480}.btn-reset:disabled{opacity:.5;cursor:not-allowed}.btn-back{display:flex;align-items:center;gap:6px;background:var(--glass-bg);color:var(--app-text);border:1px solid var(--app-border);padding:10px 20px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .2s}.btn-back svg{width:16px;height:16px;fill:currentColor}.btn-back:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light)}.btn-back:disabled{opacity:.5;cursor:not-allowed}.btn-skip{background:transparent;color:var(--app-text-muted);border:none;padding:10px 16px;border-radius:10px;font-weight:500;font-size:.8125rem;cursor:pointer;transition:color .2s}.btn-skip:hover{color:var(--app-primary)}.btn-skip:disabled{opacity:.5;cursor:not-allowed}.btn-next{display:flex;align-items:center;gap:6px;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:10px 24px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1)}.btn-next svg{width:16px;height:16px;fill:currentColor}.btn-next:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.btn-next:disabled{opacity:.5;cursor:not-allowed;transform:none}.btn-submit{display:flex;align-items:center;gap:6px;background:linear-gradient(135deg,#22c55e,#16a34a);color:#fff;border:none;padding:10px 28px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1)}.btn-submit svg{width:16px;height:16px;fill:currentColor}.btn-submit:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px #22c55e59}.btn-submit:disabled{opacity:.5;cursor:not-allowed;transform:none}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FieldRendererComponent, selector: "amf-field-renderer", inputs: ["field", "form", "formDisabled", "actionDispatcher", "context"] }] });
4152
4152
  }
4153
4153
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperFormRendererComponent, decorators: [{
4154
4154
  type: Component,
4155
- args: [{ selector: 'amf-stepper-form-renderer', standalone: true, imports: [ReactiveFormsModule, FieldRendererComponent], template: `
4156
- <div class="amf-stepper" [class]="config.cssClass" [class.stepper-disabled]="config.disabled">
4157
-
4158
- <!-- ─── Step Header ──────────────────────────────────── -->
4159
- <div class="stepper-header">
4160
- @for (step of resolvedSteps(); track $index) {
4161
- <div class="step-item"
4162
- [class.active]="$index === currentStep()"
4163
- [class.completed]="isCompleted($index)"
4164
- [class.skipped]="isSkipped($index)"
4165
- [class.navigable]="canNavigateTo($index)"
4166
- (click)="canNavigateTo($index) && goToStep($index)">
4167
- <div class="step-indicator">
4168
- @if (isCompleted($index)) {
4169
- <svg class="check-icon" viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4170
- } @else if (isSkipped($index)) {
4171
- <svg class="skip-icon" viewBox="0 0 24 24"><path d="M6 18l8.5-6L6 6v12zm2-8.14L11.03 12 8 14.14V9.86zM16 6h2v12h-2z"/></svg>
4172
- } @else {
4173
- <span class="step-number">{{ $index + 1 }}</span>
4174
- }
4175
- </div>
4176
- <div class="step-label-group">
4177
- <span class="step-title">{{ step.title }}</span>
4178
- @if (step.description) { <span class="step-description">{{ step.description }}</span> }
4179
- </div>
4180
- @if ($index < resolvedSteps().length - 1) {
4181
- <div class="step-connector" [class.completed]="isCompleted($index)"></div>
4182
- }
4183
- </div>
4184
- }
4185
- </div>
4186
-
4187
- <!-- ─── Mobile Progress Bar ───────────────────────────── -->
4188
- <div class="stepper-progress-mobile">
4189
- <span class="progress-label">Step {{ currentStep() + 1 }} of {{ resolvedSteps().length }}: {{ resolvedSteps()[currentStep()]?.title }}</span>
4190
- <div class="progress-bar-track">
4191
- <div class="progress-bar-fill" [style.width.%]="progressPercent()"></div>
4192
- </div>
4193
- </div>
4194
-
4195
- <!-- ─── Step Content ─────────────────────────────────── -->
4196
- <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="stepper-form-body">
4197
- <div class="step-content">
4198
- <div class="step-fields" [style.grid-template-columns]="currentGridColumns()">
4199
- @for (field of currentStepVisibleFields(); track field.key) {
4200
- <amf-field-renderer
4201
- [field]="field"
4202
- [form]="formGroup"
4203
- [formDisabled]="!!config.disabled"
4204
- [actionDispatcher]="actionDispatcher"
4205
- [context]="context"
4206
- [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null">
4207
- </amf-field-renderer>
4208
- }
4209
- </div>
4210
-
4211
- <!-- Step-level validation error summary -->
4212
- @if (stepErrors().length) {
4213
- <div class="step-error-summary">
4214
- <svg viewBox="0 0 24 24" class="error-summary-icon"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>
4215
- <span>Please fix {{ stepErrors().length }} error{{ stepErrors().length > 1 ? 's' : '' }} before continuing.</span>
4216
- </div>
4217
- }
4218
- </div>
4219
-
4220
- <!-- ─── Navigation Actions ────────────────────────────── -->
4221
- <div class="stepper-actions">
4222
- <div class="stepper-actions-left">
4223
- @if (config.showReset) {
4224
- <button type="button" class="btn-reset" (click)="resetForm()" [disabled]="config.disabled">
4225
- <svg viewBox="0 0 24 24"><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>
4226
- {{ config.resetLabel || 'Start Over' }}
4227
- </button>
4228
- }
4229
- @if (currentStep() > 0) {
4230
- <button type="button" class="btn-back" (click)="goBack()" [disabled]="config.disabled">
4231
- <svg viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
4232
- Back
4233
- </button>
4234
- }
4235
- </div>
4236
- <div class="stepper-actions-right">
4237
- @if (resolvedSteps()[currentStep()]?.optional) {
4238
- <button type="button" class="btn-skip" (click)="skipStep()" [disabled]="config.disabled">Skip</button>
4239
- }
4240
- @if (currentStep() < resolvedSteps().length - 1) {
4241
- <button type="button" class="btn-next" (click)="goNext()" [disabled]="config.disabled">
4242
- {{ resolvedSteps()[currentStep() + 1] ? 'Next' : 'Review' }}
4243
- <svg viewBox="0 0 24 24"><path d="M4 11v2h12l-5.59 5.59L12 20l8-8-8-8-1.41 1.41L16 11H4z"/></svg>
4244
- </button>
4245
- } @else {
4246
- @if (!config.hideSubmit) {
4247
- <button type="submit" class="btn-submit" [disabled]="formGroup.invalid || config.disabled">
4248
- {{ config.submitLabel || 'Submit' }}
4249
- <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4250
- </button>
4251
- }
4252
- }
4253
- </div>
4254
- </div>
4255
- </form>
4256
- </div>
4155
+ args: [{ selector: 'amf-stepper-form-renderer', standalone: true, imports: [ReactiveFormsModule, FieldRendererComponent], template: `
4156
+ <div class="amf-stepper" [class]="config.cssClass" [class.stepper-disabled]="config.disabled">
4157
+
4158
+ <!-- ─── Step Header ──────────────────────────────────── -->
4159
+ <div class="stepper-header">
4160
+ @for (step of resolvedSteps(); track $index) {
4161
+ <div class="step-item"
4162
+ [class.active]="$index === currentStep()"
4163
+ [class.completed]="isCompleted($index)"
4164
+ [class.skipped]="isSkipped($index)"
4165
+ [class.navigable]="canNavigateTo($index)"
4166
+ (click)="canNavigateTo($index) && goToStep($index)">
4167
+ <div class="step-indicator">
4168
+ @if (isCompleted($index)) {
4169
+ <svg class="check-icon" viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4170
+ } @else if (isSkipped($index)) {
4171
+ <svg class="skip-icon" viewBox="0 0 24 24"><path d="M6 18l8.5-6L6 6v12zm2-8.14L11.03 12 8 14.14V9.86zM16 6h2v12h-2z"/></svg>
4172
+ } @else {
4173
+ <span class="step-number">{{ $index + 1 }}</span>
4174
+ }
4175
+ </div>
4176
+ <div class="step-label-group">
4177
+ <span class="step-title">{{ step.title }}</span>
4178
+ @if (step.description) { <span class="step-description">{{ step.description }}</span> }
4179
+ </div>
4180
+ @if ($index < resolvedSteps().length - 1) {
4181
+ <div class="step-connector" [class.completed]="isCompleted($index)"></div>
4182
+ }
4183
+ </div>
4184
+ }
4185
+ </div>
4186
+
4187
+ <!-- ─── Mobile Progress Bar ───────────────────────────── -->
4188
+ <div class="stepper-progress-mobile">
4189
+ <span class="progress-label">Step {{ currentStep() + 1 }} of {{ resolvedSteps().length }}: {{ resolvedSteps()[currentStep()]?.title }}</span>
4190
+ <div class="progress-bar-track">
4191
+ <div class="progress-bar-fill" [style.width.%]="progressPercent()"></div>
4192
+ </div>
4193
+ </div>
4194
+
4195
+ <!-- ─── Step Content ─────────────────────────────────── -->
4196
+ <form [formGroup]="formGroup" (ngSubmit)="onSubmit()" class="stepper-form-body">
4197
+ <div class="step-content">
4198
+ <div class="step-fields" [style.grid-template-columns]="currentGridColumns()">
4199
+ @for (field of currentStepVisibleFields(); track field.key) {
4200
+ <amf-field-renderer
4201
+ [field]="field"
4202
+ [form]="formGroup"
4203
+ [formDisabled]="!!config.disabled"
4204
+ [actionDispatcher]="actionDispatcher"
4205
+ [context]="context"
4206
+ [style.grid-column]="field.colSpan ? 'span ' + field.colSpan : null">
4207
+ </amf-field-renderer>
4208
+ }
4209
+ </div>
4210
+
4211
+ <!-- Step-level validation error summary -->
4212
+ @if (stepErrors().length) {
4213
+ <div class="step-error-summary">
4214
+ <svg viewBox="0 0 24 24" class="error-summary-icon"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>
4215
+ <span>Please fix {{ stepErrors().length }} error{{ stepErrors().length > 1 ? 's' : '' }} before continuing.</span>
4216
+ </div>
4217
+ }
4218
+ </div>
4219
+
4220
+ <!-- ─── Navigation Actions ────────────────────────────── -->
4221
+ <div class="stepper-actions">
4222
+ <div class="stepper-actions-left">
4223
+ @if (config.showReset) {
4224
+ <button type="button" class="btn-reset" (click)="resetForm()" [disabled]="config.disabled">
4225
+ <svg viewBox="0 0 24 24"><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>
4226
+ {{ config.resetLabel || 'Start Over' }}
4227
+ </button>
4228
+ }
4229
+ @if (currentStep() > 0) {
4230
+ <button type="button" class="btn-back" (click)="goBack()" [disabled]="config.disabled">
4231
+ <svg viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
4232
+ Back
4233
+ </button>
4234
+ }
4235
+ </div>
4236
+ <div class="stepper-actions-right">
4237
+ @if (resolvedSteps()[currentStep()]?.optional) {
4238
+ <button type="button" class="btn-skip" (click)="skipStep()" [disabled]="config.disabled">Skip</button>
4239
+ }
4240
+ @if (currentStep() < resolvedSteps().length - 1) {
4241
+ <button type="button" class="btn-next" (click)="goNext()" [disabled]="config.disabled">
4242
+ {{ resolvedSteps()[currentStep() + 1] ? 'Next' : 'Review' }}
4243
+ <svg viewBox="0 0 24 24"><path d="M4 11v2h12l-5.59 5.59L12 20l8-8-8-8-1.41 1.41L16 11H4z"/></svg>
4244
+ </button>
4245
+ } @else {
4246
+ @if (!config.hideSubmit) {
4247
+ <button type="submit" class="btn-submit" [disabled]="formGroup.invalid || config.disabled">
4248
+ {{ config.submitLabel || 'Submit' }}
4249
+ <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4250
+ </button>
4251
+ }
4252
+ }
4253
+ </div>
4254
+ </div>
4255
+ </form>
4256
+ </div>
4257
4257
  `, styles: [".amf-stepper{display:flex;flex-direction:column;gap:0}.amf-stepper.stepper-disabled{opacity:.6;pointer-events:none}.stepper-header{display:flex;align-items:flex-start;gap:0;padding:20px 24px 0;overflow-x:auto;scrollbar-width:none}.stepper-header::-webkit-scrollbar{display:none}.step-item{display:flex;align-items:center;flex:1;min-width:0;cursor:default;position:relative}.step-item.navigable{cursor:pointer}.step-item.navigable:hover .step-indicator{border-color:var(--app-primary)}.step-item.navigable:hover .step-title{color:var(--app-text)}.step-indicator{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:2px solid var(--app-border);background:var(--app-surface);display:flex;align-items:center;justify-content:center;transition:all .35s cubic-bezier(.4,0,.2,1);position:relative;z-index:1}.step-item.active .step-indicator{border-color:var(--app-primary);background:var(--app-primary);box-shadow:0 0 0 4px rgba(var(--app-primary-rgb, 99 102 241),.18)}.step-item.completed .step-indicator{border-color:#22c55e;background:#22c55e}.step-item.skipped .step-indicator{border-color:var(--app-text-muted);background:var(--glass-bg)}.step-number{font-size:.8125rem;font-weight:700;color:var(--app-text-muted)}.step-item.active .step-number{color:#fff}.check-icon,.skip-icon{width:18px;height:18px;fill:#fff}.skip-icon{fill:var(--app-text-muted)}.step-label-group{display:flex;flex-direction:column;margin-left:10px;min-width:0;flex-shrink:0}.step-title{font-size:.8125rem;font-weight:600;color:var(--app-text-muted);white-space:nowrap;transition:color .2s}.step-item.active .step-title{color:var(--app-text)}.step-item.completed .step-title{color:var(--app-text-muted)}.step-description{font-size:.6875rem;color:var(--app-text-muted);opacity:.7;white-space:nowrap;margin-top:1px}.step-connector{flex:1;height:2px;background:var(--app-border);margin:0 10px 14px;border-radius:1px;transition:background .4s ease;align-self:center}.step-connector.completed{background:linear-gradient(90deg,#22c55e,var(--app-primary))}.stepper-progress-mobile{display:none;flex-direction:column;gap:8px;padding:16px 24px 0}@media(max-width:640px){.stepper-header{display:none}.stepper-progress-mobile{display:flex}}.progress-label{font-size:.8125rem;font-weight:600;color:var(--app-text)}.progress-bar-track{width:100%;height:6px;background:var(--app-border);border-radius:3px;overflow:hidden}.progress-bar-fill{height:100%;background:linear-gradient(90deg,var(--app-primary),var(--app-accent));border-radius:3px;transition:width .4s cubic-bezier(.4,0,.2,1)}.stepper-form-body{display:flex;flex-direction:column;gap:24px;padding:24px}.step-content{animation:stepFadeIn .3s ease-out}@keyframes stepFadeIn{0%{opacity:0;transform:translate(12px)}to{opacity:1;transform:translate(0)}}.step-fields{display:grid;grid-template-columns:1fr;gap:20px}.step-error-summary{display:flex;align-items:center;gap:10px;padding:12px 16px;background:#f43f5e14;border:1px solid rgba(244,63,94,.25);border-radius:10px;margin-top:8px;animation:stepFadeIn .2s ease-out}.error-summary-icon{width:18px;height:18px;fill:#f43f5e;flex-shrink:0}.step-error-summary span{font-size:.8125rem;color:#f43f5e;font-weight:500}.stepper-actions{display:flex;justify-content:space-between;align-items:center;padding-top:8px;border-top:1px solid var(--app-border)}.stepper-actions-left,.stepper-actions-right{display:flex;gap:10px;align-items:center}.btn-reset{display:flex;align-items:center;gap:6px;background:transparent;color:#ef4444;border:1px solid rgba(239,68,68,.3);padding:10px 20px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .2s}.btn-reset svg{width:16px;height:16px;fill:currentColor}.btn-reset:hover{background:#ef44441a;border-color:#ef444480}.btn-reset:disabled{opacity:.5;cursor:not-allowed}.btn-back{display:flex;align-items:center;gap:6px;background:var(--glass-bg);color:var(--app-text);border:1px solid var(--app-border);padding:10px 20px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .2s}.btn-back svg{width:16px;height:16px;fill:currentColor}.btn-back:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light)}.btn-back:disabled{opacity:.5;cursor:not-allowed}.btn-skip{background:transparent;color:var(--app-text-muted);border:none;padding:10px 16px;border-radius:10px;font-weight:500;font-size:.8125rem;cursor:pointer;transition:color .2s}.btn-skip:hover{color:var(--app-primary)}.btn-skip:disabled{opacity:.5;cursor:not-allowed}.btn-next{display:flex;align-items:center;gap:6px;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:10px 24px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1)}.btn-next svg{width:16px;height:16px;fill:currentColor}.btn-next:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.btn-next:disabled{opacity:.5;cursor:not-allowed;transform:none}.btn-submit{display:flex;align-items:center;gap:6px;background:linear-gradient(135deg,#22c55e,#16a34a);color:#fff;border:none;padding:10px 28px;border-radius:10px;font-weight:600;font-size:.875rem;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1)}.btn-submit svg{width:16px;height:16px;fill:currentColor}.btn-submit:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 24px -4px #22c55e59}.btn-submit:disabled{opacity:.5;cursor:not-allowed;transform:none}\n"] }]
4258
4258
  }], propDecorators: { config: [{
4259
4259
  type: Input
@@ -4286,60 +4286,60 @@ class CellRendererComponent {
4286
4286
  return path.split('.').reduce((c, k) => c?.[k], obj) ?? '';
4287
4287
  }
4288
4288
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CellRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4289
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CellRendererComponent, isStandalone: true, selector: "amf-cell-renderer", inputs: { column: "column", row: "row", value: "value" }, ngImport: i0, template: `
4290
- @switch (column.type || 'text') {
4291
- @case ('badge') { <span class="cell-badge" [class]="getBadgeClass()">{{ value | titlecase }}</span> }
4292
- @case ('avatar') {
4293
- <div class="cell-avatar">
4294
- <div class="avatar-circle">{{ getInitial() }}</div>
4295
- <div class="avatar-info">
4296
- <span class="avatar-name">{{ value }}</span>
4297
- @if (column.subtitleKey) { <span class="avatar-subtitle">{{ getNestedValue(row, column.subtitleKey) }}</span> }
4298
- </div>
4299
- </div>
4300
- }
4301
- @case ('date') { <span>{{ value | date:(column.dateFormat || 'mediumDate') }}</span> }
4302
- @case ('datetime') { <span>{{ value | date:(column.dateFormat || 'medium') }}</span> }
4303
- @case ('currency') { <span>{{ value | currency:(column.currencyCodeKey ? getNestedValue(row, column.currencyCodeKey) : (column.currencyCode || 'USD')):(column.currencyDisplay !== undefined ? column.currencyDisplay : 'symbol') }}</span> }
4304
- @case ('boolean') { <span class="cell-boolean" [class.is-true]="value">{{ value ? '✓' : '✗' }}</span> }
4305
- @case ('number') { <span class="cell-number">{{ value }}</span> }
4306
- @case ('progress') {
4307
- <div class="cell-progress">
4308
- <div class="progress-bar"><div class="progress-fill" [style.width.%]="value"></div></div>
4309
- <span class="progress-text">{{ value }}%</span>
4310
- </div>
4311
- }
4312
- @default { <span>{{ value }}</span> }
4313
- }
4289
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CellRendererComponent, isStandalone: true, selector: "amf-cell-renderer", inputs: { column: "column", row: "row", value: "value" }, ngImport: i0, template: `
4290
+ @switch (column.type || 'text') {
4291
+ @case ('badge') { <span class="cell-badge" [class]="getBadgeClass()">{{ value | titlecase }}</span> }
4292
+ @case ('avatar') {
4293
+ <div class="cell-avatar">
4294
+ <div class="avatar-circle">{{ getInitial() }}</div>
4295
+ <div class="avatar-info">
4296
+ <span class="avatar-name">{{ value }}</span>
4297
+ @if (column.subtitleKey) { <span class="avatar-subtitle">{{ getNestedValue(row, column.subtitleKey) }}</span> }
4298
+ </div>
4299
+ </div>
4300
+ }
4301
+ @case ('date') { <span>{{ value | date:(column.dateFormat || 'mediumDate') }}</span> }
4302
+ @case ('datetime') { <span>{{ value | date:(column.dateFormat || 'medium') }}</span> }
4303
+ @case ('currency') { <span>{{ value | currency:(column.currencyCodeKey ? getNestedValue(row, column.currencyCodeKey) : (column.currencyCode || 'USD')):(column.currencyDisplay !== undefined ? column.currencyDisplay : 'symbol') }}</span> }
4304
+ @case ('boolean') { <span class="cell-boolean" [class.is-true]="value">{{ value ? '✓' : '✗' }}</span> }
4305
+ @case ('number') { <span class="cell-number">{{ value }}</span> }
4306
+ @case ('progress') {
4307
+ <div class="cell-progress">
4308
+ <div class="progress-bar"><div class="progress-fill" [style.width.%]="value"></div></div>
4309
+ <span class="progress-text">{{ value }}%</span>
4310
+ </div>
4311
+ }
4312
+ @default { <span>{{ value }}</span> }
4313
+ }
4314
4314
  `, isInline: true, styles: [":host{display:contents}.cell-badge{padding:4px 10px;border-radius:6px;font-size:.75rem;font-weight:600;display:inline-block}.cell-badge.success,.cell-badge.active{background:#34d39926;color:#34d399}.cell-badge.danger,.cell-badge.inactive{background:#f43f5e26;color:#fb7185}.cell-badge.warning,.cell-badge.pending{background:#fbbf2426;color:#fbbf24}.cell-badge.info{background:#3b82f626;color:#60a5fa}.cell-badge.muted{background:var(--glass-bg);color:var(--app-text-muted)}.cell-avatar{display:flex;align-items:center;gap:12px}.avatar-circle{width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.875rem;flex-shrink:0}.avatar-info{display:flex;flex-direction:column}.avatar-name{font-weight:600;color:var(--app-text);font-size:.875rem}.avatar-subtitle{font-size:.75rem;color:var(--app-text-muted)}.cell-boolean{font-weight:700}.cell-boolean.is-true{color:#34d399}.cell-boolean:not(.is-true){color:#fb7185}.cell-number{font-variant-numeric:tabular-nums}.cell-progress{display:flex;align-items:center;gap:8px}.progress-bar{flex:1;height:6px;background:var(--glass-bg);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:linear-gradient(90deg,var(--app-primary),var(--app-accent));border-radius:3px;transition:width .3s}.progress-text{font-size:.75rem;color:var(--app-text-muted);min-width:36px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i1$1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }] });
4315
4315
  }
4316
4316
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CellRendererComponent, decorators: [{
4317
4317
  type: Component,
4318
- args: [{ selector: 'amf-cell-renderer', standalone: true, imports: [CommonModule, TitleCasePipe, DatePipe, CurrencyPipe], template: `
4319
- @switch (column.type || 'text') {
4320
- @case ('badge') { <span class="cell-badge" [class]="getBadgeClass()">{{ value | titlecase }}</span> }
4321
- @case ('avatar') {
4322
- <div class="cell-avatar">
4323
- <div class="avatar-circle">{{ getInitial() }}</div>
4324
- <div class="avatar-info">
4325
- <span class="avatar-name">{{ value }}</span>
4326
- @if (column.subtitleKey) { <span class="avatar-subtitle">{{ getNestedValue(row, column.subtitleKey) }}</span> }
4327
- </div>
4328
- </div>
4329
- }
4330
- @case ('date') { <span>{{ value | date:(column.dateFormat || 'mediumDate') }}</span> }
4331
- @case ('datetime') { <span>{{ value | date:(column.dateFormat || 'medium') }}</span> }
4332
- @case ('currency') { <span>{{ value | currency:(column.currencyCodeKey ? getNestedValue(row, column.currencyCodeKey) : (column.currencyCode || 'USD')):(column.currencyDisplay !== undefined ? column.currencyDisplay : 'symbol') }}</span> }
4333
- @case ('boolean') { <span class="cell-boolean" [class.is-true]="value">{{ value ? '✓' : '✗' }}</span> }
4334
- @case ('number') { <span class="cell-number">{{ value }}</span> }
4335
- @case ('progress') {
4336
- <div class="cell-progress">
4337
- <div class="progress-bar"><div class="progress-fill" [style.width.%]="value"></div></div>
4338
- <span class="progress-text">{{ value }}%</span>
4339
- </div>
4340
- }
4341
- @default { <span>{{ value }}</span> }
4342
- }
4318
+ args: [{ selector: 'amf-cell-renderer', standalone: true, imports: [CommonModule, TitleCasePipe, DatePipe, CurrencyPipe], template: `
4319
+ @switch (column.type || 'text') {
4320
+ @case ('badge') { <span class="cell-badge" [class]="getBadgeClass()">{{ value | titlecase }}</span> }
4321
+ @case ('avatar') {
4322
+ <div class="cell-avatar">
4323
+ <div class="avatar-circle">{{ getInitial() }}</div>
4324
+ <div class="avatar-info">
4325
+ <span class="avatar-name">{{ value }}</span>
4326
+ @if (column.subtitleKey) { <span class="avatar-subtitle">{{ getNestedValue(row, column.subtitleKey) }}</span> }
4327
+ </div>
4328
+ </div>
4329
+ }
4330
+ @case ('date') { <span>{{ value | date:(column.dateFormat || 'mediumDate') }}</span> }
4331
+ @case ('datetime') { <span>{{ value | date:(column.dateFormat || 'medium') }}</span> }
4332
+ @case ('currency') { <span>{{ value | currency:(column.currencyCodeKey ? getNestedValue(row, column.currencyCodeKey) : (column.currencyCode || 'USD')):(column.currencyDisplay !== undefined ? column.currencyDisplay : 'symbol') }}</span> }
4333
+ @case ('boolean') { <span class="cell-boolean" [class.is-true]="value">{{ value ? '✓' : '✗' }}</span> }
4334
+ @case ('number') { <span class="cell-number">{{ value }}</span> }
4335
+ @case ('progress') {
4336
+ <div class="cell-progress">
4337
+ <div class="progress-bar"><div class="progress-fill" [style.width.%]="value"></div></div>
4338
+ <span class="progress-text">{{ value }}%</span>
4339
+ </div>
4340
+ }
4341
+ @default { <span>{{ value }}</span> }
4342
+ }
4343
4343
  `, styles: [":host{display:contents}.cell-badge{padding:4px 10px;border-radius:6px;font-size:.75rem;font-weight:600;display:inline-block}.cell-badge.success,.cell-badge.active{background:#34d39926;color:#34d399}.cell-badge.danger,.cell-badge.inactive{background:#f43f5e26;color:#fb7185}.cell-badge.warning,.cell-badge.pending{background:#fbbf2426;color:#fbbf24}.cell-badge.info{background:#3b82f626;color:#60a5fa}.cell-badge.muted{background:var(--glass-bg);color:var(--app-text-muted)}.cell-avatar{display:flex;align-items:center;gap:12px}.avatar-circle{width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.875rem;flex-shrink:0}.avatar-info{display:flex;flex-direction:column}.avatar-name{font-weight:600;color:var(--app-text);font-size:.875rem}.avatar-subtitle{font-size:.75rem;color:var(--app-text-muted)}.cell-boolean{font-weight:700}.cell-boolean.is-true{color:#34d399}.cell-boolean:not(.is-true){color:#fb7185}.cell-number{font-variant-numeric:tabular-nums}.cell-progress{display:flex;align-items:center;gap:8px}.progress-bar{flex:1;height:6px;background:var(--glass-bg);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:linear-gradient(90deg,var(--app-primary),var(--app-accent));border-radius:3px;transition:width .3s}.progress-text{font-size:.75rem;color:var(--app-text-muted);min-width:36px}\n"] }]
4344
4344
  }], propDecorators: { column: [{
4345
4345
  type: Input
@@ -4777,404 +4777,404 @@ class TableRendererComponent {
4777
4777
  }
4778
4778
  }
4779
4779
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TableRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4780
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: TableRendererComponent, isStandalone: true, selector: "amf-table-renderer", inputs: { config: "config", context: "context" }, outputs: { rowAction: "rowAction" }, ngImport: i0, template: `
4781
- <div class="amf-table-card" [class]="'variant-' + (config.variant || 'default') + ' ' + (config.cssClass || '')">
4782
- <div class="table-header">
4783
- <div class="table-header-left">
4784
- @if (config.searchable) {
4785
- <div class="search-box">
4786
- <svg viewBox="0 0 24 24" class="search-icon"><path [attr.d]="iconRegistry.getIcon('search')"></path></svg>
4787
- <input type="text" [placeholder]="config.searchPlaceholder || 'Search...'" [ngModel]="searchQuery()" (ngModelChange)="searchQuery.set($event)" />
4788
- </div>
4789
- }
4790
- @for (filter of config.filters || []; track filter.key) {
4791
- <select class="filter-select" [ngModel]="getFilterValue(filter.key)" (ngModelChange)="setFilterValue(filter.key, $event)">
4792
- <option value="">{{ filter.label }}</option>
4793
- @for (opt of filter.options; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
4794
- </select>
4795
- }
4796
- </div>
4797
- <div class="table-header-right">
4798
- @for (action of config.headerActions || []; track action.id) {
4799
- <button class="btn-primary btn-sm" (click)="handleAction(action, null)">
4800
- @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
4801
- {{ action.label }}
4802
- </button>
4803
- }
4804
-
4805
- @if (config.exportable) {
4806
- <div class="export-container">
4807
- <button class="btn-ghost btn-sm" (click)="exportMenuOpen.set(!exportMenuOpen())">
4808
- <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon('download')"></path></svg>
4809
- Export
4810
- </button>
4811
- @if (exportMenuOpen()) {
4812
- <div class="dropdown-menu export-menu">
4813
- @for (format of config.exportFormats || ['csv', 'json']; track format) {
4814
- <div class="dropdown-item" (click)="exportData(format); exportMenuOpen.set(false)">
4815
- Export as {{ format | uppercase }}
4816
- </div>
4817
- }
4818
- </div>
4819
- }
4820
- </div>
4821
- }
4822
- </div>
4823
- </div>
4824
- <div class="table-wrapper">
4825
- <table class="data-table" [class.striped]="config.striped" [class.hoverable]="config.hoverable !== false">
4826
- <thead>
4827
- <tr cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="dropColumn($event)">
4828
- @if (config.reorderable) { <th class="drag-col" style="width: 40px; text-align: center;"></th> }
4829
- @if (config.selectionMode === 'checkbox') {
4830
- <th class="selection-col" style="width: 40px; text-align: center;">
4831
- @if (config.showSelectAll !== false) {
4832
- <input type="checkbox"
4833
- class="amf-checkbox"
4834
- [checked]="selectedRows().size > 0 && selectedRows().size === filteredData().length"
4835
- (change)="toggleAllSelection($event)" />
4836
- }
4837
- </th>
4838
- }
4839
- @if (config.expandable) {
4840
- <th style="width: 36px;"></th>
4841
- }
4842
- @for (col of visibleColumns(); track col.key) {
4843
- <th cdkDrag [cdkDragDisabled]="!config.columnReorder" [style.width]="col.width" [style.min-width]="col.minWidth" [style.text-align]="col.align || 'left'" [class.sortable]="col.sortable" (click)="col.sortable ? toggleSort(col.key) : null">
4844
- {{ col.label }} @if (col.sortable && sortKey() === col.key) { <span class="sort-indicator">{{ sortDirection() === 'asc' ? '↑' : '↓' }}</span> }
4845
- </th>
4846
- }
4847
- @if (config.actions?.length) { <th class="actions-col">Actions</th> }
4848
- </tr>
4849
- </thead>
4850
- <tbody cdkDropList (cdkDropListDropped)="dropRow($event)">
4851
- @for (row of groupedRows(); track $index) {
4852
- @if (row.__isGroupHeader) {
4853
- <tr class="group-header-row">
4854
- <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + (config.expandable ? 1 : 0) + (config.actions?.length ? 1 : 0)">
4855
- <button class="group-toggle" (click)="toggleGroup(row.__groupKey)">
4856
- <span class="group-chevron" [class.open]="!collapsedGroups().has(row.__groupKey)">▶</span>
4857
- {{ config.groupBy }}: <strong>{{ row.__groupKey }}</strong>
4858
- <span class="group-count">({{ row.__count }} items)</span>
4859
- </button>
4860
- </td>
4861
- </tr>
4862
- } @else {
4863
- <tr cdkDrag [cdkDragDisabled]="!config.reorderable" (click)="handleRowClick(row)" [class.clickable]="config.rowClick || config.selectionMode === 'single' || config.selectionMode === 'multi'" [class.selected]="selectedRows().has(row)" [class.expanded]="expandedRows().has(row)">
4864
- @if (config.reorderable) {
4865
- <td class="drag-cell" (click)="$event.stopPropagation()" cdkDragHandle>
4866
- <svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:var(--app-text-muted)"><path [attr.d]="iconRegistry.getIcon('menu')"></path></svg>
4867
- </td>
4868
- }
4869
- @if (config.selectionMode === 'checkbox') {
4870
- <td class="selection-cell" (click)="$event.stopPropagation(); toggleSelection(row)">
4871
- <input type="checkbox" class="amf-checkbox" [checked]="selectedRows().has(row)" (click)="$event.stopPropagation()" (change)="$event.stopPropagation(); toggleSelection(row)" />
4872
- </td>
4873
- }
4874
- @if (config.expandable) {
4875
- <td class="expand-cell" (click)="$event.stopPropagation(); toggleRowExpand(row)">
4876
- <span class="expand-chevron" [class.open]="expandedRows().has(row)">▶</span>
4877
- </td>
4878
- }
4879
- @for (col of visibleColumns(); track col.key) {
4880
- <td [style.text-align]="col.align || 'left'" (dblclick)="config.inlineEdit && col.editable !== false ? startEdit(row, col.key, $event) : null" [class.editable-cell]="config.inlineEdit && col.editable !== false">
4881
- @if (isEditing(row, col.key)) {
4882
- <div class="inline-edit-wrap" (click)="$event.stopPropagation()">
4883
- <div class="inline-edit-row">
4884
- @if (col.editType === 'select' && col.editOptions) {
4885
- <select class="inline-input" [(ngModel)]="editBuffer[col.key]">
4886
- @for (opt of col.editOptions; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
4887
- </select>
4888
- } @else {
4889
- <input class="inline-input" [type]="col.editType || 'text'" [(ngModel)]="editBuffer[col.key]" (keydown.enter)="commitEdit(row, col.key)" (keydown.escape)="cancelEdit()" />
4890
- }
4891
- <div class="inline-edit-actions">
4892
- <button class="ie-btn ie-save" title="Save (Enter)" (click)="commitEdit(row, col.key)">
4893
- <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4894
- </button>
4895
- <button class="ie-btn ie-cancel" title="Cancel (Esc)" (click)="cancelEdit()">
4896
- <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
4897
- </button>
4898
- </div>
4899
- </div>
4900
- @if (editError()) {
4901
- <span class="inline-edit-error">{{ editError() }}</span>
4902
- }
4903
- </div>
4904
- } @else {
4905
- <amf-cell-renderer [column]="col" [row]="row" [value]="getCellValue(row, col.key)"></amf-cell-renderer>
4906
- }
4907
- </td>
4908
- }
4909
- @if (config.actions?.length) {
4910
- <td class="actions-cell">
4911
- <div class="action-btns">
4912
- @for (action of config.actions; track action.id) {
4913
- <button class="action-btn" [class]="action.variant || 'ghost'" [title]="action.label" (click)="handleAction(action, row); $event.stopPropagation()">
4914
- @if (action.icon) { <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> } @else { {{ action.label }} }
4915
- </button>
4916
- }
4917
- </div>
4918
- </td>
4919
- }
4920
- </tr>
4921
- @if (config.expandable && expandedRows().has(row)) {
4922
- <tr class="expanded-row">
4923
- <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + 1 + (config.actions?.length ? 1 : 0)" class="expanded-content">
4924
- @if (config.expandSection) {
4925
- <div class="expand-section">Row detail: {{ row | json }}</div>
4926
- } @else {
4927
- <div class="expand-section">
4928
- @for (col of visibleColumns(); track col.key) {
4929
- <div class="expand-field"><span class="expand-label">{{ col.label }}:</span> <span>{{ getCellValue(row, col.key) }}</span></div>
4930
- }
4931
- </div>
4932
- }
4933
- </td>
4934
- </tr>
4935
- }
4936
- }
4937
- } @empty { <tr><td [attr.colspan]="visibleColumns().length + (config.actions?.length ? 1 : 0)" class="empty-state">{{ config.emptyMessage || 'No data found.' }}</td></tr> }
4938
- @if (config.aggregates?.length) {
4939
- <tr class="aggregate-row">
4940
- @if (config.reorderable) { <td></td> }
4941
- @if (config.selectionMode === 'checkbox') { <td></td> }
4942
- @if (config.expandable) { <td></td> }
4943
- @for (col of visibleColumns(); track col.key) {
4944
- <td class="aggregate-cell" [style.text-align]="col.align || 'right'">
4945
- @if (getAggregate(col.key); as agg) { <span class="agg-value">{{ agg.label ? agg.label + ': ' : '' }}{{ agg.value }}</span> }
4946
- </td>
4947
- }
4948
- @if (config.actions?.length) { <td></td> }
4949
- </tr>
4950
- }
4951
- </tbody>
4952
- </table>
4953
- </div>
4954
- @if (config.pagination?.enabled) {
4955
- <div class="table-footer">
4956
- <div class="footer-left">
4957
- <span class="results-count">Showing {{ paginatedData().length }} of {{ filteredData().length }} @if (config.pagination?.showTotal) { (total: {{ allData().length }}) }</span>
4958
- @if ((config.pagination?.pageSizeOptions || [5, 10, 25, 50]).length > 1) {
4959
- <div class="page-size-wrap">
4960
- <label class="page-size-label">Rows:</label>
4961
- <select class="page-size-select" [ngModel]="activePageSize()" (ngModelChange)="setPageSize($event)">
4962
- @for (opt of config.pagination?.pageSizeOptions || [5, 10, 25, 50]; track opt) {
4963
- <option [value]="opt">{{ opt }}</option>
4964
- }
4965
- </select>
4966
- </div>
4967
- }
4968
- </div>
4969
- <div class="pagination">
4970
- <button class="btn-page-nav" [disabled]="currentPage() <= 1" (click)="currentPage.set(currentPage() - 1)">Previous</button>
4971
- @for (p of pageNumbers(); track p) { <button class="btn-page" [class.active]="p === currentPage()" (click)="currentPage.set(p)">{{ p }}</button> }
4972
- <button class="btn-page-nav" [disabled]="currentPage() >= totalPages()" (click)="currentPage.set(currentPage() + 1)">Next</button>
4973
- </div>
4974
- </div>
4975
- }
4976
- </div>
4780
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: TableRendererComponent, isStandalone: true, selector: "amf-table-renderer", inputs: { config: "config", context: "context" }, outputs: { rowAction: "rowAction" }, ngImport: i0, template: `
4781
+ <div class="amf-table-card" [class]="'variant-' + (config.variant || 'default') + ' ' + (config.cssClass || '')">
4782
+ <div class="table-header">
4783
+ <div class="table-header-left">
4784
+ @if (config.searchable) {
4785
+ <div class="search-box">
4786
+ <svg viewBox="0 0 24 24" class="search-icon"><path [attr.d]="iconRegistry.getIcon('search')"></path></svg>
4787
+ <input type="text" [placeholder]="config.searchPlaceholder || 'Search...'" [ngModel]="searchQuery()" (ngModelChange)="searchQuery.set($event)" />
4788
+ </div>
4789
+ }
4790
+ @for (filter of config.filters || []; track filter.key) {
4791
+ <select class="filter-select" [ngModel]="getFilterValue(filter.key)" (ngModelChange)="setFilterValue(filter.key, $event)">
4792
+ <option value="">{{ filter.label }}</option>
4793
+ @for (opt of filter.options; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
4794
+ </select>
4795
+ }
4796
+ </div>
4797
+ <div class="table-header-right">
4798
+ @for (action of config.headerActions || []; track action.id) {
4799
+ <button class="btn-primary btn-sm" (click)="handleAction(action, null)">
4800
+ @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
4801
+ {{ action.label }}
4802
+ </button>
4803
+ }
4804
+
4805
+ @if (config.exportable) {
4806
+ <div class="export-container">
4807
+ <button class="btn-ghost btn-sm" (click)="exportMenuOpen.set(!exportMenuOpen())">
4808
+ <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon('download')"></path></svg>
4809
+ Export
4810
+ </button>
4811
+ @if (exportMenuOpen()) {
4812
+ <div class="dropdown-menu export-menu">
4813
+ @for (format of config.exportFormats || ['csv', 'json']; track format) {
4814
+ <div class="dropdown-item" (click)="exportData(format); exportMenuOpen.set(false)">
4815
+ Export as {{ format | uppercase }}
4816
+ </div>
4817
+ }
4818
+ </div>
4819
+ }
4820
+ </div>
4821
+ }
4822
+ </div>
4823
+ </div>
4824
+ <div class="table-wrapper">
4825
+ <table class="data-table" [class.striped]="config.striped" [class.hoverable]="config.hoverable !== false">
4826
+ <thead>
4827
+ <tr cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="dropColumn($event)">
4828
+ @if (config.reorderable) { <th class="drag-col" style="width: 40px; text-align: center;"></th> }
4829
+ @if (config.selectionMode === 'checkbox') {
4830
+ <th class="selection-col" style="width: 40px; text-align: center;">
4831
+ @if (config.showSelectAll !== false) {
4832
+ <input type="checkbox"
4833
+ class="amf-checkbox"
4834
+ [checked]="selectedRows().size > 0 && selectedRows().size === filteredData().length"
4835
+ (change)="toggleAllSelection($event)" />
4836
+ }
4837
+ </th>
4838
+ }
4839
+ @if (config.expandable) {
4840
+ <th style="width: 36px;"></th>
4841
+ }
4842
+ @for (col of visibleColumns(); track col.key) {
4843
+ <th cdkDrag [cdkDragDisabled]="!config.columnReorder" [style.width]="col.width" [style.min-width]="col.minWidth" [style.text-align]="col.align || 'left'" [class.sortable]="col.sortable" (click)="col.sortable ? toggleSort(col.key) : null">
4844
+ {{ col.label }} @if (col.sortable && sortKey() === col.key) { <span class="sort-indicator">{{ sortDirection() === 'asc' ? '↑' : '↓' }}</span> }
4845
+ </th>
4846
+ }
4847
+ @if (config.actions?.length) { <th class="actions-col">Actions</th> }
4848
+ </tr>
4849
+ </thead>
4850
+ <tbody cdkDropList (cdkDropListDropped)="dropRow($event)">
4851
+ @for (row of groupedRows(); track $index) {
4852
+ @if (row.__isGroupHeader) {
4853
+ <tr class="group-header-row">
4854
+ <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + (config.expandable ? 1 : 0) + (config.actions?.length ? 1 : 0)">
4855
+ <button class="group-toggle" (click)="toggleGroup(row.__groupKey)">
4856
+ <span class="group-chevron" [class.open]="!collapsedGroups().has(row.__groupKey)">▶</span>
4857
+ {{ config.groupBy }}: <strong>{{ row.__groupKey }}</strong>
4858
+ <span class="group-count">({{ row.__count }} items)</span>
4859
+ </button>
4860
+ </td>
4861
+ </tr>
4862
+ } @else {
4863
+ <tr cdkDrag [cdkDragDisabled]="!config.reorderable" (click)="handleRowClick(row)" [class.clickable]="config.rowClick || config.selectionMode === 'single' || config.selectionMode === 'multi'" [class.selected]="selectedRows().has(row)" [class.expanded]="expandedRows().has(row)">
4864
+ @if (config.reorderable) {
4865
+ <td class="drag-cell" (click)="$event.stopPropagation()" cdkDragHandle>
4866
+ <svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:var(--app-text-muted)"><path [attr.d]="iconRegistry.getIcon('menu')"></path></svg>
4867
+ </td>
4868
+ }
4869
+ @if (config.selectionMode === 'checkbox') {
4870
+ <td class="selection-cell" (click)="$event.stopPropagation(); toggleSelection(row)">
4871
+ <input type="checkbox" class="amf-checkbox" [checked]="selectedRows().has(row)" (click)="$event.stopPropagation()" (change)="$event.stopPropagation(); toggleSelection(row)" />
4872
+ </td>
4873
+ }
4874
+ @if (config.expandable) {
4875
+ <td class="expand-cell" (click)="$event.stopPropagation(); toggleRowExpand(row)">
4876
+ <span class="expand-chevron" [class.open]="expandedRows().has(row)">▶</span>
4877
+ </td>
4878
+ }
4879
+ @for (col of visibleColumns(); track col.key) {
4880
+ <td [style.text-align]="col.align || 'left'" (dblclick)="config.inlineEdit && col.editable !== false ? startEdit(row, col.key, $event) : null" [class.editable-cell]="config.inlineEdit && col.editable !== false">
4881
+ @if (isEditing(row, col.key)) {
4882
+ <div class="inline-edit-wrap" (click)="$event.stopPropagation()">
4883
+ <div class="inline-edit-row">
4884
+ @if (col.editType === 'select' && col.editOptions) {
4885
+ <select class="inline-input" [(ngModel)]="editBuffer[col.key]">
4886
+ @for (opt of col.editOptions; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
4887
+ </select>
4888
+ } @else {
4889
+ <input class="inline-input" [type]="col.editType || 'text'" [(ngModel)]="editBuffer[col.key]" (keydown.enter)="commitEdit(row, col.key)" (keydown.escape)="cancelEdit()" />
4890
+ }
4891
+ <div class="inline-edit-actions">
4892
+ <button class="ie-btn ie-save" title="Save (Enter)" (click)="commitEdit(row, col.key)">
4893
+ <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
4894
+ </button>
4895
+ <button class="ie-btn ie-cancel" title="Cancel (Esc)" (click)="cancelEdit()">
4896
+ <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
4897
+ </button>
4898
+ </div>
4899
+ </div>
4900
+ @if (editError()) {
4901
+ <span class="inline-edit-error">{{ editError() }}</span>
4902
+ }
4903
+ </div>
4904
+ } @else {
4905
+ <amf-cell-renderer [column]="col" [row]="row" [value]="getCellValue(row, col.key)"></amf-cell-renderer>
4906
+ }
4907
+ </td>
4908
+ }
4909
+ @if (config.actions?.length) {
4910
+ <td class="actions-cell">
4911
+ <div class="action-btns">
4912
+ @for (action of config.actions; track action.id) {
4913
+ <button class="action-btn" [class]="action.variant || 'ghost'" [title]="action.label" (click)="handleAction(action, row); $event.stopPropagation()">
4914
+ @if (action.icon) { <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> } @else { {{ action.label }} }
4915
+ </button>
4916
+ }
4917
+ </div>
4918
+ </td>
4919
+ }
4920
+ </tr>
4921
+ @if (config.expandable && expandedRows().has(row)) {
4922
+ <tr class="expanded-row">
4923
+ <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + 1 + (config.actions?.length ? 1 : 0)" class="expanded-content">
4924
+ @if (config.expandSection) {
4925
+ <div class="expand-section">Row detail: {{ row | json }}</div>
4926
+ } @else {
4927
+ <div class="expand-section">
4928
+ @for (col of visibleColumns(); track col.key) {
4929
+ <div class="expand-field"><span class="expand-label">{{ col.label }}:</span> <span>{{ getCellValue(row, col.key) }}</span></div>
4930
+ }
4931
+ </div>
4932
+ }
4933
+ </td>
4934
+ </tr>
4935
+ }
4936
+ }
4937
+ } @empty { <tr><td [attr.colspan]="visibleColumns().length + (config.actions?.length ? 1 : 0)" class="empty-state">{{ config.emptyMessage || 'No data found.' }}</td></tr> }
4938
+ @if (config.aggregates?.length) {
4939
+ <tr class="aggregate-row">
4940
+ @if (config.reorderable) { <td></td> }
4941
+ @if (config.selectionMode === 'checkbox') { <td></td> }
4942
+ @if (config.expandable) { <td></td> }
4943
+ @for (col of visibleColumns(); track col.key) {
4944
+ <td class="aggregate-cell" [style.text-align]="col.align || 'right'">
4945
+ @if (getAggregate(col.key); as agg) { <span class="agg-value">{{ agg.label ? agg.label + ': ' : '' }}{{ agg.value }}</span> }
4946
+ </td>
4947
+ }
4948
+ @if (config.actions?.length) { <td></td> }
4949
+ </tr>
4950
+ }
4951
+ </tbody>
4952
+ </table>
4953
+ </div>
4954
+ @if (config.pagination?.enabled) {
4955
+ <div class="table-footer">
4956
+ <div class="footer-left">
4957
+ <span class="results-count">Showing {{ paginatedData().length }} of {{ filteredData().length }} @if (config.pagination?.showTotal) { (total: {{ allData().length }}) }</span>
4958
+ @if ((config.pagination?.pageSizeOptions || [5, 10, 25, 50]).length > 1) {
4959
+ <div class="page-size-wrap">
4960
+ <label class="page-size-label">Rows:</label>
4961
+ <select class="page-size-select" [ngModel]="activePageSize()" (ngModelChange)="setPageSize($event)">
4962
+ @for (opt of config.pagination?.pageSizeOptions || [5, 10, 25, 50]; track opt) {
4963
+ <option [value]="opt">{{ opt }}</option>
4964
+ }
4965
+ </select>
4966
+ </div>
4967
+ }
4968
+ </div>
4969
+ <div class="pagination">
4970
+ <button class="btn-page-nav" [disabled]="currentPage() <= 1" (click)="currentPage.set(currentPage() - 1)">Previous</button>
4971
+ @for (p of pageNumbers(); track p) { <button class="btn-page" [class.active]="p === currentPage()" (click)="currentPage.set(p)">{{ p }}</button> }
4972
+ <button class="btn-page-nav" [disabled]="currentPage() >= totalPages()" (click)="currentPage.set(currentPage() + 1)">Next</button>
4973
+ </div>
4974
+ </div>
4975
+ }
4976
+ </div>
4977
4977
  `, isInline: true, styles: [".amf-table-card{background:var(--app-surface);border:1px solid var(--app-border);border-radius:16px;overflow:hidden;box-shadow:0 1px 3px #0000000d}.table-header{padding:16px 20px;display:flex;justify-content:space-between;align-items:center;gap:16px;border-bottom:1px solid var(--app-border);flex-wrap:wrap}.table-header-left,.table-header-right{display:flex;align-items:center;gap:12px}.search-box{position:relative;min-width:240px}.search-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;fill:var(--app-text-muted)}.search-box input{width:100%;padding:8px 12px 8px 36px;border:1px solid var(--app-border);border-radius:8px;font-size:.8125rem;outline:none;background:var(--glass-bg);color:var(--app-text)}.search-box input:focus{border-color:var(--app-primary)}.filter-select{padding:8px 12px;border:1px solid var(--app-border);border-radius:8px;font-size:.8125rem;outline:none;background:var(--glass-bg);color:var(--app-text);color-scheme:dark}.filter-select option{background-color:#1e1e2d;color:#fff}:host-context([data-color-scheme=\"light\"]) .filter-select{color-scheme:light}:host-context([data-color-scheme=\"light\"]) .filter-select option{background-color:#fff;color:#000}.table-wrapper{width:100%;overflow-x:auto}.data-table{width:100%;border-collapse:collapse;white-space:normal;word-break:break-word}.data-table th{background:var(--app-bg);padding:10px 20px;font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--app-text-muted);border-bottom:1px solid var(--app-border);-webkit-user-select:none;user-select:none}.data-table th.sortable{cursor:pointer}.data-table th.sortable:hover{color:var(--app-primary)}.sort-indicator{margin-left:4px;font-size:.75rem}.data-table td{padding:14px 20px;border-bottom:1px solid var(--app-border);font-size:.875rem;color:var(--app-text)}.data-table.hoverable tbody tr:hover{background:var(--glass-bg)}.data-table.striped tbody tr:nth-child(2n){background:var(--glass-bg)}.variant-striped .data-table tbody tr:nth-child(2n){background:var(--glass-bg)}.variant-borderless{border:none!important;box-shadow:none!important;background:transparent!important}.variant-borderless .table-header{border-bottom:none;padding:0 0 16px}.variant-borderless .data-table th{background:transparent;border-bottom:2px solid var(--app-border)}.variant-borderless .data-table td{border-bottom:1px dashed var(--app-border)}.variant-borderless .table-footer{border-top:none;background:transparent;padding:16px 0 0}.variant-glass{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);box-shadow:var(--glass-shadow-sm)}.variant-glass .table-header,.variant-glass .table-footer,.variant-glass .data-table th{background:transparent;border-color:var(--glass-border)}.variant-glass .data-table td{border-bottom:1px solid var(--glass-border)}.variant-elevated{box-shadow:0 20px 40px var(--glass-shadow);transform:translateY(-2px);transition:all .3s ease}.variant-compact .table-header{padding:12px 16px}.variant-compact .data-table th{padding:8px 16px;font-size:.625rem}.variant-compact .data-table td{padding:8px 16px;font-size:.8125rem}.variant-compact .table-footer{padding:8px 16px}tr.clickable{cursor:pointer}.amf-checkbox{width:16px;height:16px;cursor:pointer;accent-color:var(--app-primary)}.data-table tbody tr.selected{background:#3b82f626!important}.actions-col{text-align:right!important;width:120px}.actions-cell{text-align:right}.action-btns{display:flex;justify-content:flex-end;gap:6px}.action-btn{width:30px;height:30px;border-radius:6px;border:1px solid var(--app-border);background:transparent;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.action-btn svg{width:14px;height:14px;fill:var(--app-text-muted)}.action-btn:hover{border-color:var(--app-primary)}.action-btn:hover svg{fill:var(--app-primary)}.action-btn.danger:hover{border-color:#f43f5e}.action-btn.danger:hover svg{fill:#f43f5e}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;display:flex;align-items:center;gap:6px;transition:all .2s}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px var(--app-glow)}.btn-icon{width:16px;height:16px;fill:currentColor}.btn-sm{padding:6px 12px;font-size:.75rem;border-radius:6px}.btn-ghost{background:transparent;border:1px solid var(--app-border);color:var(--app-text);padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;display:flex;align-items:center;gap:6px;cursor:pointer;transition:all .2s}.btn-ghost:hover{background:var(--glass-bg-hover);color:var(--app-primary)}.export-container{position:relative}.export-menu{position:absolute;top:calc(100% + 8px);right:0;background:var(--app-surface);border:1px solid var(--app-border);border-radius:12px;box-shadow:0 10px 40px #00000080;min-width:160px;z-index:100;overflow:hidden;animation:slideInDown .2s ease-out backwards}.export-menu .dropdown-item{padding:10px 16px;font-size:.8125rem;font-weight:500;cursor:pointer;color:var(--app-text);transition:background .2s}.export-menu .dropdown-item:hover{background:var(--glass-bg-hover);color:var(--app-primary)}.empty-state{text-align:center;padding:40px!important;color:var(--app-text-muted)}.table-footer{padding:12px 20px;display:flex;justify-content:space-between;align-items:center;background:var(--app-bg);border-top:1px solid var(--app-border)}.footer-left{display:flex;align-items:center;gap:16px}.results-count{font-size:.75rem;color:var(--app-text-muted)}.page-size-wrap{display:flex;align-items:center;gap:6px}.page-size-label{font-size:.75rem;color:var(--app-text-muted);white-space:nowrap}.page-size-select{padding:4px 8px;border:1px solid var(--app-border);border-radius:6px;font-size:.75rem;background:var(--glass-bg);color:var(--app-text);outline:none;cursor:pointer;color-scheme:dark}.page-size-select option{background-color:#1a1a2e;color:#fff}:host-context([data-color-scheme=\"light\"]) .page-size-select{color-scheme:light}:host-context([data-color-scheme=\"light\"]) .page-size-select option{background-color:#fff;color:#000}.pagination{display:flex;gap:4px}.btn-page,.btn-page-nav{padding:6px 10px;border:1px solid var(--app-border);background:transparent;border-radius:6px;font-size:.75rem;font-weight:500;color:var(--app-text);cursor:pointer}.btn-page.active{background:var(--app-primary);border-color:var(--app-primary);color:#fff}.btn-page-nav:disabled{opacity:.4;cursor:not-allowed}.editable-cell{position:relative}.editable-cell:hover{background:#3b82f614;cursor:text}.inline-edit-wrap{display:flex;flex-direction:column;gap:4px;min-width:0}.inline-edit-row{display:flex;align-items:center;gap:4px}.inline-input{flex:1;min-width:0;padding:5px 8px;border:1.5px solid var(--app-primary);border-radius:6px;background:var(--app-surface);color:var(--app-text);font-size:.875rem;outline:none}.inline-input.input-invalid{border-color:#f43f5e}.inline-edit-error{font-size:.6875rem;color:#f43f5e;font-weight:500;padding:0 2px;animation:fadeIn .15s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.inline-edit-actions{display:flex;gap:3px;flex-shrink:0}.ie-btn{width:26px;height:26px;border-radius:5px;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:opacity .15s}.ie-btn svg{width:14px;height:14px;fill:currentColor}.ie-btn:hover{opacity:.85}.ie-save{background:#22c55e;color:#fff}.ie-cancel{background:var(--app-border);color:var(--app-text-muted)}select.inline-input{color-scheme:dark;cursor:pointer}select.inline-input option{background-color:#1a1a2e;color:#fff}:host-context([data-color-scheme=\"light\"]) select.inline-input{color-scheme:light}:host-context([data-color-scheme=\"light\"]) select.inline-input option{background-color:#fff;color:#000}.expand-cell{width:36px;text-align:center;cursor:pointer}.expand-chevron{display:inline-block;transition:transform .2s;font-size:.625rem;color:var(--app-text-muted)}.expand-chevron.open{transform:rotate(90deg)}.expanded-row td,.expanded-content{padding:0!important}.expand-section{padding:14px 24px;display:flex;flex-wrap:wrap;gap:16px;background:var(--glass-bg);animation:fadeInUp .2s ease-out}.expand-field{display:flex;gap:8px;font-size:.8125rem}.expand-label{color:var(--app-text-muted);font-weight:600}.group-header-row td{background:var(--app-bg)}.group-toggle{display:flex;align-items:center;gap:8px;background:none;border:none;color:var(--app-text);cursor:pointer;font-size:.8125rem;padding:8px 16px}.group-chevron{display:inline-block;font-size:.625rem;transition:transform .2s;color:var(--app-text-muted)}.group-chevron.open{transform:rotate(90deg)}.group-count{color:var(--app-text-muted);font-size:.75rem}.aggregate-row td{background:var(--app-bg);border-top:2px solid var(--app-border)}.aggregate-cell{padding:10px 20px!important}.agg-value{font-size:.8125rem;font-weight:700;color:var(--app-primary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i2.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: CellRendererComponent, selector: "amf-cell-renderer", inputs: ["column", "row", "value"] }, { kind: "pipe", type: i1$1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
4978
4978
  }
4979
4979
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TableRendererComponent, decorators: [{
4980
4980
  type: Component,
4981
- args: [{ selector: 'amf-table-renderer', standalone: true, imports: [CommonModule, FormsModule, DragDropModule, CellRendererComponent], template: `
4982
- <div class="amf-table-card" [class]="'variant-' + (config.variant || 'default') + ' ' + (config.cssClass || '')">
4983
- <div class="table-header">
4984
- <div class="table-header-left">
4985
- @if (config.searchable) {
4986
- <div class="search-box">
4987
- <svg viewBox="0 0 24 24" class="search-icon"><path [attr.d]="iconRegistry.getIcon('search')"></path></svg>
4988
- <input type="text" [placeholder]="config.searchPlaceholder || 'Search...'" [ngModel]="searchQuery()" (ngModelChange)="searchQuery.set($event)" />
4989
- </div>
4990
- }
4991
- @for (filter of config.filters || []; track filter.key) {
4992
- <select class="filter-select" [ngModel]="getFilterValue(filter.key)" (ngModelChange)="setFilterValue(filter.key, $event)">
4993
- <option value="">{{ filter.label }}</option>
4994
- @for (opt of filter.options; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
4995
- </select>
4996
- }
4997
- </div>
4998
- <div class="table-header-right">
4999
- @for (action of config.headerActions || []; track action.id) {
5000
- <button class="btn-primary btn-sm" (click)="handleAction(action, null)">
5001
- @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
5002
- {{ action.label }}
5003
- </button>
5004
- }
5005
-
5006
- @if (config.exportable) {
5007
- <div class="export-container">
5008
- <button class="btn-ghost btn-sm" (click)="exportMenuOpen.set(!exportMenuOpen())">
5009
- <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon('download')"></path></svg>
5010
- Export
5011
- </button>
5012
- @if (exportMenuOpen()) {
5013
- <div class="dropdown-menu export-menu">
5014
- @for (format of config.exportFormats || ['csv', 'json']; track format) {
5015
- <div class="dropdown-item" (click)="exportData(format); exportMenuOpen.set(false)">
5016
- Export as {{ format | uppercase }}
5017
- </div>
5018
- }
5019
- </div>
5020
- }
5021
- </div>
5022
- }
5023
- </div>
5024
- </div>
5025
- <div class="table-wrapper">
5026
- <table class="data-table" [class.striped]="config.striped" [class.hoverable]="config.hoverable !== false">
5027
- <thead>
5028
- <tr cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="dropColumn($event)">
5029
- @if (config.reorderable) { <th class="drag-col" style="width: 40px; text-align: center;"></th> }
5030
- @if (config.selectionMode === 'checkbox') {
5031
- <th class="selection-col" style="width: 40px; text-align: center;">
5032
- @if (config.showSelectAll !== false) {
5033
- <input type="checkbox"
5034
- class="amf-checkbox"
5035
- [checked]="selectedRows().size > 0 && selectedRows().size === filteredData().length"
5036
- (change)="toggleAllSelection($event)" />
5037
- }
5038
- </th>
5039
- }
5040
- @if (config.expandable) {
5041
- <th style="width: 36px;"></th>
5042
- }
5043
- @for (col of visibleColumns(); track col.key) {
5044
- <th cdkDrag [cdkDragDisabled]="!config.columnReorder" [style.width]="col.width" [style.min-width]="col.minWidth" [style.text-align]="col.align || 'left'" [class.sortable]="col.sortable" (click)="col.sortable ? toggleSort(col.key) : null">
5045
- {{ col.label }} @if (col.sortable && sortKey() === col.key) { <span class="sort-indicator">{{ sortDirection() === 'asc' ? '↑' : '↓' }}</span> }
5046
- </th>
5047
- }
5048
- @if (config.actions?.length) { <th class="actions-col">Actions</th> }
5049
- </tr>
5050
- </thead>
5051
- <tbody cdkDropList (cdkDropListDropped)="dropRow($event)">
5052
- @for (row of groupedRows(); track $index) {
5053
- @if (row.__isGroupHeader) {
5054
- <tr class="group-header-row">
5055
- <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + (config.expandable ? 1 : 0) + (config.actions?.length ? 1 : 0)">
5056
- <button class="group-toggle" (click)="toggleGroup(row.__groupKey)">
5057
- <span class="group-chevron" [class.open]="!collapsedGroups().has(row.__groupKey)">▶</span>
5058
- {{ config.groupBy }}: <strong>{{ row.__groupKey }}</strong>
5059
- <span class="group-count">({{ row.__count }} items)</span>
5060
- </button>
5061
- </td>
5062
- </tr>
5063
- } @else {
5064
- <tr cdkDrag [cdkDragDisabled]="!config.reorderable" (click)="handleRowClick(row)" [class.clickable]="config.rowClick || config.selectionMode === 'single' || config.selectionMode === 'multi'" [class.selected]="selectedRows().has(row)" [class.expanded]="expandedRows().has(row)">
5065
- @if (config.reorderable) {
5066
- <td class="drag-cell" (click)="$event.stopPropagation()" cdkDragHandle>
5067
- <svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:var(--app-text-muted)"><path [attr.d]="iconRegistry.getIcon('menu')"></path></svg>
5068
- </td>
5069
- }
5070
- @if (config.selectionMode === 'checkbox') {
5071
- <td class="selection-cell" (click)="$event.stopPropagation(); toggleSelection(row)">
5072
- <input type="checkbox" class="amf-checkbox" [checked]="selectedRows().has(row)" (click)="$event.stopPropagation()" (change)="$event.stopPropagation(); toggleSelection(row)" />
5073
- </td>
5074
- }
5075
- @if (config.expandable) {
5076
- <td class="expand-cell" (click)="$event.stopPropagation(); toggleRowExpand(row)">
5077
- <span class="expand-chevron" [class.open]="expandedRows().has(row)">▶</span>
5078
- </td>
5079
- }
5080
- @for (col of visibleColumns(); track col.key) {
5081
- <td [style.text-align]="col.align || 'left'" (dblclick)="config.inlineEdit && col.editable !== false ? startEdit(row, col.key, $event) : null" [class.editable-cell]="config.inlineEdit && col.editable !== false">
5082
- @if (isEditing(row, col.key)) {
5083
- <div class="inline-edit-wrap" (click)="$event.stopPropagation()">
5084
- <div class="inline-edit-row">
5085
- @if (col.editType === 'select' && col.editOptions) {
5086
- <select class="inline-input" [(ngModel)]="editBuffer[col.key]">
5087
- @for (opt of col.editOptions; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
5088
- </select>
5089
- } @else {
5090
- <input class="inline-input" [type]="col.editType || 'text'" [(ngModel)]="editBuffer[col.key]" (keydown.enter)="commitEdit(row, col.key)" (keydown.escape)="cancelEdit()" />
5091
- }
5092
- <div class="inline-edit-actions">
5093
- <button class="ie-btn ie-save" title="Save (Enter)" (click)="commitEdit(row, col.key)">
5094
- <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
5095
- </button>
5096
- <button class="ie-btn ie-cancel" title="Cancel (Esc)" (click)="cancelEdit()">
5097
- <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
5098
- </button>
5099
- </div>
5100
- </div>
5101
- @if (editError()) {
5102
- <span class="inline-edit-error">{{ editError() }}</span>
5103
- }
5104
- </div>
5105
- } @else {
5106
- <amf-cell-renderer [column]="col" [row]="row" [value]="getCellValue(row, col.key)"></amf-cell-renderer>
5107
- }
5108
- </td>
5109
- }
5110
- @if (config.actions?.length) {
5111
- <td class="actions-cell">
5112
- <div class="action-btns">
5113
- @for (action of config.actions; track action.id) {
5114
- <button class="action-btn" [class]="action.variant || 'ghost'" [title]="action.label" (click)="handleAction(action, row); $event.stopPropagation()">
5115
- @if (action.icon) { <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> } @else { {{ action.label }} }
5116
- </button>
5117
- }
5118
- </div>
5119
- </td>
5120
- }
5121
- </tr>
5122
- @if (config.expandable && expandedRows().has(row)) {
5123
- <tr class="expanded-row">
5124
- <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + 1 + (config.actions?.length ? 1 : 0)" class="expanded-content">
5125
- @if (config.expandSection) {
5126
- <div class="expand-section">Row detail: {{ row | json }}</div>
5127
- } @else {
5128
- <div class="expand-section">
5129
- @for (col of visibleColumns(); track col.key) {
5130
- <div class="expand-field"><span class="expand-label">{{ col.label }}:</span> <span>{{ getCellValue(row, col.key) }}</span></div>
5131
- }
5132
- </div>
5133
- }
5134
- </td>
5135
- </tr>
5136
- }
5137
- }
5138
- } @empty { <tr><td [attr.colspan]="visibleColumns().length + (config.actions?.length ? 1 : 0)" class="empty-state">{{ config.emptyMessage || 'No data found.' }}</td></tr> }
5139
- @if (config.aggregates?.length) {
5140
- <tr class="aggregate-row">
5141
- @if (config.reorderable) { <td></td> }
5142
- @if (config.selectionMode === 'checkbox') { <td></td> }
5143
- @if (config.expandable) { <td></td> }
5144
- @for (col of visibleColumns(); track col.key) {
5145
- <td class="aggregate-cell" [style.text-align]="col.align || 'right'">
5146
- @if (getAggregate(col.key); as agg) { <span class="agg-value">{{ agg.label ? agg.label + ': ' : '' }}{{ agg.value }}</span> }
5147
- </td>
5148
- }
5149
- @if (config.actions?.length) { <td></td> }
5150
- </tr>
5151
- }
5152
- </tbody>
5153
- </table>
5154
- </div>
5155
- @if (config.pagination?.enabled) {
5156
- <div class="table-footer">
5157
- <div class="footer-left">
5158
- <span class="results-count">Showing {{ paginatedData().length }} of {{ filteredData().length }} @if (config.pagination?.showTotal) { (total: {{ allData().length }}) }</span>
5159
- @if ((config.pagination?.pageSizeOptions || [5, 10, 25, 50]).length > 1) {
5160
- <div class="page-size-wrap">
5161
- <label class="page-size-label">Rows:</label>
5162
- <select class="page-size-select" [ngModel]="activePageSize()" (ngModelChange)="setPageSize($event)">
5163
- @for (opt of config.pagination?.pageSizeOptions || [5, 10, 25, 50]; track opt) {
5164
- <option [value]="opt">{{ opt }}</option>
5165
- }
5166
- </select>
5167
- </div>
5168
- }
5169
- </div>
5170
- <div class="pagination">
5171
- <button class="btn-page-nav" [disabled]="currentPage() <= 1" (click)="currentPage.set(currentPage() - 1)">Previous</button>
5172
- @for (p of pageNumbers(); track p) { <button class="btn-page" [class.active]="p === currentPage()" (click)="currentPage.set(p)">{{ p }}</button> }
5173
- <button class="btn-page-nav" [disabled]="currentPage() >= totalPages()" (click)="currentPage.set(currentPage() + 1)">Next</button>
5174
- </div>
5175
- </div>
5176
- }
5177
- </div>
4981
+ args: [{ selector: 'amf-table-renderer', standalone: true, imports: [CommonModule, FormsModule, DragDropModule, CellRendererComponent], template: `
4982
+ <div class="amf-table-card" [class]="'variant-' + (config.variant || 'default') + ' ' + (config.cssClass || '')">
4983
+ <div class="table-header">
4984
+ <div class="table-header-left">
4985
+ @if (config.searchable) {
4986
+ <div class="search-box">
4987
+ <svg viewBox="0 0 24 24" class="search-icon"><path [attr.d]="iconRegistry.getIcon('search')"></path></svg>
4988
+ <input type="text" [placeholder]="config.searchPlaceholder || 'Search...'" [ngModel]="searchQuery()" (ngModelChange)="searchQuery.set($event)" />
4989
+ </div>
4990
+ }
4991
+ @for (filter of config.filters || []; track filter.key) {
4992
+ <select class="filter-select" [ngModel]="getFilterValue(filter.key)" (ngModelChange)="setFilterValue(filter.key, $event)">
4993
+ <option value="">{{ filter.label }}</option>
4994
+ @for (opt of filter.options; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
4995
+ </select>
4996
+ }
4997
+ </div>
4998
+ <div class="table-header-right">
4999
+ @for (action of config.headerActions || []; track action.id) {
5000
+ <button class="btn-primary btn-sm" (click)="handleAction(action, null)">
5001
+ @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
5002
+ {{ action.label }}
5003
+ </button>
5004
+ }
5005
+
5006
+ @if (config.exportable) {
5007
+ <div class="export-container">
5008
+ <button class="btn-ghost btn-sm" (click)="exportMenuOpen.set(!exportMenuOpen())">
5009
+ <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon('download')"></path></svg>
5010
+ Export
5011
+ </button>
5012
+ @if (exportMenuOpen()) {
5013
+ <div class="dropdown-menu export-menu">
5014
+ @for (format of config.exportFormats || ['csv', 'json']; track format) {
5015
+ <div class="dropdown-item" (click)="exportData(format); exportMenuOpen.set(false)">
5016
+ Export as {{ format | uppercase }}
5017
+ </div>
5018
+ }
5019
+ </div>
5020
+ }
5021
+ </div>
5022
+ }
5023
+ </div>
5024
+ </div>
5025
+ <div class="table-wrapper">
5026
+ <table class="data-table" [class.striped]="config.striped" [class.hoverable]="config.hoverable !== false">
5027
+ <thead>
5028
+ <tr cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="dropColumn($event)">
5029
+ @if (config.reorderable) { <th class="drag-col" style="width: 40px; text-align: center;"></th> }
5030
+ @if (config.selectionMode === 'checkbox') {
5031
+ <th class="selection-col" style="width: 40px; text-align: center;">
5032
+ @if (config.showSelectAll !== false) {
5033
+ <input type="checkbox"
5034
+ class="amf-checkbox"
5035
+ [checked]="selectedRows().size > 0 && selectedRows().size === filteredData().length"
5036
+ (change)="toggleAllSelection($event)" />
5037
+ }
5038
+ </th>
5039
+ }
5040
+ @if (config.expandable) {
5041
+ <th style="width: 36px;"></th>
5042
+ }
5043
+ @for (col of visibleColumns(); track col.key) {
5044
+ <th cdkDrag [cdkDragDisabled]="!config.columnReorder" [style.width]="col.width" [style.min-width]="col.minWidth" [style.text-align]="col.align || 'left'" [class.sortable]="col.sortable" (click)="col.sortable ? toggleSort(col.key) : null">
5045
+ {{ col.label }} @if (col.sortable && sortKey() === col.key) { <span class="sort-indicator">{{ sortDirection() === 'asc' ? '↑' : '↓' }}</span> }
5046
+ </th>
5047
+ }
5048
+ @if (config.actions?.length) { <th class="actions-col">Actions</th> }
5049
+ </tr>
5050
+ </thead>
5051
+ <tbody cdkDropList (cdkDropListDropped)="dropRow($event)">
5052
+ @for (row of groupedRows(); track $index) {
5053
+ @if (row.__isGroupHeader) {
5054
+ <tr class="group-header-row">
5055
+ <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + (config.expandable ? 1 : 0) + (config.actions?.length ? 1 : 0)">
5056
+ <button class="group-toggle" (click)="toggleGroup(row.__groupKey)">
5057
+ <span class="group-chevron" [class.open]="!collapsedGroups().has(row.__groupKey)">▶</span>
5058
+ {{ config.groupBy }}: <strong>{{ row.__groupKey }}</strong>
5059
+ <span class="group-count">({{ row.__count }} items)</span>
5060
+ </button>
5061
+ </td>
5062
+ </tr>
5063
+ } @else {
5064
+ <tr cdkDrag [cdkDragDisabled]="!config.reorderable" (click)="handleRowClick(row)" [class.clickable]="config.rowClick || config.selectionMode === 'single' || config.selectionMode === 'multi'" [class.selected]="selectedRows().has(row)" [class.expanded]="expandedRows().has(row)">
5065
+ @if (config.reorderable) {
5066
+ <td class="drag-cell" (click)="$event.stopPropagation()" cdkDragHandle>
5067
+ <svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:var(--app-text-muted)"><path [attr.d]="iconRegistry.getIcon('menu')"></path></svg>
5068
+ </td>
5069
+ }
5070
+ @if (config.selectionMode === 'checkbox') {
5071
+ <td class="selection-cell" (click)="$event.stopPropagation(); toggleSelection(row)">
5072
+ <input type="checkbox" class="amf-checkbox" [checked]="selectedRows().has(row)" (click)="$event.stopPropagation()" (change)="$event.stopPropagation(); toggleSelection(row)" />
5073
+ </td>
5074
+ }
5075
+ @if (config.expandable) {
5076
+ <td class="expand-cell" (click)="$event.stopPropagation(); toggleRowExpand(row)">
5077
+ <span class="expand-chevron" [class.open]="expandedRows().has(row)">▶</span>
5078
+ </td>
5079
+ }
5080
+ @for (col of visibleColumns(); track col.key) {
5081
+ <td [style.text-align]="col.align || 'left'" (dblclick)="config.inlineEdit && col.editable !== false ? startEdit(row, col.key, $event) : null" [class.editable-cell]="config.inlineEdit && col.editable !== false">
5082
+ @if (isEditing(row, col.key)) {
5083
+ <div class="inline-edit-wrap" (click)="$event.stopPropagation()">
5084
+ <div class="inline-edit-row">
5085
+ @if (col.editType === 'select' && col.editOptions) {
5086
+ <select class="inline-input" [(ngModel)]="editBuffer[col.key]">
5087
+ @for (opt of col.editOptions; track opt.value) { <option [value]="opt.value">{{ opt.label }}</option> }
5088
+ </select>
5089
+ } @else {
5090
+ <input class="inline-input" [type]="col.editType || 'text'" [(ngModel)]="editBuffer[col.key]" (keydown.enter)="commitEdit(row, col.key)" (keydown.escape)="cancelEdit()" />
5091
+ }
5092
+ <div class="inline-edit-actions">
5093
+ <button class="ie-btn ie-save" title="Save (Enter)" (click)="commitEdit(row, col.key)">
5094
+ <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
5095
+ </button>
5096
+ <button class="ie-btn ie-cancel" title="Cancel (Esc)" (click)="cancelEdit()">
5097
+ <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
5098
+ </button>
5099
+ </div>
5100
+ </div>
5101
+ @if (editError()) {
5102
+ <span class="inline-edit-error">{{ editError() }}</span>
5103
+ }
5104
+ </div>
5105
+ } @else {
5106
+ <amf-cell-renderer [column]="col" [row]="row" [value]="getCellValue(row, col.key)"></amf-cell-renderer>
5107
+ }
5108
+ </td>
5109
+ }
5110
+ @if (config.actions?.length) {
5111
+ <td class="actions-cell">
5112
+ <div class="action-btns">
5113
+ @for (action of config.actions; track action.id) {
5114
+ <button class="action-btn" [class]="action.variant || 'ghost'" [title]="action.label" (click)="handleAction(action, row); $event.stopPropagation()">
5115
+ @if (action.icon) { <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> } @else { {{ action.label }} }
5116
+ </button>
5117
+ }
5118
+ </div>
5119
+ </td>
5120
+ }
5121
+ </tr>
5122
+ @if (config.expandable && expandedRows().has(row)) {
5123
+ <tr class="expanded-row">
5124
+ <td [attr.colspan]="visibleColumns().length + (config.reorderable ? 1 : 0) + (config.selectionMode === 'checkbox' ? 1 : 0) + 1 + (config.actions?.length ? 1 : 0)" class="expanded-content">
5125
+ @if (config.expandSection) {
5126
+ <div class="expand-section">Row detail: {{ row | json }}</div>
5127
+ } @else {
5128
+ <div class="expand-section">
5129
+ @for (col of visibleColumns(); track col.key) {
5130
+ <div class="expand-field"><span class="expand-label">{{ col.label }}:</span> <span>{{ getCellValue(row, col.key) }}</span></div>
5131
+ }
5132
+ </div>
5133
+ }
5134
+ </td>
5135
+ </tr>
5136
+ }
5137
+ }
5138
+ } @empty { <tr><td [attr.colspan]="visibleColumns().length + (config.actions?.length ? 1 : 0)" class="empty-state">{{ config.emptyMessage || 'No data found.' }}</td></tr> }
5139
+ @if (config.aggregates?.length) {
5140
+ <tr class="aggregate-row">
5141
+ @if (config.reorderable) { <td></td> }
5142
+ @if (config.selectionMode === 'checkbox') { <td></td> }
5143
+ @if (config.expandable) { <td></td> }
5144
+ @for (col of visibleColumns(); track col.key) {
5145
+ <td class="aggregate-cell" [style.text-align]="col.align || 'right'">
5146
+ @if (getAggregate(col.key); as agg) { <span class="agg-value">{{ agg.label ? agg.label + ': ' : '' }}{{ agg.value }}</span> }
5147
+ </td>
5148
+ }
5149
+ @if (config.actions?.length) { <td></td> }
5150
+ </tr>
5151
+ }
5152
+ </tbody>
5153
+ </table>
5154
+ </div>
5155
+ @if (config.pagination?.enabled) {
5156
+ <div class="table-footer">
5157
+ <div class="footer-left">
5158
+ <span class="results-count">Showing {{ paginatedData().length }} of {{ filteredData().length }} @if (config.pagination?.showTotal) { (total: {{ allData().length }}) }</span>
5159
+ @if ((config.pagination?.pageSizeOptions || [5, 10, 25, 50]).length > 1) {
5160
+ <div class="page-size-wrap">
5161
+ <label class="page-size-label">Rows:</label>
5162
+ <select class="page-size-select" [ngModel]="activePageSize()" (ngModelChange)="setPageSize($event)">
5163
+ @for (opt of config.pagination?.pageSizeOptions || [5, 10, 25, 50]; track opt) {
5164
+ <option [value]="opt">{{ opt }}</option>
5165
+ }
5166
+ </select>
5167
+ </div>
5168
+ }
5169
+ </div>
5170
+ <div class="pagination">
5171
+ <button class="btn-page-nav" [disabled]="currentPage() <= 1" (click)="currentPage.set(currentPage() - 1)">Previous</button>
5172
+ @for (p of pageNumbers(); track p) { <button class="btn-page" [class.active]="p === currentPage()" (click)="currentPage.set(p)">{{ p }}</button> }
5173
+ <button class="btn-page-nav" [disabled]="currentPage() >= totalPages()" (click)="currentPage.set(currentPage() + 1)">Next</button>
5174
+ </div>
5175
+ </div>
5176
+ }
5177
+ </div>
5178
5178
  `, styles: [".amf-table-card{background:var(--app-surface);border:1px solid var(--app-border);border-radius:16px;overflow:hidden;box-shadow:0 1px 3px #0000000d}.table-header{padding:16px 20px;display:flex;justify-content:space-between;align-items:center;gap:16px;border-bottom:1px solid var(--app-border);flex-wrap:wrap}.table-header-left,.table-header-right{display:flex;align-items:center;gap:12px}.search-box{position:relative;min-width:240px}.search-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;fill:var(--app-text-muted)}.search-box input{width:100%;padding:8px 12px 8px 36px;border:1px solid var(--app-border);border-radius:8px;font-size:.8125rem;outline:none;background:var(--glass-bg);color:var(--app-text)}.search-box input:focus{border-color:var(--app-primary)}.filter-select{padding:8px 12px;border:1px solid var(--app-border);border-radius:8px;font-size:.8125rem;outline:none;background:var(--glass-bg);color:var(--app-text);color-scheme:dark}.filter-select option{background-color:#1e1e2d;color:#fff}:host-context([data-color-scheme=\"light\"]) .filter-select{color-scheme:light}:host-context([data-color-scheme=\"light\"]) .filter-select option{background-color:#fff;color:#000}.table-wrapper{width:100%;overflow-x:auto}.data-table{width:100%;border-collapse:collapse;white-space:normal;word-break:break-word}.data-table th{background:var(--app-bg);padding:10px 20px;font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--app-text-muted);border-bottom:1px solid var(--app-border);-webkit-user-select:none;user-select:none}.data-table th.sortable{cursor:pointer}.data-table th.sortable:hover{color:var(--app-primary)}.sort-indicator{margin-left:4px;font-size:.75rem}.data-table td{padding:14px 20px;border-bottom:1px solid var(--app-border);font-size:.875rem;color:var(--app-text)}.data-table.hoverable tbody tr:hover{background:var(--glass-bg)}.data-table.striped tbody tr:nth-child(2n){background:var(--glass-bg)}.variant-striped .data-table tbody tr:nth-child(2n){background:var(--glass-bg)}.variant-borderless{border:none!important;box-shadow:none!important;background:transparent!important}.variant-borderless .table-header{border-bottom:none;padding:0 0 16px}.variant-borderless .data-table th{background:transparent;border-bottom:2px solid var(--app-border)}.variant-borderless .data-table td{border-bottom:1px dashed var(--app-border)}.variant-borderless .table-footer{border-top:none;background:transparent;padding:16px 0 0}.variant-glass{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);box-shadow:var(--glass-shadow-sm)}.variant-glass .table-header,.variant-glass .table-footer,.variant-glass .data-table th{background:transparent;border-color:var(--glass-border)}.variant-glass .data-table td{border-bottom:1px solid var(--glass-border)}.variant-elevated{box-shadow:0 20px 40px var(--glass-shadow);transform:translateY(-2px);transition:all .3s ease}.variant-compact .table-header{padding:12px 16px}.variant-compact .data-table th{padding:8px 16px;font-size:.625rem}.variant-compact .data-table td{padding:8px 16px;font-size:.8125rem}.variant-compact .table-footer{padding:8px 16px}tr.clickable{cursor:pointer}.amf-checkbox{width:16px;height:16px;cursor:pointer;accent-color:var(--app-primary)}.data-table tbody tr.selected{background:#3b82f626!important}.actions-col{text-align:right!important;width:120px}.actions-cell{text-align:right}.action-btns{display:flex;justify-content:flex-end;gap:6px}.action-btn{width:30px;height:30px;border-radius:6px;border:1px solid var(--app-border);background:transparent;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.action-btn svg{width:14px;height:14px;fill:var(--app-text-muted)}.action-btn:hover{border-color:var(--app-primary)}.action-btn:hover svg{fill:var(--app-primary)}.action-btn.danger:hover{border-color:#f43f5e}.action-btn.danger:hover svg{fill:#f43f5e}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;display:flex;align-items:center;gap:6px;transition:all .2s}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px var(--app-glow)}.btn-icon{width:16px;height:16px;fill:currentColor}.btn-sm{padding:6px 12px;font-size:.75rem;border-radius:6px}.btn-ghost{background:transparent;border:1px solid var(--app-border);color:var(--app-text);padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;display:flex;align-items:center;gap:6px;cursor:pointer;transition:all .2s}.btn-ghost:hover{background:var(--glass-bg-hover);color:var(--app-primary)}.export-container{position:relative}.export-menu{position:absolute;top:calc(100% + 8px);right:0;background:var(--app-surface);border:1px solid var(--app-border);border-radius:12px;box-shadow:0 10px 40px #00000080;min-width:160px;z-index:100;overflow:hidden;animation:slideInDown .2s ease-out backwards}.export-menu .dropdown-item{padding:10px 16px;font-size:.8125rem;font-weight:500;cursor:pointer;color:var(--app-text);transition:background .2s}.export-menu .dropdown-item:hover{background:var(--glass-bg-hover);color:var(--app-primary)}.empty-state{text-align:center;padding:40px!important;color:var(--app-text-muted)}.table-footer{padding:12px 20px;display:flex;justify-content:space-between;align-items:center;background:var(--app-bg);border-top:1px solid var(--app-border)}.footer-left{display:flex;align-items:center;gap:16px}.results-count{font-size:.75rem;color:var(--app-text-muted)}.page-size-wrap{display:flex;align-items:center;gap:6px}.page-size-label{font-size:.75rem;color:var(--app-text-muted);white-space:nowrap}.page-size-select{padding:4px 8px;border:1px solid var(--app-border);border-radius:6px;font-size:.75rem;background:var(--glass-bg);color:var(--app-text);outline:none;cursor:pointer;color-scheme:dark}.page-size-select option{background-color:#1a1a2e;color:#fff}:host-context([data-color-scheme=\"light\"]) .page-size-select{color-scheme:light}:host-context([data-color-scheme=\"light\"]) .page-size-select option{background-color:#fff;color:#000}.pagination{display:flex;gap:4px}.btn-page,.btn-page-nav{padding:6px 10px;border:1px solid var(--app-border);background:transparent;border-radius:6px;font-size:.75rem;font-weight:500;color:var(--app-text);cursor:pointer}.btn-page.active{background:var(--app-primary);border-color:var(--app-primary);color:#fff}.btn-page-nav:disabled{opacity:.4;cursor:not-allowed}.editable-cell{position:relative}.editable-cell:hover{background:#3b82f614;cursor:text}.inline-edit-wrap{display:flex;flex-direction:column;gap:4px;min-width:0}.inline-edit-row{display:flex;align-items:center;gap:4px}.inline-input{flex:1;min-width:0;padding:5px 8px;border:1.5px solid var(--app-primary);border-radius:6px;background:var(--app-surface);color:var(--app-text);font-size:.875rem;outline:none}.inline-input.input-invalid{border-color:#f43f5e}.inline-edit-error{font-size:.6875rem;color:#f43f5e;font-weight:500;padding:0 2px;animation:fadeIn .15s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.inline-edit-actions{display:flex;gap:3px;flex-shrink:0}.ie-btn{width:26px;height:26px;border-radius:5px;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:opacity .15s}.ie-btn svg{width:14px;height:14px;fill:currentColor}.ie-btn:hover{opacity:.85}.ie-save{background:#22c55e;color:#fff}.ie-cancel{background:var(--app-border);color:var(--app-text-muted)}select.inline-input{color-scheme:dark;cursor:pointer}select.inline-input option{background-color:#1a1a2e;color:#fff}:host-context([data-color-scheme=\"light\"]) select.inline-input{color-scheme:light}:host-context([data-color-scheme=\"light\"]) select.inline-input option{background-color:#fff;color:#000}.expand-cell{width:36px;text-align:center;cursor:pointer}.expand-chevron{display:inline-block;transition:transform .2s;font-size:.625rem;color:var(--app-text-muted)}.expand-chevron.open{transform:rotate(90deg)}.expanded-row td,.expanded-content{padding:0!important}.expand-section{padding:14px 24px;display:flex;flex-wrap:wrap;gap:16px;background:var(--glass-bg);animation:fadeInUp .2s ease-out}.expand-field{display:flex;gap:8px;font-size:.8125rem}.expand-label{color:var(--app-text-muted);font-weight:600}.group-header-row td{background:var(--app-bg)}.group-toggle{display:flex;align-items:center;gap:8px;background:none;border:none;color:var(--app-text);cursor:pointer;font-size:.8125rem;padding:8px 16px}.group-chevron{display:inline-block;font-size:.625rem;transition:transform .2s;color:var(--app-text-muted)}.group-chevron.open{transform:rotate(90deg)}.group-count{color:var(--app-text-muted);font-size:.75rem}.aggregate-row td{background:var(--app-bg);border-top:2px solid var(--app-border)}.aggregate-cell{padding:10px 20px!important}.agg-value{font-size:.8125rem;font-weight:700;color:var(--app-primary)}\n"] }]
5179
5179
  }], propDecorators: { config: [{
5180
5180
  type: Input
@@ -5196,44 +5196,44 @@ class CardSectionComponent {
5196
5196
  return this.sanitizer.bypassSecurityTrustHtml(this.config.content || '');
5197
5197
  }
5198
5198
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5199
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CardSectionComponent, isStandalone: true, selector: "amf-card", inputs: { config: "config", context: "context" }, ngImport: i0, template: `
5200
- <div class="amf-card" [class]="'variant-' + (config.variant || 'glass')">
5201
- @if (config.title) { <h2 class="card-title">{{ config.title }}</h2> }
5202
- @if (config.content) { <div class="card-content" [innerHTML]="trustedContent"></div> }
5203
- @if (config.sections?.length) {
5204
- <div class="card-sections">
5205
- @for (nested of config.sections; track nested.id) {
5206
- <amf-renderer [section]="nested" [context]="context" class="card-nested-section"></amf-renderer>
5207
- }
5208
- </div>
5209
- }
5210
- @if (config.actions?.length) {
5211
- <div class="card-actions">
5212
- @for (action of config.actions; track action.label) { <button [class]="'btn-' + (action.variant || 'secondary')" (click)="actionDispatcher.dispatch(action.action, context)">{{ action.label }}</button> }
5213
- </div>
5214
- }
5215
- </div>
5199
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CardSectionComponent, isStandalone: true, selector: "amf-card", inputs: { config: "config", context: "context" }, ngImport: i0, template: `
5200
+ <div class="amf-card" [class]="'variant-' + (config.variant || 'glass')">
5201
+ @if (config.title) { <h2 class="card-title">{{ config.title }}</h2> }
5202
+ @if (config.content) { <div class="card-content" [innerHTML]="trustedContent"></div> }
5203
+ @if (config.sections?.length) {
5204
+ <div class="card-sections">
5205
+ @for (nested of config.sections; track nested.id) {
5206
+ <amf-renderer [section]="nested" [context]="context" class="card-nested-section"></amf-renderer>
5207
+ }
5208
+ </div>
5209
+ }
5210
+ @if (config.actions?.length) {
5211
+ <div class="card-actions">
5212
+ @for (action of config.actions; track action.label) { <button [class]="'btn-' + (action.variant || 'secondary')" (click)="actionDispatcher.dispatch(action.action, context)">{{ action.label }}</button> }
5213
+ </div>
5214
+ }
5215
+ </div>
5216
5216
  `, isInline: true, styles: [".amf-card{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);border-radius:16px;padding:24px;box-shadow:var(--glass-shadow-sm);transition:all .3s cubic-bezier(.4,0,.2,1)}.amf-card:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light);box-shadow:var(--glass-shadow);transform:translateY(-2px)}.variant-default{background:var(--app-surface);border:1px solid var(--app-border);backdrop-filter:none;-webkit-backdrop-filter:none}.variant-outlined{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.variant-elevated{box-shadow:0 20px 40px var(--glass-shadow);transform:translateY(-4px)}.variant-gradient{background:linear-gradient(135deg,#3b82f626,#8b5cf626);border:1px solid rgba(139,92,246,.3)}.card-title{font-size:1.25rem;margin-bottom:16px}.card-content{color:var(--app-text-muted);font-size:.9375rem;line-height:1.6}.card-sections{display:flex;flex-direction:column;gap:16px;margin-top:16px}.card-nested-section{display:block}.card-actions{margin-top:20px;display:flex;gap:12px}.btn-secondary{background:var(--glass-bg);border:1px solid var(--app-border);color:var(--app-text);padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-secondary:hover{background:var(--glass-bg-hover)}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px var(--app-glow)}.btn-danger{background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-danger:hover{transform:translateY(-1px);box-shadow:0 4px 12px #ef444466}.btn-success{background:linear-gradient(135deg,#10b981,#059669);color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-success:hover{transform:translateY(-1px);box-shadow:0 4px 12px #10b98166}.btn-ghost{background:transparent;border:1px solid transparent;color:var(--app-text-muted);padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-ghost:hover{background:#ffffff0d;color:var(--app-text)}\n"], dependencies: [{ kind: "component", type: MetaRendererComponent, selector: "amf-renderer", inputs: ["section", "context"] }] });
5217
5217
  }
5218
5218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardSectionComponent, decorators: [{
5219
5219
  type: Component,
5220
- args: [{ selector: 'amf-card', standalone: true, imports: [MetaRendererComponent], template: `
5221
- <div class="amf-card" [class]="'variant-' + (config.variant || 'glass')">
5222
- @if (config.title) { <h2 class="card-title">{{ config.title }}</h2> }
5223
- @if (config.content) { <div class="card-content" [innerHTML]="trustedContent"></div> }
5224
- @if (config.sections?.length) {
5225
- <div class="card-sections">
5226
- @for (nested of config.sections; track nested.id) {
5227
- <amf-renderer [section]="nested" [context]="context" class="card-nested-section"></amf-renderer>
5228
- }
5229
- </div>
5230
- }
5231
- @if (config.actions?.length) {
5232
- <div class="card-actions">
5233
- @for (action of config.actions; track action.label) { <button [class]="'btn-' + (action.variant || 'secondary')" (click)="actionDispatcher.dispatch(action.action, context)">{{ action.label }}</button> }
5234
- </div>
5235
- }
5236
- </div>
5220
+ args: [{ selector: 'amf-card', standalone: true, imports: [MetaRendererComponent], template: `
5221
+ <div class="amf-card" [class]="'variant-' + (config.variant || 'glass')">
5222
+ @if (config.title) { <h2 class="card-title">{{ config.title }}</h2> }
5223
+ @if (config.content) { <div class="card-content" [innerHTML]="trustedContent"></div> }
5224
+ @if (config.sections?.length) {
5225
+ <div class="card-sections">
5226
+ @for (nested of config.sections; track nested.id) {
5227
+ <amf-renderer [section]="nested" [context]="context" class="card-nested-section"></amf-renderer>
5228
+ }
5229
+ </div>
5230
+ }
5231
+ @if (config.actions?.length) {
5232
+ <div class="card-actions">
5233
+ @for (action of config.actions; track action.label) { <button [class]="'btn-' + (action.variant || 'secondary')" (click)="actionDispatcher.dispatch(action.action, context)">{{ action.label }}</button> }
5234
+ </div>
5235
+ }
5236
+ </div>
5237
5237
  `, styles: [".amf-card{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);border-radius:16px;padding:24px;box-shadow:var(--glass-shadow-sm);transition:all .3s cubic-bezier(.4,0,.2,1)}.amf-card:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light);box-shadow:var(--glass-shadow);transform:translateY(-2px)}.variant-default{background:var(--app-surface);border:1px solid var(--app-border);backdrop-filter:none;-webkit-backdrop-filter:none}.variant-outlined{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.variant-elevated{box-shadow:0 20px 40px var(--glass-shadow);transform:translateY(-4px)}.variant-gradient{background:linear-gradient(135deg,#3b82f626,#8b5cf626);border:1px solid rgba(139,92,246,.3)}.card-title{font-size:1.25rem;margin-bottom:16px}.card-content{color:var(--app-text-muted);font-size:.9375rem;line-height:1.6}.card-sections{display:flex;flex-direction:column;gap:16px;margin-top:16px}.card-nested-section{display:block}.card-actions{margin-top:20px;display:flex;gap:12px}.btn-secondary{background:var(--glass-bg);border:1px solid var(--app-border);color:var(--app-text);padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-secondary:hover{background:var(--glass-bg-hover)}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px var(--app-glow)}.btn-danger{background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-danger:hover{transform:translateY(-1px);box-shadow:0 4px 12px #ef444466}.btn-success{background:linear-gradient(135deg,#10b981,#059669);color:#fff;border:none;padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-success:hover{transform:translateY(-1px);box-shadow:0 4px 12px #10b98166}.btn-ghost{background:transparent;border:1px solid transparent;color:var(--app-text-muted);padding:8px 16px;border-radius:8px;font-weight:600;font-size:.8125rem;cursor:pointer;transition:all .2s}.btn-ghost:hover{background:#ffffff0d;color:var(--app-text)}\n"] }]
5238
5238
  }], propDecorators: { config: [{
5239
5239
  type: Input
@@ -5250,46 +5250,46 @@ class StatsGridSectionComponent {
5250
5250
  iconRegistry = inject(IconRegistryService);
5251
5251
  get gridCols() { return `repeat(auto-fit, minmax(280px, 1fr))`; }
5252
5252
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StatsGridSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5253
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: StatsGridSectionComponent, isStandalone: true, selector: "amf-stats-grid", inputs: { config: "config", context: "context" }, ngImport: i0, template: `
5254
- <div class="amf-stats-grid" [style.grid-template-columns]="gridCols" [class]="'variant-' + (config.variant || 'glass')">
5255
- @for (stat of config.stats; track stat.label; let i = $index) {
5256
- <div class="stat-card" [style.animation-delay]="(i * 0.1) + 's'">
5257
- <div class="stat-glow" [style.background]="stat.glowColor || stat.color"></div>
5258
- @if (stat.icon) {
5259
- <div class="stat-icon" [style.color]="stat.color" [style.background]="stat.bgColor">
5260
- <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(stat.icon)"></path></svg>
5261
- </div>
5262
- }
5263
- <div class="stat-data">
5264
- <span class="stat-label">{{ stat.label }}</span>
5265
- <span class="stat-value">{{ stat.value }}</span>
5266
- @if (stat.trend) { <span class="stat-trend" [class.positive]="stat.trendPositive" [class.negative]="!stat.trendPositive">{{ stat.trend }}</span> }
5267
- </div>
5268
- </div>
5269
- }
5270
- </div>
5253
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: StatsGridSectionComponent, isStandalone: true, selector: "amf-stats-grid", inputs: { config: "config", context: "context" }, ngImport: i0, template: `
5254
+ <div class="amf-stats-grid" [style.grid-template-columns]="gridCols" [class]="'variant-' + (config.variant || 'glass')">
5255
+ @for (stat of config.stats; track stat.label; let i = $index) {
5256
+ <div class="stat-card" [style.animation-delay]="(i * 0.1) + 's'">
5257
+ <div class="stat-glow" [style.background]="stat.glowColor || stat.color"></div>
5258
+ @if (stat.icon) {
5259
+ <div class="stat-icon" [style.color]="stat.color" [style.background]="stat.bgColor">
5260
+ <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(stat.icon)"></path></svg>
5261
+ </div>
5262
+ }
5263
+ <div class="stat-data">
5264
+ <span class="stat-label">{{ stat.label }}</span>
5265
+ <span class="stat-value">{{ stat.value }}</span>
5266
+ @if (stat.trend) { <span class="stat-trend" [class.positive]="stat.trendPositive" [class.negative]="!stat.trendPositive">{{ stat.trend }}</span> }
5267
+ </div>
5268
+ </div>
5269
+ }
5270
+ </div>
5271
5271
  `, isInline: true, styles: [".amf-stats-grid{display:grid;gap:20px}.stat-card{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);border-radius:16px;padding:24px;display:flex;align-items:center;gap:20px;position:relative;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);animation:fadeInUp .5s ease-out backwards}.stat-card:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light);transform:translateY(-4px);box-shadow:var(--glass-shadow)}.variant-default .stat-card{background:var(--app-surface);border:1px solid var(--app-border);backdrop-filter:none;-webkit-backdrop-filter:none}.variant-compact .stat-card{padding:14px 16px;gap:14px;min-height:80px}.variant-compact .stat-icon{width:38px;height:38px;border-radius:10px}.variant-compact .stat-icon svg{width:18px;height:18px}.variant-compact .stat-value{font-size:1.25rem;font-weight:800}.variant-compact .stat-glow{width:60px;height:60px;top:-10px;right:-10px}.variant-outlined .stat-card{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none}.variant-elevated .stat-card{box-shadow:0 20px 40px var(--glass-shadow);transform:translateY(-2px);border-color:var(--glass-border-light)}.stat-glow{position:absolute;width:100px;height:100px;border-radius:50%;filter:blur(40px);opacity:.15;top:-20px;right:-20px;pointer-events:none;transition:opacity .3s}.stat-card:hover .stat-glow{opacity:.3}.stat-icon{width:52px;height:52px;border-radius:14px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.stat-icon svg{width:26px;height:26px;fill:currentColor}.stat-data{display:flex;flex-direction:column}.stat-label{font-size:.8125rem;color:var(--app-text-muted);font-weight:500}.stat-value{font-size:1.5rem;font-weight:700;color:var(--app-text);margin:2px 0}.stat-trend{font-size:.75rem;font-weight:600}.stat-trend.positive{color:#34d399}.stat-trend.negative{color:#fb7185}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}\n"] });
5272
5272
  }
5273
5273
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StatsGridSectionComponent, decorators: [{
5274
5274
  type: Component,
5275
- args: [{ selector: 'amf-stats-grid', standalone: true, imports: [], template: `
5276
- <div class="amf-stats-grid" [style.grid-template-columns]="gridCols" [class]="'variant-' + (config.variant || 'glass')">
5277
- @for (stat of config.stats; track stat.label; let i = $index) {
5278
- <div class="stat-card" [style.animation-delay]="(i * 0.1) + 's'">
5279
- <div class="stat-glow" [style.background]="stat.glowColor || stat.color"></div>
5280
- @if (stat.icon) {
5281
- <div class="stat-icon" [style.color]="stat.color" [style.background]="stat.bgColor">
5282
- <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(stat.icon)"></path></svg>
5283
- </div>
5284
- }
5285
- <div class="stat-data">
5286
- <span class="stat-label">{{ stat.label }}</span>
5287
- <span class="stat-value">{{ stat.value }}</span>
5288
- @if (stat.trend) { <span class="stat-trend" [class.positive]="stat.trendPositive" [class.negative]="!stat.trendPositive">{{ stat.trend }}</span> }
5289
- </div>
5290
- </div>
5291
- }
5292
- </div>
5275
+ args: [{ selector: 'amf-stats-grid', standalone: true, imports: [], template: `
5276
+ <div class="amf-stats-grid" [style.grid-template-columns]="gridCols" [class]="'variant-' + (config.variant || 'glass')">
5277
+ @for (stat of config.stats; track stat.label; let i = $index) {
5278
+ <div class="stat-card" [style.animation-delay]="(i * 0.1) + 's'">
5279
+ <div class="stat-glow" [style.background]="stat.glowColor || stat.color"></div>
5280
+ @if (stat.icon) {
5281
+ <div class="stat-icon" [style.color]="stat.color" [style.background]="stat.bgColor">
5282
+ <svg viewBox="0 0 24 24"><path [attr.d]="iconRegistry.getIcon(stat.icon)"></path></svg>
5283
+ </div>
5284
+ }
5285
+ <div class="stat-data">
5286
+ <span class="stat-label">{{ stat.label }}</span>
5287
+ <span class="stat-value">{{ stat.value }}</span>
5288
+ @if (stat.trend) { <span class="stat-trend" [class.positive]="stat.trendPositive" [class.negative]="!stat.trendPositive">{{ stat.trend }}</span> }
5289
+ </div>
5290
+ </div>
5291
+ }
5292
+ </div>
5293
5293
  `, styles: [".amf-stats-grid{display:grid;gap:20px}.stat-card{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);border-radius:16px;padding:24px;display:flex;align-items:center;gap:20px;position:relative;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);animation:fadeInUp .5s ease-out backwards}.stat-card:hover{background:var(--glass-bg-hover);border-color:var(--glass-border-light);transform:translateY(-4px);box-shadow:var(--glass-shadow)}.variant-default .stat-card{background:var(--app-surface);border:1px solid var(--app-border);backdrop-filter:none;-webkit-backdrop-filter:none}.variant-compact .stat-card{padding:14px 16px;gap:14px;min-height:80px}.variant-compact .stat-icon{width:38px;height:38px;border-radius:10px}.variant-compact .stat-icon svg{width:18px;height:18px}.variant-compact .stat-value{font-size:1.25rem;font-weight:800}.variant-compact .stat-glow{width:60px;height:60px;top:-10px;right:-10px}.variant-outlined .stat-card{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none}.variant-elevated .stat-card{box-shadow:0 20px 40px var(--glass-shadow);transform:translateY(-2px);border-color:var(--glass-border-light)}.stat-glow{position:absolute;width:100px;height:100px;border-radius:50%;filter:blur(40px);opacity:.15;top:-20px;right:-20px;pointer-events:none;transition:opacity .3s}.stat-card:hover .stat-glow{opacity:.3}.stat-icon{width:52px;height:52px;border-radius:14px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.stat-icon svg{width:26px;height:26px;fill:currentColor}.stat-data{display:flex;flex-direction:column}.stat-label{font-size:.8125rem;color:var(--app-text-muted);font-weight:500}.stat-value{font-size:1.5rem;font-weight:700;color:var(--app-text);margin:2px 0}.stat-trend{font-size:.75rem;font-weight:600}.stat-trend.positive{color:#34d399}.stat-trend.negative{color:#fb7185}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}\n"] }]
5294
5294
  }], propDecorators: { config: [{
5295
5295
  type: Input
@@ -5314,40 +5314,40 @@ class PageHeaderSectionComponent {
5314
5314
  return this.config.title;
5315
5315
  }
5316
5316
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PageHeaderSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5317
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PageHeaderSectionComponent, isStandalone: true, selector: "amf-page-header", inputs: { config: "config", context: "context" }, ngImport: i0, template: `
5318
- <header class="amf-page-header">
5319
- <div class="header-content">
5320
- <h1>{{ resolvedTitle }}</h1>
5321
- @if (config.subtitle) { <p>{{ config.subtitle }}</p> }
5322
- </div>
5323
- <div class="header-actions">
5324
- @for (action of config.actions || []; track action.label) {
5325
- <button [class]="'btn-' + (action.variant || 'primary')" (click)="actionDispatcher.dispatch(action.action, context)">
5326
- @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
5327
- {{ action.label }}
5328
- </button>
5329
- }
5330
- </div>
5331
- </header>
5317
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PageHeaderSectionComponent, isStandalone: true, selector: "amf-page-header", inputs: { config: "config", context: "context" }, ngImport: i0, template: `
5318
+ <header class="amf-page-header">
5319
+ <div class="header-content">
5320
+ <h1>{{ resolvedTitle }}</h1>
5321
+ @if (config.subtitle) { <p>{{ config.subtitle }}</p> }
5322
+ </div>
5323
+ <div class="header-actions">
5324
+ @for (action of config.actions || []; track action.label) {
5325
+ <button [class]="'btn-' + (action.variant || 'primary')" (click)="actionDispatcher.dispatch(action.action, context)">
5326
+ @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
5327
+ {{ action.label }}
5328
+ </button>
5329
+ }
5330
+ </div>
5331
+ </header>
5332
5332
  `, isInline: true, styles: [".amf-page-header{display:flex;justify-content:space-between;align-items:center;animation:fadeInUp .4s ease-out}.header-content h1{font-size:1.875rem;margin-bottom:4px}.header-content p{color:var(--app-text-muted);font-size:.9375rem}.header-actions{display:flex;gap:12px}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:10px 20px;border-radius:10px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .3s}.btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.btn-secondary{background:var(--glass-bg);border:1px solid var(--app-border);color:var(--app-text);padding:10px 20px;border-radius:10px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .2s}.btn-secondary:hover{background:var(--glass-bg-hover)}.btn-ghost{background:transparent;border:none;color:var(--app-text-muted);padding:10px 20px;border-radius:10px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .2s}.btn-ghost:hover{color:var(--app-primary);background:var(--glass-bg)}.btn-icon{width:18px;height:18px;fill:currentColor}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}\n"] });
5333
5333
  }
5334
5334
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PageHeaderSectionComponent, decorators: [{
5335
5335
  type: Component,
5336
- args: [{ selector: 'amf-page-header', standalone: true, imports: [], template: `
5337
- <header class="amf-page-header">
5338
- <div class="header-content">
5339
- <h1>{{ resolvedTitle }}</h1>
5340
- @if (config.subtitle) { <p>{{ config.subtitle }}</p> }
5341
- </div>
5342
- <div class="header-actions">
5343
- @for (action of config.actions || []; track action.label) {
5344
- <button [class]="'btn-' + (action.variant || 'primary')" (click)="actionDispatcher.dispatch(action.action, context)">
5345
- @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
5346
- {{ action.label }}
5347
- </button>
5348
- }
5349
- </div>
5350
- </header>
5336
+ args: [{ selector: 'amf-page-header', standalone: true, imports: [], template: `
5337
+ <header class="amf-page-header">
5338
+ <div class="header-content">
5339
+ <h1>{{ resolvedTitle }}</h1>
5340
+ @if (config.subtitle) { <p>{{ config.subtitle }}</p> }
5341
+ </div>
5342
+ <div class="header-actions">
5343
+ @for (action of config.actions || []; track action.label) {
5344
+ <button [class]="'btn-' + (action.variant || 'primary')" (click)="actionDispatcher.dispatch(action.action, context)">
5345
+ @if (action.icon) { <svg viewBox="0 0 24 24" class="btn-icon"><path [attr.d]="iconRegistry.getIcon(action.icon)"></path></svg> }
5346
+ {{ action.label }}
5347
+ </button>
5348
+ }
5349
+ </div>
5350
+ </header>
5351
5351
  `, styles: [".amf-page-header{display:flex;justify-content:space-between;align-items:center;animation:fadeInUp .4s ease-out}.header-content h1{font-size:1.875rem;margin-bottom:4px}.header-content p{color:var(--app-text-muted);font-size:.9375rem}.header-actions{display:flex;gap:12px}.btn-primary{background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;border:none;padding:10px 20px;border-radius:10px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .3s}.btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 24px -4px var(--app-glow)}.btn-secondary{background:var(--glass-bg);border:1px solid var(--app-border);color:var(--app-text);padding:10px 20px;border-radius:10px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .2s}.btn-secondary:hover{background:var(--glass-bg-hover)}.btn-ghost{background:transparent;border:none;color:var(--app-text-muted);padding:10px 20px;border-radius:10px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .2s}.btn-ghost:hover{color:var(--app-primary);background:var(--glass-bg)}.btn-icon{width:18px;height:18px;fill:currentColor}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}\n"] }]
5352
5352
  }], propDecorators: { config: [{
5353
5353
  type: Input
@@ -5794,140 +5794,140 @@ class SidebarComponent {
5794
5794
  }
5795
5795
  }
5796
5796
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5797
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: SidebarComponent, isStandalone: true, selector: "app-sidebar", ngImport: i0, template: `
5798
- <div class="sidebar-container" [class.collapsed]="config.sidebarCollapsed()">
5799
- <div class="sidebar-header">
5800
- <div class="logo">
5801
- <div class="logo-glow">
5802
- <svg viewBox="0 0 24 24" class="logo-icon">
5803
- <path [attr.d]="iconRegistry.getIcon('dashboard')"></path>
5804
- </svg>
5805
- </div>
5806
- <span class="logo-text">{{ config.appName() }}</span>
5807
- </div>
5808
- </div>
5809
-
5810
- <nav class="sidebar-nav">
5811
- @for (group of navigation.menuItems(); track group.label) {
5812
- <div class="nav-group">
5813
- <h3 class="group-title">{{ group.label }}</h3>
5814
- <ul>
5815
- <ng-container *ngTemplateOutlet="menuList; context: { $implicit: group.items }"></ng-container>
5816
- </ul>
5817
- </div>
5818
- }
5819
- </nav>
5820
-
5821
- <ng-template #menuList let-listItems>
5822
- @for (node of listItems; track node.label) {
5823
- <li class="nav-item-wrapper">
5824
- <div
5825
- class="nav-item"
5826
- [routerLink]="node.route ? node.route : null"
5827
- routerLinkActive="active"
5828
- [class.has-children]="node.children?.length"
5829
- (click)="toggleExpand(node)"
5830
- >
5831
- <div class="nav-link-content">
5832
- @if (node.icon) {
5833
- <svg viewBox="0 0 24 24" class="nav-icon">
5834
- <path [attr.d]="iconRegistry.getIcon(node.icon)"></path>
5835
- </svg>
5836
- }
5837
- <span class="nav-label">{{ node.label }}</span>
5838
- </div>
5839
-
5840
- @if (node.badge) {
5841
- <span class="badge" [style.background]="'linear-gradient(135deg, ' + node.badgeColor + ', ' + node.badgeColor + '88)'">
5842
- {{ node.badge }}
5843
- </span>
5844
- }
5845
-
5846
- @if (node.children?.length) {
5847
- <svg viewBox="0 0 24 24" class="chevron" [class.rotated]="expandedItems.has(node)">
5848
- <path [attr.d]="iconRegistry.getIcon('chevron-right')"></path>
5849
- </svg>
5850
- }
5851
- </div>
5852
-
5853
- @if (node.children?.length && expandedItems.has(node)) {
5854
- <ul class="sub-menu">
5855
- <ng-container *ngTemplateOutlet="menuList; context: { $implicit: node.children }"></ng-container>
5856
- </ul>
5857
- }
5858
- </li>
5859
- }
5860
- </ng-template>
5861
- </div>
5797
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: SidebarComponent, isStandalone: true, selector: "app-sidebar", ngImport: i0, template: `
5798
+ <div class="sidebar-container" [class.collapsed]="config.sidebarCollapsed()">
5799
+ <div class="sidebar-header">
5800
+ <div class="logo">
5801
+ <div class="logo-glow">
5802
+ <svg viewBox="0 0 24 24" class="logo-icon">
5803
+ <path [attr.d]="iconRegistry.getIcon('dashboard')"></path>
5804
+ </svg>
5805
+ </div>
5806
+ <span class="logo-text">{{ config.appName() }}</span>
5807
+ </div>
5808
+ </div>
5809
+
5810
+ <nav class="sidebar-nav">
5811
+ @for (group of navigation.menuItems(); track group.label) {
5812
+ <div class="nav-group">
5813
+ <h3 class="group-title">{{ group.label }}</h3>
5814
+ <ul>
5815
+ <ng-container *ngTemplateOutlet="menuList; context: { $implicit: group.items }"></ng-container>
5816
+ </ul>
5817
+ </div>
5818
+ }
5819
+ </nav>
5820
+
5821
+ <ng-template #menuList let-listItems>
5822
+ @for (node of listItems; track node.label) {
5823
+ <li class="nav-item-wrapper">
5824
+ <div
5825
+ class="nav-item"
5826
+ [routerLink]="node.route ? node.route : null"
5827
+ routerLinkActive="active"
5828
+ [class.has-children]="node.children?.length"
5829
+ (click)="toggleExpand(node)"
5830
+ >
5831
+ <div class="nav-link-content">
5832
+ @if (node.icon) {
5833
+ <svg viewBox="0 0 24 24" class="nav-icon">
5834
+ <path [attr.d]="iconRegistry.getIcon(node.icon)"></path>
5835
+ </svg>
5836
+ }
5837
+ <span class="nav-label">{{ node.label }}</span>
5838
+ </div>
5839
+
5840
+ @if (node.badge) {
5841
+ <span class="badge" [style.background]="'linear-gradient(135deg, ' + node.badgeColor + ', ' + node.badgeColor + '88)'">
5842
+ {{ node.badge }}
5843
+ </span>
5844
+ }
5845
+
5846
+ @if (node.children?.length) {
5847
+ <svg viewBox="0 0 24 24" class="chevron" [class.rotated]="expandedItems.has(node)">
5848
+ <path [attr.d]="iconRegistry.getIcon('chevron-right')"></path>
5849
+ </svg>
5850
+ }
5851
+ </div>
5852
+
5853
+ @if (node.children?.length && expandedItems.has(node)) {
5854
+ <ul class="sub-menu">
5855
+ <ng-container *ngTemplateOutlet="menuList; context: { $implicit: node.children }"></ng-container>
5856
+ </ul>
5857
+ }
5858
+ </li>
5859
+ }
5860
+ </ng-template>
5861
+ </div>
5862
5862
  `, isInline: true, styles: [":host{display:block;height:100%}.sidebar-container{width:var(--sidebar-width, 260px);height:100%;background:var(--app-sidebar-bg);backdrop-filter:blur(var(--glass-blur-heavy));-webkit-backdrop-filter:blur(var(--glass-blur-heavy));border-right:1px solid var(--glass-border);display:flex;flex-direction:column;transition:width var(--transition-smooth);overflow:hidden;position:relative}.sidebar-container:after{content:\"\";position:absolute;top:0;right:0;width:1px;height:100%;background:linear-gradient(to bottom,transparent,var(--app-primary-light),transparent);pointer-events:none}.sidebar-container.collapsed{width:80px}.sidebar-header{height:68px;display:flex;align-items:center;padding:0 20px;border-bottom:1px solid var(--glass-border)}.logo{display:flex;align-items:center;gap:12px;font-weight:700;font-size:1.25rem;color:var(--app-text);white-space:nowrap}.logo-glow{width:38px;height:38px;border-radius:10px;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));display:flex;align-items:center;justify-content:center;box-shadow:0 0 20px var(--app-glow);animation:pulseGlow 4s ease-in-out infinite;flex-shrink:0}.logo-icon{width:20px;height:20px;fill:#fff}.sidebar-container.collapsed .logo-text{display:none}.sidebar-nav{flex:1;overflow-y:auto;padding:16px 0}.nav-group{margin-top:28px}.nav-group:first-child{margin-top:0}.group-title{font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--app-text-muted);padding:0 24px 8px;opacity:.6}.sidebar-container.collapsed .group-title{display:none}ul{list-style:none;padding:0;margin:0}.nav-item-wrapper{margin-bottom:2px;padding:0 10px}.nav-item{display:flex;align-items:center;justify-content:space-between;height:44px;padding:0 14px;border-radius:10px;color:var(--app-sidebar-text);cursor:pointer;transition:all var(--transition-smooth);text-decoration:none;position:relative}.nav-item:hover{background:var(--glass-bg-hover);color:var(--app-text)}.nav-item.active{background:linear-gradient(135deg,var(--app-primary-light),var(--app-accent-light));color:var(--app-primary);box-shadow:0 0 20px var(--app-glow)}.nav-item.active:before{content:\"\";position:absolute;left:0;top:50%;transform:translateY(-50%);width:3px;height:20px;border-radius:0 3px 3px 0;background:linear-gradient(to bottom,var(--app-primary),var(--app-accent))}.nav-item.active .nav-icon{filter:drop-shadow(0 0 6px var(--app-glow))}.nav-link-content{display:flex;align-items:center;gap:12px}.nav-icon{width:20px;height:20px;fill:currentColor;flex-shrink:0;transition:all var(--transition-fast)}.sidebar-container.collapsed .nav-label,.sidebar-container.collapsed .chevron,.sidebar-container.collapsed .badge{display:none}.chevron{width:16px;height:16px;fill:currentColor;transition:transform var(--transition-smooth);opacity:.5}.chevron.rotated{transform:rotate(90deg)}.badge{font-size:10px;padding:2px 8px;border-radius:10px;color:#fff;font-weight:600;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.sub-menu{padding-left:24px;margin-top:4px;animation:fadeInUp .2s ease-out}.sidebar-container.collapsed .sub-menu{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
5863
5863
  }
5864
5864
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SidebarComponent, decorators: [{
5865
5865
  type: Component,
5866
- args: [{ selector: 'app-sidebar', standalone: true, imports: [CommonModule, RouterLink, RouterLinkActive], template: `
5867
- <div class="sidebar-container" [class.collapsed]="config.sidebarCollapsed()">
5868
- <div class="sidebar-header">
5869
- <div class="logo">
5870
- <div class="logo-glow">
5871
- <svg viewBox="0 0 24 24" class="logo-icon">
5872
- <path [attr.d]="iconRegistry.getIcon('dashboard')"></path>
5873
- </svg>
5874
- </div>
5875
- <span class="logo-text">{{ config.appName() }}</span>
5876
- </div>
5877
- </div>
5878
-
5879
- <nav class="sidebar-nav">
5880
- @for (group of navigation.menuItems(); track group.label) {
5881
- <div class="nav-group">
5882
- <h3 class="group-title">{{ group.label }}</h3>
5883
- <ul>
5884
- <ng-container *ngTemplateOutlet="menuList; context: { $implicit: group.items }"></ng-container>
5885
- </ul>
5886
- </div>
5887
- }
5888
- </nav>
5889
-
5890
- <ng-template #menuList let-listItems>
5891
- @for (node of listItems; track node.label) {
5892
- <li class="nav-item-wrapper">
5893
- <div
5894
- class="nav-item"
5895
- [routerLink]="node.route ? node.route : null"
5896
- routerLinkActive="active"
5897
- [class.has-children]="node.children?.length"
5898
- (click)="toggleExpand(node)"
5899
- >
5900
- <div class="nav-link-content">
5901
- @if (node.icon) {
5902
- <svg viewBox="0 0 24 24" class="nav-icon">
5903
- <path [attr.d]="iconRegistry.getIcon(node.icon)"></path>
5904
- </svg>
5905
- }
5906
- <span class="nav-label">{{ node.label }}</span>
5907
- </div>
5908
-
5909
- @if (node.badge) {
5910
- <span class="badge" [style.background]="'linear-gradient(135deg, ' + node.badgeColor + ', ' + node.badgeColor + '88)'">
5911
- {{ node.badge }}
5912
- </span>
5913
- }
5914
-
5915
- @if (node.children?.length) {
5916
- <svg viewBox="0 0 24 24" class="chevron" [class.rotated]="expandedItems.has(node)">
5917
- <path [attr.d]="iconRegistry.getIcon('chevron-right')"></path>
5918
- </svg>
5919
- }
5920
- </div>
5921
-
5922
- @if (node.children?.length && expandedItems.has(node)) {
5923
- <ul class="sub-menu">
5924
- <ng-container *ngTemplateOutlet="menuList; context: { $implicit: node.children }"></ng-container>
5925
- </ul>
5926
- }
5927
- </li>
5928
- }
5929
- </ng-template>
5930
- </div>
5866
+ args: [{ selector: 'app-sidebar', standalone: true, imports: [CommonModule, RouterLink, RouterLinkActive], template: `
5867
+ <div class="sidebar-container" [class.collapsed]="config.sidebarCollapsed()">
5868
+ <div class="sidebar-header">
5869
+ <div class="logo">
5870
+ <div class="logo-glow">
5871
+ <svg viewBox="0 0 24 24" class="logo-icon">
5872
+ <path [attr.d]="iconRegistry.getIcon('dashboard')"></path>
5873
+ </svg>
5874
+ </div>
5875
+ <span class="logo-text">{{ config.appName() }}</span>
5876
+ </div>
5877
+ </div>
5878
+
5879
+ <nav class="sidebar-nav">
5880
+ @for (group of navigation.menuItems(); track group.label) {
5881
+ <div class="nav-group">
5882
+ <h3 class="group-title">{{ group.label }}</h3>
5883
+ <ul>
5884
+ <ng-container *ngTemplateOutlet="menuList; context: { $implicit: group.items }"></ng-container>
5885
+ </ul>
5886
+ </div>
5887
+ }
5888
+ </nav>
5889
+
5890
+ <ng-template #menuList let-listItems>
5891
+ @for (node of listItems; track node.label) {
5892
+ <li class="nav-item-wrapper">
5893
+ <div
5894
+ class="nav-item"
5895
+ [routerLink]="node.route ? node.route : null"
5896
+ routerLinkActive="active"
5897
+ [class.has-children]="node.children?.length"
5898
+ (click)="toggleExpand(node)"
5899
+ >
5900
+ <div class="nav-link-content">
5901
+ @if (node.icon) {
5902
+ <svg viewBox="0 0 24 24" class="nav-icon">
5903
+ <path [attr.d]="iconRegistry.getIcon(node.icon)"></path>
5904
+ </svg>
5905
+ }
5906
+ <span class="nav-label">{{ node.label }}</span>
5907
+ </div>
5908
+
5909
+ @if (node.badge) {
5910
+ <span class="badge" [style.background]="'linear-gradient(135deg, ' + node.badgeColor + ', ' + node.badgeColor + '88)'">
5911
+ {{ node.badge }}
5912
+ </span>
5913
+ }
5914
+
5915
+ @if (node.children?.length) {
5916
+ <svg viewBox="0 0 24 24" class="chevron" [class.rotated]="expandedItems.has(node)">
5917
+ <path [attr.d]="iconRegistry.getIcon('chevron-right')"></path>
5918
+ </svg>
5919
+ }
5920
+ </div>
5921
+
5922
+ @if (node.children?.length && expandedItems.has(node)) {
5923
+ <ul class="sub-menu">
5924
+ <ng-container *ngTemplateOutlet="menuList; context: { $implicit: node.children }"></ng-container>
5925
+ </ul>
5926
+ }
5927
+ </li>
5928
+ }
5929
+ </ng-template>
5930
+ </div>
5931
5931
  `, styles: [":host{display:block;height:100%}.sidebar-container{width:var(--sidebar-width, 260px);height:100%;background:var(--app-sidebar-bg);backdrop-filter:blur(var(--glass-blur-heavy));-webkit-backdrop-filter:blur(var(--glass-blur-heavy));border-right:1px solid var(--glass-border);display:flex;flex-direction:column;transition:width var(--transition-smooth);overflow:hidden;position:relative}.sidebar-container:after{content:\"\";position:absolute;top:0;right:0;width:1px;height:100%;background:linear-gradient(to bottom,transparent,var(--app-primary-light),transparent);pointer-events:none}.sidebar-container.collapsed{width:80px}.sidebar-header{height:68px;display:flex;align-items:center;padding:0 20px;border-bottom:1px solid var(--glass-border)}.logo{display:flex;align-items:center;gap:12px;font-weight:700;font-size:1.25rem;color:var(--app-text);white-space:nowrap}.logo-glow{width:38px;height:38px;border-radius:10px;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));display:flex;align-items:center;justify-content:center;box-shadow:0 0 20px var(--app-glow);animation:pulseGlow 4s ease-in-out infinite;flex-shrink:0}.logo-icon{width:20px;height:20px;fill:#fff}.sidebar-container.collapsed .logo-text{display:none}.sidebar-nav{flex:1;overflow-y:auto;padding:16px 0}.nav-group{margin-top:28px}.nav-group:first-child{margin-top:0}.group-title{font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--app-text-muted);padding:0 24px 8px;opacity:.6}.sidebar-container.collapsed .group-title{display:none}ul{list-style:none;padding:0;margin:0}.nav-item-wrapper{margin-bottom:2px;padding:0 10px}.nav-item{display:flex;align-items:center;justify-content:space-between;height:44px;padding:0 14px;border-radius:10px;color:var(--app-sidebar-text);cursor:pointer;transition:all var(--transition-smooth);text-decoration:none;position:relative}.nav-item:hover{background:var(--glass-bg-hover);color:var(--app-text)}.nav-item.active{background:linear-gradient(135deg,var(--app-primary-light),var(--app-accent-light));color:var(--app-primary);box-shadow:0 0 20px var(--app-glow)}.nav-item.active:before{content:\"\";position:absolute;left:0;top:50%;transform:translateY(-50%);width:3px;height:20px;border-radius:0 3px 3px 0;background:linear-gradient(to bottom,var(--app-primary),var(--app-accent))}.nav-item.active .nav-icon{filter:drop-shadow(0 0 6px var(--app-glow))}.nav-link-content{display:flex;align-items:center;gap:12px}.nav-icon{width:20px;height:20px;fill:currentColor;flex-shrink:0;transition:all var(--transition-fast)}.sidebar-container.collapsed .nav-label,.sidebar-container.collapsed .chevron,.sidebar-container.collapsed .badge{display:none}.chevron{width:16px;height:16px;fill:currentColor;transition:transform var(--transition-smooth);opacity:.5}.chevron.rotated{transform:rotate(90deg)}.badge{font-size:10px;padding:2px 8px;border-radius:10px;color:#fff;font-weight:600;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.sub-menu{padding-left:24px;margin-top:4px;animation:fadeInUp .2s ease-out}.sidebar-container.collapsed .sub-menu{display:none}\n"] }]
5932
5932
  }] });
5933
5933
 
@@ -5947,252 +5947,252 @@ class NavbarComponent {
5947
5947
  return colors[name] || '#06b6d4';
5948
5948
  }
5949
5949
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: NavbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5950
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: NavbarComponent, isStandalone: true, selector: "app-navbar", ngImport: i0, template: `
5951
- <header class="navbar-container">
5952
- <div class="left-section">
5953
- <button class="icon-btn" (click)="config.toggleSidebar()" title="Toggle Sidebar">
5954
- <svg viewBox="0 0 24 24">
5955
- <path [attr.d]="iconRegistry.getIcon('menu')"></path>
5956
- </svg>
5957
- </button>
5958
-
5959
- <div class="search-box">
5960
- <svg viewBox="0 0 24 24" class="search-icon">
5961
- <path [attr.d]="iconRegistry.getIcon('search')"></path>
5962
- </svg>
5963
- <input type="text" placeholder="Search anything...">
5964
- </div>
5965
- </div>
5966
-
5967
- <div class="right-section">
5968
- <!-- Theme Switcher -->
5969
- <button class="icon-btn theme-btn" (click)="themeToggleOpen.set(!themeToggleOpen())" title="Change Theme">
5970
- <svg viewBox="0 0 24 24">
5971
- <path [attr.d]="iconRegistry.getIcon('palette')"></path>
5972
- </svg>
5973
-
5974
- @if (themeToggleOpen()) {
5975
- <div class="dropdown theme-dropdown">
5976
- @for (theme of themeService.availableThemes; track theme.name) {
5977
- <div
5978
- class="dropdown-item"
5979
- [class.active]="themeService.currentTheme() === theme.name"
5980
- (click)="themeService.setTheme(theme.name); themeToggleOpen.set(false)"
5981
- >
5982
- <span class="theme-dot" [style.background]="getThemeColor(theme.name)"></span>
5983
- {{ theme.label }}
5984
- </div>
5985
- }
5986
- </div>
5987
- }
5988
- </button>
5989
-
5990
- <!-- User Profile -->
5991
- <div class="user-profile" (click)="userMenuOpen.set(!userMenuOpen())">
5992
- <div class="user-info">
5993
- <span class="user-name">{{ auth.user()?.name }}</span>
5994
- <span class="user-role">{{ auth.user()?.role }}</span>
5995
- </div>
5996
- <div class="avatar">
5997
- @if (auth.user()?.avatar) {
5998
- <img [src]="auth.user()?.avatar" [alt]="auth.user()?.name">
5999
- } @else {
6000
- <svg viewBox="0 0 24 24">
6001
- <path [attr.d]="iconRegistry.getIcon('person')"></path>
6002
- </svg>
6003
- }
6004
- </div>
6005
-
6006
- @if (userMenuOpen()) {
6007
- <div class="dropdown user-dropdown">
6008
- <div class="dropdown-header">
6009
- <strong>{{ auth.user()?.name }}</strong>
6010
- <span>{{ auth.user()?.email }}</span>
6011
- </div>
6012
- <div class="divider"></div>
6013
- <div class="dropdown-item">Your Profile</div>
6014
- <div class="dropdown-item">Settings</div>
6015
- <div class="divider"></div>
6016
- <div class="dropdown-item logout" (click)="auth.logout()">
6017
- <svg viewBox="0 0 24 24" class="logout-icon">
6018
- <path [attr.d]="iconRegistry.getIcon('logout')"></path>
6019
- </svg>
6020
- Logout
6021
- </div>
6022
- </div>
6023
- }
6024
- </div>
6025
- </div>
6026
- </header>
5950
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: NavbarComponent, isStandalone: true, selector: "app-navbar", ngImport: i0, template: `
5951
+ <header class="navbar-container">
5952
+ <div class="left-section">
5953
+ <button class="icon-btn" (click)="config.toggleSidebar()" title="Toggle Sidebar">
5954
+ <svg viewBox="0 0 24 24">
5955
+ <path [attr.d]="iconRegistry.getIcon('menu')"></path>
5956
+ </svg>
5957
+ </button>
5958
+
5959
+ <div class="search-box">
5960
+ <svg viewBox="0 0 24 24" class="search-icon">
5961
+ <path [attr.d]="iconRegistry.getIcon('search')"></path>
5962
+ </svg>
5963
+ <input type="text" placeholder="Search anything...">
5964
+ </div>
5965
+ </div>
5966
+
5967
+ <div class="right-section">
5968
+ <!-- Theme Switcher -->
5969
+ <button class="icon-btn theme-btn" (click)="themeToggleOpen.set(!themeToggleOpen())" title="Change Theme">
5970
+ <svg viewBox="0 0 24 24">
5971
+ <path [attr.d]="iconRegistry.getIcon('palette')"></path>
5972
+ </svg>
5973
+
5974
+ @if (themeToggleOpen()) {
5975
+ <div class="dropdown theme-dropdown">
5976
+ @for (theme of themeService.availableThemes; track theme.name) {
5977
+ <div
5978
+ class="dropdown-item"
5979
+ [class.active]="themeService.currentTheme() === theme.name"
5980
+ (click)="themeService.setTheme(theme.name); themeToggleOpen.set(false)"
5981
+ >
5982
+ <span class="theme-dot" [style.background]="getThemeColor(theme.name)"></span>
5983
+ {{ theme.label }}
5984
+ </div>
5985
+ }
5986
+ </div>
5987
+ }
5988
+ </button>
5989
+
5990
+ <!-- User Profile -->
5991
+ <div class="user-profile" (click)="userMenuOpen.set(!userMenuOpen())">
5992
+ <div class="user-info">
5993
+ <span class="user-name">{{ auth.user()?.name }}</span>
5994
+ <span class="user-role">{{ auth.user()?.role }}</span>
5995
+ </div>
5996
+ <div class="avatar">
5997
+ @if (auth.user()?.avatar) {
5998
+ <img [src]="auth.user()?.avatar" [alt]="auth.user()?.name">
5999
+ } @else {
6000
+ <svg viewBox="0 0 24 24">
6001
+ <path [attr.d]="iconRegistry.getIcon('person')"></path>
6002
+ </svg>
6003
+ }
6004
+ </div>
6005
+
6006
+ @if (userMenuOpen()) {
6007
+ <div class="dropdown user-dropdown">
6008
+ <div class="dropdown-header">
6009
+ <strong>{{ auth.user()?.name }}</strong>
6010
+ <span>{{ auth.user()?.email }}</span>
6011
+ </div>
6012
+ <div class="divider"></div>
6013
+ <div class="dropdown-item">Your Profile</div>
6014
+ <div class="dropdown-item">Settings</div>
6015
+ <div class="divider"></div>
6016
+ <div class="dropdown-item logout" (click)="auth.logout()">
6017
+ <svg viewBox="0 0 24 24" class="logout-icon">
6018
+ <path [attr.d]="iconRegistry.getIcon('logout')"></path>
6019
+ </svg>
6020
+ Logout
6021
+ </div>
6022
+ </div>
6023
+ }
6024
+ </div>
6025
+ </div>
6026
+ </header>
6027
6027
  `, isInline: true, styles: [":host{display:block;width:100%}.navbar-container{height:68px;padding:0 24px;background:var(--app-navbar-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border-bottom:1px solid var(--glass-border);display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}.left-section,.right-section{display:flex;align-items:center;gap:16px}.icon-btn{width:40px;height:40px;border-radius:10px;border:1px solid transparent;background:transparent;color:var(--app-text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--transition-smooth);position:relative}.icon-btn:hover{background:var(--glass-bg-hover);border-color:var(--glass-border);color:var(--app-primary);box-shadow:0 0 16px var(--app-glow)}.icon-btn svg{width:22px;height:22px;fill:currentColor}.search-box{display:flex;align-items:center;background:var(--glass-bg);border:1px solid var(--glass-border);border-radius:10px;padding:0 14px;width:300px;height:40px;transition:all var(--transition-smooth)}.search-box:focus-within{border-color:var(--app-primary);background:var(--glass-bg-hover);box-shadow:0 0 20px var(--app-glow)}.search-icon{width:18px;height:18px;fill:var(--app-text-muted);flex-shrink:0;transition:fill var(--transition-fast)}.search-box:focus-within .search-icon{fill:var(--app-primary)}.search-box input{border:none;background:transparent;padding:8px;outline:none;flex:1;font-size:.875rem;color:var(--app-text)}.search-box input::placeholder{color:var(--app-text-muted)}.user-profile{display:flex;align-items:center;gap:12px;cursor:pointer;padding:4px 12px;border-radius:12px;border:1px solid transparent;transition:all var(--transition-smooth);position:relative}.user-profile:hover{background:var(--glass-bg-hover);border-color:var(--glass-border)}.user-info{display:flex;flex-direction:column;align-items:flex-end}.user-name{font-size:.875rem;font-weight:600;color:var(--app-text)}.user-role{font-size:.6875rem;color:var(--app-text-muted);text-transform:uppercase;letter-spacing:.05em}.avatar{width:38px;height:38px;border-radius:12px;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:box-shadow var(--transition-smooth)}.user-profile:hover .avatar{box-shadow:0 0 20px var(--app-glow)}.avatar img{width:100%;height:100%;object-fit:cover}.avatar svg{width:22px;height:22px;fill:currentColor}.dropdown{position:absolute;top:calc(100% + 8px);right:0;background:var(--app-bg-secondary);backdrop-filter:blur(var(--glass-blur-heavy));-webkit-backdrop-filter:blur(var(--glass-blur-heavy));border:1px solid var(--glass-border-light);border-radius:14px;box-shadow:var(--glass-shadow),0 0 30px #0006;min-width:220px;overflow:hidden;animation:slideInDown .25s ease-out}.dropdown-header{padding:14px 16px;display:flex;flex-direction:column}.dropdown-header strong{color:var(--app-text);font-size:.9375rem}.dropdown-header span{font-size:.75rem;color:var(--app-text-muted);margin-top:2px}.dropdown-item{padding:10px 16px;font-size:.875rem;cursor:pointer;transition:all var(--transition-fast);color:var(--app-text-muted);display:flex;align-items:center;gap:10px}.dropdown-item:hover{background:var(--glass-bg-hover);color:var(--app-primary)}.dropdown-item.active{background:var(--app-primary-light);color:var(--app-primary);font-weight:600}.theme-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.divider{height:1px;background:var(--glass-border);margin:4px 0}.logout{color:#f43f5e!important}.logout:hover{background:#f43f5e1a!important;color:#fb7185!important}.logout-icon{width:18px;height:18px;fill:currentColor}\n"] });
6028
6028
  }
6029
6029
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: NavbarComponent, decorators: [{
6030
6030
  type: Component,
6031
- args: [{ selector: 'app-navbar', standalone: true, imports: [], template: `
6032
- <header class="navbar-container">
6033
- <div class="left-section">
6034
- <button class="icon-btn" (click)="config.toggleSidebar()" title="Toggle Sidebar">
6035
- <svg viewBox="0 0 24 24">
6036
- <path [attr.d]="iconRegistry.getIcon('menu')"></path>
6037
- </svg>
6038
- </button>
6039
-
6040
- <div class="search-box">
6041
- <svg viewBox="0 0 24 24" class="search-icon">
6042
- <path [attr.d]="iconRegistry.getIcon('search')"></path>
6043
- </svg>
6044
- <input type="text" placeholder="Search anything...">
6045
- </div>
6046
- </div>
6047
-
6048
- <div class="right-section">
6049
- <!-- Theme Switcher -->
6050
- <button class="icon-btn theme-btn" (click)="themeToggleOpen.set(!themeToggleOpen())" title="Change Theme">
6051
- <svg viewBox="0 0 24 24">
6052
- <path [attr.d]="iconRegistry.getIcon('palette')"></path>
6053
- </svg>
6054
-
6055
- @if (themeToggleOpen()) {
6056
- <div class="dropdown theme-dropdown">
6057
- @for (theme of themeService.availableThemes; track theme.name) {
6058
- <div
6059
- class="dropdown-item"
6060
- [class.active]="themeService.currentTheme() === theme.name"
6061
- (click)="themeService.setTheme(theme.name); themeToggleOpen.set(false)"
6062
- >
6063
- <span class="theme-dot" [style.background]="getThemeColor(theme.name)"></span>
6064
- {{ theme.label }}
6065
- </div>
6066
- }
6067
- </div>
6068
- }
6069
- </button>
6070
-
6071
- <!-- User Profile -->
6072
- <div class="user-profile" (click)="userMenuOpen.set(!userMenuOpen())">
6073
- <div class="user-info">
6074
- <span class="user-name">{{ auth.user()?.name }}</span>
6075
- <span class="user-role">{{ auth.user()?.role }}</span>
6076
- </div>
6077
- <div class="avatar">
6078
- @if (auth.user()?.avatar) {
6079
- <img [src]="auth.user()?.avatar" [alt]="auth.user()?.name">
6080
- } @else {
6081
- <svg viewBox="0 0 24 24">
6082
- <path [attr.d]="iconRegistry.getIcon('person')"></path>
6083
- </svg>
6084
- }
6085
- </div>
6086
-
6087
- @if (userMenuOpen()) {
6088
- <div class="dropdown user-dropdown">
6089
- <div class="dropdown-header">
6090
- <strong>{{ auth.user()?.name }}</strong>
6091
- <span>{{ auth.user()?.email }}</span>
6092
- </div>
6093
- <div class="divider"></div>
6094
- <div class="dropdown-item">Your Profile</div>
6095
- <div class="dropdown-item">Settings</div>
6096
- <div class="divider"></div>
6097
- <div class="dropdown-item logout" (click)="auth.logout()">
6098
- <svg viewBox="0 0 24 24" class="logout-icon">
6099
- <path [attr.d]="iconRegistry.getIcon('logout')"></path>
6100
- </svg>
6101
- Logout
6102
- </div>
6103
- </div>
6104
- }
6105
- </div>
6106
- </div>
6107
- </header>
6031
+ args: [{ selector: 'app-navbar', standalone: true, imports: [], template: `
6032
+ <header class="navbar-container">
6033
+ <div class="left-section">
6034
+ <button class="icon-btn" (click)="config.toggleSidebar()" title="Toggle Sidebar">
6035
+ <svg viewBox="0 0 24 24">
6036
+ <path [attr.d]="iconRegistry.getIcon('menu')"></path>
6037
+ </svg>
6038
+ </button>
6039
+
6040
+ <div class="search-box">
6041
+ <svg viewBox="0 0 24 24" class="search-icon">
6042
+ <path [attr.d]="iconRegistry.getIcon('search')"></path>
6043
+ </svg>
6044
+ <input type="text" placeholder="Search anything...">
6045
+ </div>
6046
+ </div>
6047
+
6048
+ <div class="right-section">
6049
+ <!-- Theme Switcher -->
6050
+ <button class="icon-btn theme-btn" (click)="themeToggleOpen.set(!themeToggleOpen())" title="Change Theme">
6051
+ <svg viewBox="0 0 24 24">
6052
+ <path [attr.d]="iconRegistry.getIcon('palette')"></path>
6053
+ </svg>
6054
+
6055
+ @if (themeToggleOpen()) {
6056
+ <div class="dropdown theme-dropdown">
6057
+ @for (theme of themeService.availableThemes; track theme.name) {
6058
+ <div
6059
+ class="dropdown-item"
6060
+ [class.active]="themeService.currentTheme() === theme.name"
6061
+ (click)="themeService.setTheme(theme.name); themeToggleOpen.set(false)"
6062
+ >
6063
+ <span class="theme-dot" [style.background]="getThemeColor(theme.name)"></span>
6064
+ {{ theme.label }}
6065
+ </div>
6066
+ }
6067
+ </div>
6068
+ }
6069
+ </button>
6070
+
6071
+ <!-- User Profile -->
6072
+ <div class="user-profile" (click)="userMenuOpen.set(!userMenuOpen())">
6073
+ <div class="user-info">
6074
+ <span class="user-name">{{ auth.user()?.name }}</span>
6075
+ <span class="user-role">{{ auth.user()?.role }}</span>
6076
+ </div>
6077
+ <div class="avatar">
6078
+ @if (auth.user()?.avatar) {
6079
+ <img [src]="auth.user()?.avatar" [alt]="auth.user()?.name">
6080
+ } @else {
6081
+ <svg viewBox="0 0 24 24">
6082
+ <path [attr.d]="iconRegistry.getIcon('person')"></path>
6083
+ </svg>
6084
+ }
6085
+ </div>
6086
+
6087
+ @if (userMenuOpen()) {
6088
+ <div class="dropdown user-dropdown">
6089
+ <div class="dropdown-header">
6090
+ <strong>{{ auth.user()?.name }}</strong>
6091
+ <span>{{ auth.user()?.email }}</span>
6092
+ </div>
6093
+ <div class="divider"></div>
6094
+ <div class="dropdown-item">Your Profile</div>
6095
+ <div class="dropdown-item">Settings</div>
6096
+ <div class="divider"></div>
6097
+ <div class="dropdown-item logout" (click)="auth.logout()">
6098
+ <svg viewBox="0 0 24 24" class="logout-icon">
6099
+ <path [attr.d]="iconRegistry.getIcon('logout')"></path>
6100
+ </svg>
6101
+ Logout
6102
+ </div>
6103
+ </div>
6104
+ }
6105
+ </div>
6106
+ </div>
6107
+ </header>
6108
6108
  `, styles: [":host{display:block;width:100%}.navbar-container{height:68px;padding:0 24px;background:var(--app-navbar-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border-bottom:1px solid var(--glass-border);display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}.left-section,.right-section{display:flex;align-items:center;gap:16px}.icon-btn{width:40px;height:40px;border-radius:10px;border:1px solid transparent;background:transparent;color:var(--app-text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--transition-smooth);position:relative}.icon-btn:hover{background:var(--glass-bg-hover);border-color:var(--glass-border);color:var(--app-primary);box-shadow:0 0 16px var(--app-glow)}.icon-btn svg{width:22px;height:22px;fill:currentColor}.search-box{display:flex;align-items:center;background:var(--glass-bg);border:1px solid var(--glass-border);border-radius:10px;padding:0 14px;width:300px;height:40px;transition:all var(--transition-smooth)}.search-box:focus-within{border-color:var(--app-primary);background:var(--glass-bg-hover);box-shadow:0 0 20px var(--app-glow)}.search-icon{width:18px;height:18px;fill:var(--app-text-muted);flex-shrink:0;transition:fill var(--transition-fast)}.search-box:focus-within .search-icon{fill:var(--app-primary)}.search-box input{border:none;background:transparent;padding:8px;outline:none;flex:1;font-size:.875rem;color:var(--app-text)}.search-box input::placeholder{color:var(--app-text-muted)}.user-profile{display:flex;align-items:center;gap:12px;cursor:pointer;padding:4px 12px;border-radius:12px;border:1px solid transparent;transition:all var(--transition-smooth);position:relative}.user-profile:hover{background:var(--glass-bg-hover);border-color:var(--glass-border)}.user-info{display:flex;flex-direction:column;align-items:flex-end}.user-name{font-size:.875rem;font-weight:600;color:var(--app-text)}.user-role{font-size:.6875rem;color:var(--app-text-muted);text-transform:uppercase;letter-spacing:.05em}.avatar{width:38px;height:38px;border-radius:12px;background:linear-gradient(135deg,var(--app-primary),var(--app-accent));color:#fff;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:box-shadow var(--transition-smooth)}.user-profile:hover .avatar{box-shadow:0 0 20px var(--app-glow)}.avatar img{width:100%;height:100%;object-fit:cover}.avatar svg{width:22px;height:22px;fill:currentColor}.dropdown{position:absolute;top:calc(100% + 8px);right:0;background:var(--app-bg-secondary);backdrop-filter:blur(var(--glass-blur-heavy));-webkit-backdrop-filter:blur(var(--glass-blur-heavy));border:1px solid var(--glass-border-light);border-radius:14px;box-shadow:var(--glass-shadow),0 0 30px #0006;min-width:220px;overflow:hidden;animation:slideInDown .25s ease-out}.dropdown-header{padding:14px 16px;display:flex;flex-direction:column}.dropdown-header strong{color:var(--app-text);font-size:.9375rem}.dropdown-header span{font-size:.75rem;color:var(--app-text-muted);margin-top:2px}.dropdown-item{padding:10px 16px;font-size:.875rem;cursor:pointer;transition:all var(--transition-fast);color:var(--app-text-muted);display:flex;align-items:center;gap:10px}.dropdown-item:hover{background:var(--glass-bg-hover);color:var(--app-primary)}.dropdown-item.active{background:var(--app-primary-light);color:var(--app-primary);font-weight:600}.theme-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.divider{height:1px;background:var(--glass-border);margin:4px 0}.logout{color:#f43f5e!important}.logout:hover{background:#f43f5e1a!important;color:#fb7185!important}.logout-icon{width:18px;height:18px;fill:currentColor}\n"] }]
6109
6109
  }] });
6110
6110
 
6111
6111
  class FooterComponent {
6112
6112
  config = inject(AppConfigService);
6113
6113
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6114
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: FooterComponent, isStandalone: true, selector: "app-footer", ngImport: i0, template: `
6115
- <footer class="footer-container">
6116
- <div class="footer-content">
6117
- <p class="copyright">{{ config.copyrightText() }}</p>
6118
- <div class="links">
6119
- <a href="#">Terms</a>
6120
- <a href="#">Privacy</a>
6121
- <a href="#">Support</a>
6122
- </div>
6123
- </div>
6124
- </footer>
6114
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: FooterComponent, isStandalone: true, selector: "app-footer", ngImport: i0, template: `
6115
+ <footer class="footer-container">
6116
+ <div class="footer-content">
6117
+ <p class="copyright">{{ config.copyrightText() }}</p>
6118
+ <div class="links">
6119
+ <a href="#">Terms</a>
6120
+ <a href="#">Privacy</a>
6121
+ <a href="#">Support</a>
6122
+ </div>
6123
+ </div>
6124
+ </footer>
6125
6125
  `, isInline: true, styles: [".footer-container{height:52px;padding:0 28px;background:var(--app-navbar-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border-top:1px solid var(--glass-border);display:flex;align-items:center;margin-top:auto;position:relative}.footer-container:before{content:\"\";position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(to right,transparent,var(--app-primary-light),transparent)}.footer-content{width:100%;display:flex;justify-content:space-between;align-items:center}.copyright{font-size:.8125rem;color:var(--app-text-muted);opacity:.6}.links{display:flex;gap:20px}.links a{font-size:.8125rem;color:var(--app-text-muted);text-decoration:none;transition:all var(--transition-fast);opacity:.6}.links a:hover{color:var(--app-primary);opacity:1}\n"] });
6126
6126
  }
6127
6127
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FooterComponent, decorators: [{
6128
6128
  type: Component,
6129
- args: [{ selector: 'app-footer', standalone: true, imports: [], template: `
6130
- <footer class="footer-container">
6131
- <div class="footer-content">
6132
- <p class="copyright">{{ config.copyrightText() }}</p>
6133
- <div class="links">
6134
- <a href="#">Terms</a>
6135
- <a href="#">Privacy</a>
6136
- <a href="#">Support</a>
6137
- </div>
6138
- </div>
6139
- </footer>
6129
+ args: [{ selector: 'app-footer', standalone: true, imports: [], template: `
6130
+ <footer class="footer-container">
6131
+ <div class="footer-content">
6132
+ <p class="copyright">{{ config.copyrightText() }}</p>
6133
+ <div class="links">
6134
+ <a href="#">Terms</a>
6135
+ <a href="#">Privacy</a>
6136
+ <a href="#">Support</a>
6137
+ </div>
6138
+ </div>
6139
+ </footer>
6140
6140
  `, styles: [".footer-container{height:52px;padding:0 28px;background:var(--app-navbar-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border-top:1px solid var(--glass-border);display:flex;align-items:center;margin-top:auto;position:relative}.footer-container:before{content:\"\";position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(to right,transparent,var(--app-primary-light),transparent)}.footer-content{width:100%;display:flex;justify-content:space-between;align-items:center}.copyright{font-size:.8125rem;color:var(--app-text-muted);opacity:.6}.links{display:flex;gap:20px}.links a{font-size:.8125rem;color:var(--app-text-muted);text-decoration:none;transition:all var(--transition-fast);opacity:.6}.links a:hover{color:var(--app-primary);opacity:1}\n"] }]
6141
6141
  }] });
6142
6142
 
6143
6143
  class VerticalLayoutComponent {
6144
6144
  config = inject(AppConfigService);
6145
6145
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: VerticalLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6146
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: VerticalLayoutComponent, isStandalone: true, selector: "app-vertical-layout", ngImport: i0, template: `
6147
- <div class="layout-wrapper" [class.collapsed]="config.sidebarCollapsed()">
6148
- <!-- Animated Gradient Mesh Background -->
6149
- <div class="gradient-mesh" aria-hidden="true">
6150
- <div class="blob blob-1"></div>
6151
- <div class="blob blob-2"></div>
6152
- <div class="blob blob-3"></div>
6153
- </div>
6154
-
6155
- <!-- Sidebar -->
6156
- <app-sidebar class="layout-sidebar"></app-sidebar>
6157
-
6158
- <!-- Main Content Area -->
6159
- <div class="layout-main">
6160
- <app-navbar></app-navbar>
6161
-
6162
- <main class="content-body">
6163
- <router-outlet></router-outlet>
6164
- </main>
6165
-
6166
- <app-footer></app-footer>
6167
- </div>
6168
- </div>
6146
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: VerticalLayoutComponent, isStandalone: true, selector: "app-vertical-layout", ngImport: i0, template: `
6147
+ <div class="layout-wrapper" [class.collapsed]="config.sidebarCollapsed()">
6148
+ <!-- Animated Gradient Mesh Background -->
6149
+ <div class="gradient-mesh" aria-hidden="true">
6150
+ <div class="blob blob-1"></div>
6151
+ <div class="blob blob-2"></div>
6152
+ <div class="blob blob-3"></div>
6153
+ </div>
6154
+
6155
+ <!-- Sidebar -->
6156
+ <app-sidebar class="layout-sidebar"></app-sidebar>
6157
+
6158
+ <!-- Main Content Area -->
6159
+ <div class="layout-main">
6160
+ <app-navbar></app-navbar>
6161
+
6162
+ <main class="content-body">
6163
+ <router-outlet></router-outlet>
6164
+ </main>
6165
+
6166
+ <app-footer></app-footer>
6167
+ </div>
6168
+ </div>
6169
6169
  `, isInline: true, styles: [":host{display:block;height:100vh;width:100%}.layout-wrapper{display:flex;height:100vh;overflow:hidden;background:var(--app-bg);position:relative}.gradient-mesh{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none}.blob{position:absolute;border-radius:50%;filter:blur(80px);opacity:.35;will-change:transform}.blob-1{width:500px;height:500px;background:var(--app-gradient-1);top:-10%;right:-5%;animation:blobMove1 20s ease-in-out infinite}.blob-2{width:400px;height:400px;background:var(--app-gradient-2);bottom:-10%;left:10%;animation:blobMove2 25s ease-in-out infinite}.blob-3{width:350px;height:350px;background:var(--app-gradient-3);top:40%;left:40%;animation:blobMove3 22s ease-in-out infinite}.layout-sidebar{flex-shrink:0;z-index:100;position:relative}.layout-main{flex:1;display:flex;flex-direction:column;overflow-y:auto;position:relative;z-index:1;transition:margin-left var(--transition-smooth)}.content-body{padding:28px;flex:1;max-width:1600px;width:100%;margin:0 auto;animation:fadeInUp .4s ease-out}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: SidebarComponent, selector: "app-sidebar" }, { kind: "component", type: NavbarComponent, selector: "app-navbar" }, { kind: "component", type: FooterComponent, selector: "app-footer" }] });
6170
6170
  }
6171
6171
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: VerticalLayoutComponent, decorators: [{
6172
6172
  type: Component,
6173
- args: [{ selector: 'app-vertical-layout', standalone: true, imports: [RouterOutlet, SidebarComponent, NavbarComponent, FooterComponent], template: `
6174
- <div class="layout-wrapper" [class.collapsed]="config.sidebarCollapsed()">
6175
- <!-- Animated Gradient Mesh Background -->
6176
- <div class="gradient-mesh" aria-hidden="true">
6177
- <div class="blob blob-1"></div>
6178
- <div class="blob blob-2"></div>
6179
- <div class="blob blob-3"></div>
6180
- </div>
6181
-
6182
- <!-- Sidebar -->
6183
- <app-sidebar class="layout-sidebar"></app-sidebar>
6184
-
6185
- <!-- Main Content Area -->
6186
- <div class="layout-main">
6187
- <app-navbar></app-navbar>
6188
-
6189
- <main class="content-body">
6190
- <router-outlet></router-outlet>
6191
- </main>
6192
-
6193
- <app-footer></app-footer>
6194
- </div>
6195
- </div>
6173
+ args: [{ selector: 'app-vertical-layout', standalone: true, imports: [RouterOutlet, SidebarComponent, NavbarComponent, FooterComponent], template: `
6174
+ <div class="layout-wrapper" [class.collapsed]="config.sidebarCollapsed()">
6175
+ <!-- Animated Gradient Mesh Background -->
6176
+ <div class="gradient-mesh" aria-hidden="true">
6177
+ <div class="blob blob-1"></div>
6178
+ <div class="blob blob-2"></div>
6179
+ <div class="blob blob-3"></div>
6180
+ </div>
6181
+
6182
+ <!-- Sidebar -->
6183
+ <app-sidebar class="layout-sidebar"></app-sidebar>
6184
+
6185
+ <!-- Main Content Area -->
6186
+ <div class="layout-main">
6187
+ <app-navbar></app-navbar>
6188
+
6189
+ <main class="content-body">
6190
+ <router-outlet></router-outlet>
6191
+ </main>
6192
+
6193
+ <app-footer></app-footer>
6194
+ </div>
6195
+ </div>
6196
6196
  `, styles: [":host{display:block;height:100vh;width:100%}.layout-wrapper{display:flex;height:100vh;overflow:hidden;background:var(--app-bg);position:relative}.gradient-mesh{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none}.blob{position:absolute;border-radius:50%;filter:blur(80px);opacity:.35;will-change:transform}.blob-1{width:500px;height:500px;background:var(--app-gradient-1);top:-10%;right:-5%;animation:blobMove1 20s ease-in-out infinite}.blob-2{width:400px;height:400px;background:var(--app-gradient-2);bottom:-10%;left:10%;animation:blobMove2 25s ease-in-out infinite}.blob-3{width:350px;height:350px;background:var(--app-gradient-3);top:40%;left:40%;animation:blobMove3 22s ease-in-out infinite}.layout-sidebar{flex-shrink:0;z-index:100;position:relative}.layout-main{flex:1;display:flex;flex-direction:column;overflow-y:auto;position:relative;z-index:1;transition:margin-left var(--transition-smooth)}.content-body{padding:28px;flex:1;max-width:1600px;width:100%;margin:0 auto;animation:fadeInUp .4s ease-out}\n"] }]
6197
6197
  }] });
6198
6198
 
@@ -6200,183 +6200,183 @@ class HorizontalLayoutComponent {
6200
6200
  navigation = inject(NavigationService);
6201
6201
  iconRegistry = inject(IconRegistryService);
6202
6202
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: HorizontalLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6203
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: HorizontalLayoutComponent, isStandalone: true, selector: "app-horizontal-layout", ngImport: i0, template: `
6204
- <div class="layout-wrapper">
6205
- <app-navbar>
6206
- <!-- Horizontal Menu Injection (Conceptual - in a full app we'd use a dedicated component or slot) -->
6207
- </app-navbar>
6208
-
6209
- <nav class="horizontal-nav">
6210
- <div class="nav-container">
6211
- <ul>
6212
- @for (group of navigation.menuItems(); track group.label) {
6213
- @for (item of group.items; track item.label) {
6214
- <li class="nav-item">
6215
- <a [routerLink]="item.route" routerLinkActive="active" class="nav-link">
6216
- @if (item.icon) {
6217
- <svg viewBox="0 0 24 24" class="nav-icon">
6218
- <path [attr.d]="iconRegistry.getIcon(item.icon)"></path>
6219
- </svg>
6220
- }
6221
- {{ item.label }}
6222
- </a>
6223
- </li>
6224
- }
6225
- }
6226
- </ul>
6227
- </div>
6228
- </nav>
6229
-
6230
- <main class="content-body">
6231
- <router-outlet></router-outlet>
6232
- </main>
6233
-
6234
- <app-footer></app-footer>
6235
- </div>
6203
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: HorizontalLayoutComponent, isStandalone: true, selector: "app-horizontal-layout", ngImport: i0, template: `
6204
+ <div class="layout-wrapper">
6205
+ <app-navbar>
6206
+ <!-- Horizontal Menu Injection (Conceptual - in a full app we'd use a dedicated component or slot) -->
6207
+ </app-navbar>
6208
+
6209
+ <nav class="horizontal-nav">
6210
+ <div class="nav-container">
6211
+ <ul>
6212
+ @for (group of navigation.menuItems(); track group.label) {
6213
+ @for (item of group.items; track item.label) {
6214
+ <li class="nav-item">
6215
+ <a [routerLink]="item.route" routerLinkActive="active" class="nav-link">
6216
+ @if (item.icon) {
6217
+ <svg viewBox="0 0 24 24" class="nav-icon">
6218
+ <path [attr.d]="iconRegistry.getIcon(item.icon)"></path>
6219
+ </svg>
6220
+ }
6221
+ {{ item.label }}
6222
+ </a>
6223
+ </li>
6224
+ }
6225
+ }
6226
+ </ul>
6227
+ </div>
6228
+ </nav>
6229
+
6230
+ <main class="content-body">
6231
+ <router-outlet></router-outlet>
6232
+ </main>
6233
+
6234
+ <app-footer></app-footer>
6235
+ </div>
6236
6236
  `, isInline: true, styles: [".layout-wrapper{display:flex;flex-direction:column;min-height:100vh;background:var(--app-bg, #f9fafb)}.horizontal-nav{background:var(--app-navbar-bg, #ffffff);border-bottom:1px solid var(--app-border, #e5e7eb);height:48px}.nav-container{max-width:1600px;margin:0 auto;height:100%;padding:0 24px}ul{display:flex;list-style:none;padding:0;margin:0;height:100%;gap:32px}.nav-item{height:100%}.nav-link{display:flex;align-items:center;gap:8px;height:100%;color:var(--app-text, #374151);text-decoration:none;font-size:.875rem;font-weight:500;border-bottom:2px solid transparent;transition:all .2s}.nav-link:hover{color:var(--app-primary, #3b82f6)}.nav-link.active{color:var(--app-primary, #3b82f6);border-bottom-color:var(--app-primary, #3b82f6)}.nav-icon{width:18px;height:18px;fill:currentColor}.content-body{padding:24px;flex:1;max-width:1600px;width:100%;margin:0 auto}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: NavbarComponent, selector: "app-navbar" }, { kind: "component", type: FooterComponent, selector: "app-footer" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
6237
6237
  }
6238
6238
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: HorizontalLayoutComponent, decorators: [{
6239
6239
  type: Component,
6240
- args: [{ selector: 'app-horizontal-layout', standalone: true, imports: [RouterOutlet, NavbarComponent, FooterComponent, RouterLink, RouterLinkActive], template: `
6241
- <div class="layout-wrapper">
6242
- <app-navbar>
6243
- <!-- Horizontal Menu Injection (Conceptual - in a full app we'd use a dedicated component or slot) -->
6244
- </app-navbar>
6245
-
6246
- <nav class="horizontal-nav">
6247
- <div class="nav-container">
6248
- <ul>
6249
- @for (group of navigation.menuItems(); track group.label) {
6250
- @for (item of group.items; track item.label) {
6251
- <li class="nav-item">
6252
- <a [routerLink]="item.route" routerLinkActive="active" class="nav-link">
6253
- @if (item.icon) {
6254
- <svg viewBox="0 0 24 24" class="nav-icon">
6255
- <path [attr.d]="iconRegistry.getIcon(item.icon)"></path>
6256
- </svg>
6257
- }
6258
- {{ item.label }}
6259
- </a>
6260
- </li>
6261
- }
6262
- }
6263
- </ul>
6264
- </div>
6265
- </nav>
6266
-
6267
- <main class="content-body">
6268
- <router-outlet></router-outlet>
6269
- </main>
6270
-
6271
- <app-footer></app-footer>
6272
- </div>
6240
+ args: [{ selector: 'app-horizontal-layout', standalone: true, imports: [RouterOutlet, NavbarComponent, FooterComponent, RouterLink, RouterLinkActive], template: `
6241
+ <div class="layout-wrapper">
6242
+ <app-navbar>
6243
+ <!-- Horizontal Menu Injection (Conceptual - in a full app we'd use a dedicated component or slot) -->
6244
+ </app-navbar>
6245
+
6246
+ <nav class="horizontal-nav">
6247
+ <div class="nav-container">
6248
+ <ul>
6249
+ @for (group of navigation.menuItems(); track group.label) {
6250
+ @for (item of group.items; track item.label) {
6251
+ <li class="nav-item">
6252
+ <a [routerLink]="item.route" routerLinkActive="active" class="nav-link">
6253
+ @if (item.icon) {
6254
+ <svg viewBox="0 0 24 24" class="nav-icon">
6255
+ <path [attr.d]="iconRegistry.getIcon(item.icon)"></path>
6256
+ </svg>
6257
+ }
6258
+ {{ item.label }}
6259
+ </a>
6260
+ </li>
6261
+ }
6262
+ }
6263
+ </ul>
6264
+ </div>
6265
+ </nav>
6266
+
6267
+ <main class="content-body">
6268
+ <router-outlet></router-outlet>
6269
+ </main>
6270
+
6271
+ <app-footer></app-footer>
6272
+ </div>
6273
6273
  `, styles: [".layout-wrapper{display:flex;flex-direction:column;min-height:100vh;background:var(--app-bg, #f9fafb)}.horizontal-nav{background:var(--app-navbar-bg, #ffffff);border-bottom:1px solid var(--app-border, #e5e7eb);height:48px}.nav-container{max-width:1600px;margin:0 auto;height:100%;padding:0 24px}ul{display:flex;list-style:none;padding:0;margin:0;height:100%;gap:32px}.nav-item{height:100%}.nav-link{display:flex;align-items:center;gap:8px;height:100%;color:var(--app-text, #374151);text-decoration:none;font-size:.875rem;font-weight:500;border-bottom:2px solid transparent;transition:all .2s}.nav-link:hover{color:var(--app-primary, #3b82f6)}.nav-link.active{color:var(--app-primary, #3b82f6);border-bottom-color:var(--app-primary, #3b82f6)}.nav-icon{width:18px;height:18px;fill:currentColor}.content-body{padding:24px;flex:1;max-width:1600px;width:100%;margin:0 auto}\n"] }]
6274
6274
  }] });
6275
6275
 
6276
6276
  class EmptyLayoutComponent {
6277
6277
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EmptyLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6278
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: EmptyLayoutComponent, isStandalone: true, selector: "app-empty-layout", ngImport: i0, template: `
6279
- <div class="empty-layout-container">
6280
- <router-outlet></router-outlet>
6281
- </div>
6278
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: EmptyLayoutComponent, isStandalone: true, selector: "app-empty-layout", ngImport: i0, template: `
6279
+ <div class="empty-layout-container">
6280
+ <router-outlet></router-outlet>
6281
+ </div>
6282
6282
  `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.empty-layout-container{height:100%;display:flex;flex-direction:column;background:var(--app-bg, #f9fafb);color:var(--app-text, #111827)}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
6283
6283
  }
6284
6284
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EmptyLayoutComponent, decorators: [{
6285
6285
  type: Component,
6286
- args: [{ selector: 'app-empty-layout', standalone: true, imports: [RouterOutlet], template: `
6287
- <div class="empty-layout-container">
6288
- <router-outlet></router-outlet>
6289
- </div>
6286
+ args: [{ selector: 'app-empty-layout', standalone: true, imports: [RouterOutlet], template: `
6287
+ <div class="empty-layout-container">
6288
+ <router-outlet></router-outlet>
6289
+ </div>
6290
6290
  `, styles: [":host{display:flex;flex-direction:column;height:100%}.empty-layout-container{height:100%;display:flex;flex-direction:column;background:var(--app-bg, #f9fafb);color:var(--app-text, #111827)}\n"] }]
6291
6291
  }] });
6292
6292
 
6293
6293
  class CenteredLayoutComponent {
6294
6294
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CenteredLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6295
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: CenteredLayoutComponent, isStandalone: true, selector: "app-centered-layout", ngImport: i0, template: `
6296
- <div class="centered-container">
6297
- <div class="centered-content glass-panel">
6298
- <router-outlet></router-outlet>
6299
- </div>
6300
- </div>
6295
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: CenteredLayoutComponent, isStandalone: true, selector: "app-centered-layout", ngImport: i0, template: `
6296
+ <div class="centered-container">
6297
+ <div class="centered-content glass-panel">
6298
+ <router-outlet></router-outlet>
6299
+ </div>
6300
+ </div>
6301
6301
  `, isInline: true, styles: [".centered-container{display:flex;align-items:center;justify-content:center;min-height:100vh;background:var(--app-bg, #f9fafb);padding:2rem}.centered-content{width:100%;max-width:600px;padding:2rem;border-radius:1rem}.glass-panel{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);box-shadow:var(--glass-shadow)}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
6302
6302
  }
6303
6303
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CenteredLayoutComponent, decorators: [{
6304
6304
  type: Component,
6305
- args: [{ selector: 'app-centered-layout', standalone: true, imports: [RouterOutlet], template: `
6306
- <div class="centered-container">
6307
- <div class="centered-content glass-panel">
6308
- <router-outlet></router-outlet>
6309
- </div>
6310
- </div>
6305
+ args: [{ selector: 'app-centered-layout', standalone: true, imports: [RouterOutlet], template: `
6306
+ <div class="centered-container">
6307
+ <div class="centered-content glass-panel">
6308
+ <router-outlet></router-outlet>
6309
+ </div>
6310
+ </div>
6311
6311
  `, styles: [".centered-container{display:flex;align-items:center;justify-content:center;min-height:100vh;background:var(--app-bg, #f9fafb);padding:2rem}.centered-content{width:100%;max-width:600px;padding:2rem;border-radius:1rem}.glass-panel{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);box-shadow:var(--glass-shadow)}\n"] }]
6312
6312
  }] });
6313
6313
 
6314
6314
  class TwoColumnLayoutComponent {
6315
6315
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TwoColumnLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6316
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: TwoColumnLayoutComponent, isStandalone: true, selector: "app-two-column-layout", ngImport: i0, template: `
6317
- <div class="two-column-container">
6318
- <aside class="left-panel glass-panel">
6319
- <!-- Master list or secondary navigation ideally goes here -->
6320
- <div class="placeholder-nav">Navigation / List</div>
6321
- </aside>
6322
- <main class="right-panel">
6323
- <router-outlet></router-outlet>
6324
- </main>
6325
- </div>
6316
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: TwoColumnLayoutComponent, isStandalone: true, selector: "app-two-column-layout", ngImport: i0, template: `
6317
+ <div class="two-column-container">
6318
+ <aside class="left-panel glass-panel">
6319
+ <!-- Master list or secondary navigation ideally goes here -->
6320
+ <div class="placeholder-nav">Navigation / List</div>
6321
+ </aside>
6322
+ <main class="right-panel">
6323
+ <router-outlet></router-outlet>
6324
+ </main>
6325
+ </div>
6326
6326
  `, isInline: true, styles: [".two-column-container{display:flex;min-height:100vh;background:var(--app-bg)}.left-panel{width:300px;flex-shrink:0;border-right:1px solid var(--glass-border);padding:1rem;display:flex;flex-direction:column}.right-panel{flex:1;padding:2rem;overflow-y:auto}.glass-panel{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur))}.placeholder-nav{color:var(--app-text-muted);font-size:.875rem;text-align:center;margin-top:2rem}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
6327
6327
  }
6328
6328
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TwoColumnLayoutComponent, decorators: [{
6329
6329
  type: Component,
6330
- args: [{ selector: 'app-two-column-layout', standalone: true, imports: [RouterOutlet], template: `
6331
- <div class="two-column-container">
6332
- <aside class="left-panel glass-panel">
6333
- <!-- Master list or secondary navigation ideally goes here -->
6334
- <div class="placeholder-nav">Navigation / List</div>
6335
- </aside>
6336
- <main class="right-panel">
6337
- <router-outlet></router-outlet>
6338
- </main>
6339
- </div>
6330
+ args: [{ selector: 'app-two-column-layout', standalone: true, imports: [RouterOutlet], template: `
6331
+ <div class="two-column-container">
6332
+ <aside class="left-panel glass-panel">
6333
+ <!-- Master list or secondary navigation ideally goes here -->
6334
+ <div class="placeholder-nav">Navigation / List</div>
6335
+ </aside>
6336
+ <main class="right-panel">
6337
+ <router-outlet></router-outlet>
6338
+ </main>
6339
+ </div>
6340
6340
  `, styles: [".two-column-container{display:flex;min-height:100vh;background:var(--app-bg)}.left-panel{width:300px;flex-shrink:0;border-right:1px solid var(--glass-border);padding:1rem;display:flex;flex-direction:column}.right-panel{flex:1;padding:2rem;overflow-y:auto}.glass-panel{background:var(--glass-bg);backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur))}.placeholder-nav{color:var(--app-text-muted);font-size:.875rem;text-align:center;margin-top:2rem}\n"] }]
6341
6341
  }] });
6342
6342
 
6343
6343
  class DashboardGridLayoutComponent {
6344
6344
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DashboardGridLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6345
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: DashboardGridLayoutComponent, isStandalone: true, selector: "app-dashboard-grid-layout", ngImport: i0, template: `
6346
- <div class="dashboard-grid-container">
6347
- <router-outlet></router-outlet>
6348
- </div>
6345
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: DashboardGridLayoutComponent, isStandalone: true, selector: "app-dashboard-grid-layout", ngImport: i0, template: `
6346
+ <div class="dashboard-grid-container">
6347
+ <router-outlet></router-outlet>
6348
+ </div>
6349
6349
  `, isInline: true, styles: [".dashboard-grid-container{display:grid;grid-template-columns:repeat(12,1fr);gap:1.5rem;padding:2rem;min-height:100vh;background:var(--app-bg)}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
6350
6350
  }
6351
6351
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DashboardGridLayoutComponent, decorators: [{
6352
6352
  type: Component,
6353
- args: [{ selector: 'app-dashboard-grid-layout', standalone: true, imports: [RouterOutlet], template: `
6354
- <div class="dashboard-grid-container">
6355
- <router-outlet></router-outlet>
6356
- </div>
6353
+ args: [{ selector: 'app-dashboard-grid-layout', standalone: true, imports: [RouterOutlet], template: `
6354
+ <div class="dashboard-grid-container">
6355
+ <router-outlet></router-outlet>
6356
+ </div>
6357
6357
  `, styles: [".dashboard-grid-container{display:grid;grid-template-columns:repeat(12,1fr);gap:1.5rem;padding:2rem;min-height:100vh;background:var(--app-bg)}\n"] }]
6358
6358
  }] });
6359
6359
 
6360
6360
  class CompactLayoutComponent {
6361
6361
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CompactLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6362
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: CompactLayoutComponent, isStandalone: true, selector: "app-compact-layout", ngImport: i0, template: `
6363
- <div class="compact-container">
6364
- <!-- Minimal or no header -->
6365
- <main class="compact-content">
6366
- <router-outlet></router-outlet>
6367
- </main>
6368
- </div>
6362
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: CompactLayoutComponent, isStandalone: true, selector: "app-compact-layout", ngImport: i0, template: `
6363
+ <div class="compact-container">
6364
+ <!-- Minimal or no header -->
6365
+ <main class="compact-content">
6366
+ <router-outlet></router-outlet>
6367
+ </main>
6368
+ </div>
6369
6369
  `, isInline: true, styles: [".compact-container{display:flex;flex-direction:column;min-height:100vh;background:var(--app-bg)}.compact-content{flex:1;padding:1rem;max-width:100%;overflow-x:hidden}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
6370
6370
  }
6371
6371
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CompactLayoutComponent, decorators: [{
6372
6372
  type: Component,
6373
- args: [{ selector: 'app-compact-layout', standalone: true, imports: [RouterOutlet], template: `
6374
- <div class="compact-container">
6375
- <!-- Minimal or no header -->
6376
- <main class="compact-content">
6377
- <router-outlet></router-outlet>
6378
- </main>
6379
- </div>
6373
+ args: [{ selector: 'app-compact-layout', standalone: true, imports: [RouterOutlet], template: `
6374
+ <div class="compact-container">
6375
+ <!-- Minimal or no header -->
6376
+ <main class="compact-content">
6377
+ <router-outlet></router-outlet>
6378
+ </main>
6379
+ </div>
6380
6380
  `, styles: [".compact-container{display:flex;flex-direction:column;min-height:100vh;background:var(--app-bg)}.compact-content{flex:1;padding:1rem;max-width:100%;overflow-x:hidden}\n"] }]
6381
6381
  }] });
6382
6382
 
@@ -6392,50 +6392,50 @@ class NotificationContainerComponent {
6392
6392
  }
6393
6393
  }
6394
6394
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: NotificationContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6395
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: NotificationContainerComponent, isStandalone: true, selector: "app-notification-container", ngImport: i0, template: `
6396
- <div class="notification-wrapper">
6397
- @for (n of service.notifications(); track n.id) {
6398
- <div class="toast" [class]="n.type" (click)="service.remove(n.id)">
6399
- <div class="toast-icon">
6400
- <svg viewBox="0 0 24 24">
6401
- <path [attr.d]="getIcon(n.type)"></path>
6402
- </svg>
6403
- </div>
6404
- <div class="toast-content">
6405
- {{ n.message }}
6406
- </div>
6407
- <button class="toast-close">
6408
- <svg viewBox="0 0 24 24">
6409
- <path [attr.d]="iconRegistry.getIcon('close')"></path>
6410
- </svg>
6411
- </button>
6412
- </div>
6413
- }
6414
- </div>
6395
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: NotificationContainerComponent, isStandalone: true, selector: "app-notification-container", ngImport: i0, template: `
6396
+ <div class="notification-wrapper">
6397
+ @for (n of service.notifications(); track n.id) {
6398
+ <div class="toast" [class]="n.type" (click)="service.remove(n.id)">
6399
+ <div class="toast-icon">
6400
+ <svg viewBox="0 0 24 24">
6401
+ <path [attr.d]="getIcon(n.type)"></path>
6402
+ </svg>
6403
+ </div>
6404
+ <div class="toast-content">
6405
+ {{ n.message }}
6406
+ </div>
6407
+ <button class="toast-close">
6408
+ <svg viewBox="0 0 24 24">
6409
+ <path [attr.d]="iconRegistry.getIcon('close')"></path>
6410
+ </svg>
6411
+ </button>
6412
+ </div>
6413
+ }
6414
+ </div>
6415
6415
  `, isInline: true, styles: [".notification-wrapper{position:fixed;top:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:12px;pointer-events:none}.toast{pointer-events:auto;min-width:300px;max-width:450px;background:var(--app-surface, #ffffff);border-radius:12px;padding:16px;display:flex;align-items:center;gap:12px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d;border-left:4px solid #e5e7eb;cursor:pointer;animation:slideIn .3s cubic-bezier(.4,0,.2,1);transition:all .2s}.toast:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.toast.success{border-left-color:#10b981}.toast.error{border-left-color:#ef4444}.toast.warning{border-left-color:#f59e0b}.toast.info{border-left-color:#3b82f6}.toast-icon{width:24px;height:24px;flex-shrink:0}.toast.success .toast-icon{fill:#10b981}.toast.error .toast-icon{fill:#ef4444}.toast.warning .toast-icon{fill:#f59e0b}.toast.info .toast-icon{fill:#3b82f6}.toast-content{flex:1;font-size:.875rem;font-weight:500;color:var(--app-text, #1f2937);line-height:1.4}.toast-close{background:none;border:none;padding:4px;cursor:pointer;color:var(--app-text-muted, #6b7280);opacity:.5;transition:opacity .2s}.toast-close:hover{opacity:1}.toast-close svg{width:16px;height:16px;fill:currentColor}@keyframes slideIn{0%{opacity:0;transform:translate(100%)}to{opacity:1;transform:translate(0)}}\n"] });
6416
6416
  }
6417
6417
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: NotificationContainerComponent, decorators: [{
6418
6418
  type: Component,
6419
- args: [{ selector: 'app-notification-container', standalone: true, imports: [], template: `
6420
- <div class="notification-wrapper">
6421
- @for (n of service.notifications(); track n.id) {
6422
- <div class="toast" [class]="n.type" (click)="service.remove(n.id)">
6423
- <div class="toast-icon">
6424
- <svg viewBox="0 0 24 24">
6425
- <path [attr.d]="getIcon(n.type)"></path>
6426
- </svg>
6427
- </div>
6428
- <div class="toast-content">
6429
- {{ n.message }}
6430
- </div>
6431
- <button class="toast-close">
6432
- <svg viewBox="0 0 24 24">
6433
- <path [attr.d]="iconRegistry.getIcon('close')"></path>
6434
- </svg>
6435
- </button>
6436
- </div>
6437
- }
6438
- </div>
6419
+ args: [{ selector: 'app-notification-container', standalone: true, imports: [], template: `
6420
+ <div class="notification-wrapper">
6421
+ @for (n of service.notifications(); track n.id) {
6422
+ <div class="toast" [class]="n.type" (click)="service.remove(n.id)">
6423
+ <div class="toast-icon">
6424
+ <svg viewBox="0 0 24 24">
6425
+ <path [attr.d]="getIcon(n.type)"></path>
6426
+ </svg>
6427
+ </div>
6428
+ <div class="toast-content">
6429
+ {{ n.message }}
6430
+ </div>
6431
+ <button class="toast-close">
6432
+ <svg viewBox="0 0 24 24">
6433
+ <path [attr.d]="iconRegistry.getIcon('close')"></path>
6434
+ </svg>
6435
+ </button>
6436
+ </div>
6437
+ }
6438
+ </div>
6439
6439
  `, styles: [".notification-wrapper{position:fixed;top:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:12px;pointer-events:none}.toast{pointer-events:auto;min-width:300px;max-width:450px;background:var(--app-surface, #ffffff);border-radius:12px;padding:16px;display:flex;align-items:center;gap:12px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d;border-left:4px solid #e5e7eb;cursor:pointer;animation:slideIn .3s cubic-bezier(.4,0,.2,1);transition:all .2s}.toast:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.toast.success{border-left-color:#10b981}.toast.error{border-left-color:#ef4444}.toast.warning{border-left-color:#f59e0b}.toast.info{border-left-color:#3b82f6}.toast-icon{width:24px;height:24px;flex-shrink:0}.toast.success .toast-icon{fill:#10b981}.toast.error .toast-icon{fill:#ef4444}.toast.warning .toast-icon{fill:#f59e0b}.toast.info .toast-icon{fill:#3b82f6}.toast-content{flex:1;font-size:.875rem;font-weight:500;color:var(--app-text, #1f2937);line-height:1.4}.toast-close{background:none;border:none;padding:4px;cursor:pointer;color:var(--app-text-muted, #6b7280);opacity:.5;transition:opacity .2s}.toast-close:hover{opacity:1}.toast-close svg{width:16px;height:16px;fill:currentColor}@keyframes slideIn{0%{opacity:0;transform:translate(100%)}to{opacity:1;transform:translate(0)}}\n"] }]
6440
6440
  }] });
6441
6441
 
@@ -6447,37 +6447,37 @@ class LayoutComponent {
6447
6447
  config = inject(AppConfigService);
6448
6448
  LayoutType = LayoutType;
6449
6449
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6450
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: LayoutComponent, isStandalone: true, selector: "app-layout", ngImport: i0, template: `
6451
- <app-notification-container></app-notification-container>
6452
- <amf-modal-host></amf-modal-host>
6453
- <amf-dialog-host></amf-dialog-host>
6454
- <amf-drawer-host></amf-drawer-host>
6455
- @switch (config.currentLayout()) {
6456
- @case (LayoutType.VERTICAL) {
6457
- <app-vertical-layout></app-vertical-layout>
6458
- }
6459
- @case (LayoutType.HORIZONTAL) {
6460
- <app-horizontal-layout></app-horizontal-layout>
6461
- }
6462
- @case (LayoutType.EMPTY) {
6463
- <app-empty-layout></app-empty-layout>
6464
- }
6465
- @case (LayoutType.CENTERED) {
6466
- <app-centered-layout></app-centered-layout>
6467
- }
6468
- @case (LayoutType.TWO_COLUMN) {
6469
- <app-two-column-layout></app-two-column-layout>
6470
- }
6471
- @case (LayoutType.DASHBOARD_GRID) {
6472
- <app-dashboard-grid-layout></app-dashboard-grid-layout>
6473
- }
6474
- @case (LayoutType.COMPACT) {
6475
- <app-compact-layout></app-compact-layout>
6476
- }
6477
- @default {
6478
- <app-vertical-layout></app-vertical-layout>
6479
- }
6480
- }
6450
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: LayoutComponent, isStandalone: true, selector: "app-layout", ngImport: i0, template: `
6451
+ <app-notification-container></app-notification-container>
6452
+ <amf-modal-host></amf-modal-host>
6453
+ <amf-dialog-host></amf-dialog-host>
6454
+ <amf-drawer-host></amf-drawer-host>
6455
+ @switch (config.currentLayout()) {
6456
+ @case (LayoutType.VERTICAL) {
6457
+ <app-vertical-layout></app-vertical-layout>
6458
+ }
6459
+ @case (LayoutType.HORIZONTAL) {
6460
+ <app-horizontal-layout></app-horizontal-layout>
6461
+ }
6462
+ @case (LayoutType.EMPTY) {
6463
+ <app-empty-layout></app-empty-layout>
6464
+ }
6465
+ @case (LayoutType.CENTERED) {
6466
+ <app-centered-layout></app-centered-layout>
6467
+ }
6468
+ @case (LayoutType.TWO_COLUMN) {
6469
+ <app-two-column-layout></app-two-column-layout>
6470
+ }
6471
+ @case (LayoutType.DASHBOARD_GRID) {
6472
+ <app-dashboard-grid-layout></app-dashboard-grid-layout>
6473
+ }
6474
+ @case (LayoutType.COMPACT) {
6475
+ <app-compact-layout></app-compact-layout>
6476
+ }
6477
+ @default {
6478
+ <app-vertical-layout></app-vertical-layout>
6479
+ }
6480
+ }
6481
6481
  `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "component", type: VerticalLayoutComponent, selector: "app-vertical-layout" }, { kind: "component", type: HorizontalLayoutComponent, selector: "app-horizontal-layout" }, { kind: "component", type: EmptyLayoutComponent, selector: "app-empty-layout" }, { kind: "component", type: CenteredLayoutComponent, selector: "app-centered-layout" }, { kind: "component", type: TwoColumnLayoutComponent, selector: "app-two-column-layout" }, { kind: "component", type: DashboardGridLayoutComponent, selector: "app-dashboard-grid-layout" }, { kind: "component", type: CompactLayoutComponent, selector: "app-compact-layout" }, { kind: "component", type: NotificationContainerComponent, selector: "app-notification-container" }, { kind: "component", type: MetaModalHostComponent, selector: "amf-modal-host" }, { kind: "component", type: AmfDialogHostComponent, selector: "amf-dialog-host" }, { kind: "component", type: AmfDrawerHostComponent, selector: "amf-drawer-host" }] });
6482
6482
  }
6483
6483
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutComponent, decorators: [{
@@ -6494,37 +6494,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6494
6494
  MetaModalHostComponent,
6495
6495
  AmfDialogHostComponent,
6496
6496
  AmfDrawerHostComponent
6497
- ], template: `
6498
- <app-notification-container></app-notification-container>
6499
- <amf-modal-host></amf-modal-host>
6500
- <amf-dialog-host></amf-dialog-host>
6501
- <amf-drawer-host></amf-drawer-host>
6502
- @switch (config.currentLayout()) {
6503
- @case (LayoutType.VERTICAL) {
6504
- <app-vertical-layout></app-vertical-layout>
6505
- }
6506
- @case (LayoutType.HORIZONTAL) {
6507
- <app-horizontal-layout></app-horizontal-layout>
6508
- }
6509
- @case (LayoutType.EMPTY) {
6510
- <app-empty-layout></app-empty-layout>
6511
- }
6512
- @case (LayoutType.CENTERED) {
6513
- <app-centered-layout></app-centered-layout>
6514
- }
6515
- @case (LayoutType.TWO_COLUMN) {
6516
- <app-two-column-layout></app-two-column-layout>
6517
- }
6518
- @case (LayoutType.DASHBOARD_GRID) {
6519
- <app-dashboard-grid-layout></app-dashboard-grid-layout>
6520
- }
6521
- @case (LayoutType.COMPACT) {
6522
- <app-compact-layout></app-compact-layout>
6523
- }
6524
- @default {
6525
- <app-vertical-layout></app-vertical-layout>
6526
- }
6527
- }
6497
+ ], template: `
6498
+ <app-notification-container></app-notification-container>
6499
+ <amf-modal-host></amf-modal-host>
6500
+ <amf-dialog-host></amf-dialog-host>
6501
+ <amf-drawer-host></amf-drawer-host>
6502
+ @switch (config.currentLayout()) {
6503
+ @case (LayoutType.VERTICAL) {
6504
+ <app-vertical-layout></app-vertical-layout>
6505
+ }
6506
+ @case (LayoutType.HORIZONTAL) {
6507
+ <app-horizontal-layout></app-horizontal-layout>
6508
+ }
6509
+ @case (LayoutType.EMPTY) {
6510
+ <app-empty-layout></app-empty-layout>
6511
+ }
6512
+ @case (LayoutType.CENTERED) {
6513
+ <app-centered-layout></app-centered-layout>
6514
+ }
6515
+ @case (LayoutType.TWO_COLUMN) {
6516
+ <app-two-column-layout></app-two-column-layout>
6517
+ }
6518
+ @case (LayoutType.DASHBOARD_GRID) {
6519
+ <app-dashboard-grid-layout></app-dashboard-grid-layout>
6520
+ }
6521
+ @case (LayoutType.COMPACT) {
6522
+ <app-compact-layout></app-compact-layout>
6523
+ }
6524
+ @default {
6525
+ <app-vertical-layout></app-vertical-layout>
6526
+ }
6527
+ }
6528
6528
  `, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}\n"] }]
6529
6529
  }] });
6530
6530