@frame-kit/ui-ng 0.1.6 → 0.1.7

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.
@@ -1,11 +1,14 @@
1
+ import { NgTemplateOutlet } from '@angular/common';
1
2
  import * as i0 from '@angular/core';
2
3
  import { input, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
3
- import { IconComponent } from '@frame-kit/ui-ng/core/icon';
4
4
 
5
5
  class TimelineComponent {
6
6
  // ===== INPUTS =====
7
7
  /** Array of timeline item data objects rendered in order. */
8
8
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
9
+ /** Optional template rendering each item's marker icon (the app owns the icon
10
+ * system). Receives the item as `$implicit`; render it from `item.icon`. */
11
+ iconTemplate = input(undefined, ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
9
12
  /** Direction the timeline runs — vertical stacks items top-to-bottom, horizontal left-to-right. */
10
13
  orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
11
14
  /** Alignment of the item content relative to the connector line. */
@@ -51,12 +54,12 @@ class TimelineComponent {
51
54
  return this.id();
52
55
  }
53
56
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
54
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TimelineComponent, isStandalone: true, selector: "fk-timeline", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, reverse: { classPropertyName: "reverse", publicName: "reverse", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass", "attr.role": "this.hostRole", "attr.aria-label": "this.hostAriaLabel", "attr.aria-orientation": "this.hostAriaOrientation", "attr.id": "this.hostId" } }, ngImport: i0, template: "@for (item of orderedItems(); track item.id ?? $index; let last = $last) {\n <div\n class=\"fk-timeline__item\"\n [class.fk-timeline__item--active]=\"item.status === 'active'\"\n [class.fk-timeline__item--completed]=\"item.status === 'completed'\"\n [class.fk-timeline__item--error]=\"item.status === 'error'\"\n [class.fk-timeline__item--warning]=\"item.status === 'warning'\"\n role=\"listitem\"\n >\n <div class=\"fk-timeline__separator\">\n <div class=\"fk-timeline__marker\">\n @if (item.icon) {\n <fk-icon [name]=\"item.icon\" size=\"xs\" />\n }\n </div>\n\n @if (!last) {\n <div class=\"fk-timeline__connector\"></div>\n }\n </div>\n\n <div class=\"fk-timeline__content\">\n @if (item.title) {\n <span class=\"fk-timeline__title\">{{ item.title }}</span>\n }\n\n @if (item.description) {\n <span class=\"fk-timeline__description\">{{ item.description }}</span>\n }\n\n @if (item.timestamp) {\n <span class=\"fk-timeline__timestamp\">{{ item.timestamp }}</span>\n }\n </div>\n </div>\n}\n\n<ng-content />\n", styles: [":host{display:flex;gap:var(--fk-timeline-gap, 0)}:host.fk-timeline--vertical{flex-direction:column}:host.fk-timeline--horizontal{flex-direction:row;overflow-x:auto}.fk-timeline__item{display:flex;position:relative}.fk-timeline__separator{display:flex;flex-shrink:0;align-items:flex-start}.fk-timeline__marker{display:flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:50%;background:var(--fk-timeline-marker-bg, var(--fk-color-surface, #ffffff));border:var(--fk-timeline-marker-border-width, 2px) solid var(--fk-timeline-marker-border-color, var(--fk-color-border, #d9e2ee));color:var(--fk-timeline-marker-color, var(--fk-color-muted, #8a98a8));overflow:hidden;z-index:1}.fk-timeline__connector{background:var(--fk-timeline-connector-color, var(--fk-color-border, #d9e2ee));flex-shrink:0}.fk-timeline__content{display:flex;flex-direction:column;gap:var(--fk-timeline-content-gap, var(--fk-rhythm-1, .25rem));min-width:0}.fk-timeline__title{font-size:var(--fk-timeline-title-font-size, var(--fk-typography-body-font-size, .9375rem));font-weight:var(--fk-timeline-title-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-timeline-title-color, var(--fk-color-text, #1f2d3d))}.fk-timeline__description{font-size:var(--fk-timeline-description-font-size, var(--fk-typography-small-font-size, .8125rem));color:var(--fk-timeline-description-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__timestamp{font-size:var(--fk-timeline-timestamp-font-size, var(--fk-typography-caption-font-size, .6875rem));color:var(--fk-timeline-timestamp-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__item--active .fk-timeline__marker{background:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));border-color:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--completed .fk-timeline__marker{background:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));border-color:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--error .fk-timeline__marker{background:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));border-color:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--warning .fk-timeline__marker{background:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));border-color:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));color:var(--fk-color-surface, #ffffff)}:host.fk-timeline--vertical .fk-timeline__item{flex-direction:row;align-items:stretch}:host.fk-timeline--vertical .fk-timeline__separator{flex-direction:column;align-items:center;flex-shrink:0}:host.fk-timeline--vertical .fk-timeline__connector{width:var(--fk-timeline-connector-width, 2px);flex:1;min-height:var(--fk-rhythm-2, .5rem)}:host.fk-timeline--vertical .fk-timeline__content{padding-bottom:var(--fk-timeline-item-gap, var(--fk-rhythm-3, .75rem))}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__content{padding-left:var(--fk-rhythm-2, .5rem);padding-top:0}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.125rem}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.25rem}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__item{flex-direction:row-reverse}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__content{padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item{display:grid;grid-template-columns:1fr auto 1fr}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__separator{grid-column:2}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(odd) .fk-timeline__content{grid-column:3;padding-left:var(--fk-rhythm-3, .75rem);padding-right:0;text-align:left}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__content{grid-column:1;grid-row:1;padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__separator{grid-row:1}:host.fk-timeline--horizontal .fk-timeline__item{display:flex;flex-direction:column;align-items:center;flex:1 1 0;min-width:0}:host.fk-timeline--horizontal .fk-timeline__item:last-child{flex:0 0 auto}:host.fk-timeline--horizontal .fk-timeline__separator{flex-direction:row;align-items:center;width:100%}:host.fk-timeline--horizontal .fk-timeline__connector{height:var(--fk-timeline-connector-width, 2px);flex:1;min-width:var(--fk-rhythm-3, .75rem)}:host.fk-timeline--horizontal .fk-timeline__content{align-items:center;text-align:center;padding-top:var(--fk-rhythm-2, .5rem);max-width:8rem}:host.fk-timeline--horizontal.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--horizontal.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--horizontal.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}@media(prefers-reduced-motion:reduce){.fk-timeline__connector,.fk-timeline__marker{transition:none}}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "fk-icon", inputs: ["name", "size", "color", "className", "id", "ariaLabel", "ariaHidden"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
57
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TimelineComponent, isStandalone: true, selector: "fk-timeline", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, reverse: { classPropertyName: "reverse", publicName: "reverse", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass", "attr.role": "this.hostRole", "attr.aria-label": "this.hostAriaLabel", "attr.aria-orientation": "this.hostAriaOrientation", "attr.id": "this.hostId" } }, ngImport: i0, template: "@for (item of orderedItems(); track item.id ?? $index; let last = $last) {\n <div\n class=\"fk-timeline__item\"\n [class.fk-timeline__item--active]=\"item.status === 'active'\"\n [class.fk-timeline__item--completed]=\"item.status === 'completed'\"\n [class.fk-timeline__item--error]=\"item.status === 'error'\"\n [class.fk-timeline__item--warning]=\"item.status === 'warning'\"\n role=\"listitem\"\n >\n <div class=\"fk-timeline__separator\">\n <div class=\"fk-timeline__marker\">\n @if (item.icon && iconTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n }\n </div>\n\n @if (!last) {\n <div class=\"fk-timeline__connector\"></div>\n }\n </div>\n\n <div class=\"fk-timeline__content\">\n @if (item.title) {\n <span class=\"fk-timeline__title\">{{ item.title }}</span>\n }\n\n @if (item.description) {\n <span class=\"fk-timeline__description\">{{ item.description }}</span>\n }\n\n @if (item.timestamp) {\n <span class=\"fk-timeline__timestamp\">{{ item.timestamp }}</span>\n }\n </div>\n </div>\n}\n\n<ng-content />\n", styles: [":host{display:flex;gap:var(--fk-timeline-gap, 0)}:host.fk-timeline--vertical{flex-direction:column}:host.fk-timeline--horizontal{flex-direction:row;overflow-x:auto}.fk-timeline__item{display:flex;position:relative}.fk-timeline__separator{display:flex;flex-shrink:0;align-items:flex-start}.fk-timeline__marker{display:flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:50%;background:var(--fk-timeline-marker-bg, var(--fk-color-surface, #ffffff));border:var(--fk-timeline-marker-border-width, 2px) solid var(--fk-timeline-marker-border-color, var(--fk-color-border, #d9e2ee));color:var(--fk-timeline-marker-color, var(--fk-color-muted, #8a98a8));overflow:hidden;z-index:1}.fk-timeline__connector{background:var(--fk-timeline-connector-color, var(--fk-color-border, #d9e2ee));flex-shrink:0}.fk-timeline__content{display:flex;flex-direction:column;gap:var(--fk-timeline-content-gap, var(--fk-rhythm-1, .25rem));min-width:0}.fk-timeline__title{font-size:var(--fk-timeline-title-font-size, var(--fk-typography-body-font-size, .9375rem));font-weight:var(--fk-timeline-title-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-timeline-title-color, var(--fk-color-text, #1f2d3d))}.fk-timeline__description{font-size:var(--fk-timeline-description-font-size, var(--fk-typography-small-font-size, .8125rem));color:var(--fk-timeline-description-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__timestamp{font-size:var(--fk-timeline-timestamp-font-size, var(--fk-typography-caption-font-size, .6875rem));color:var(--fk-timeline-timestamp-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__item--active .fk-timeline__marker{background:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));border-color:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--completed .fk-timeline__marker{background:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));border-color:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--error .fk-timeline__marker{background:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));border-color:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--warning .fk-timeline__marker{background:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));border-color:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));color:var(--fk-color-surface, #ffffff)}:host.fk-timeline--vertical .fk-timeline__item{flex-direction:row;align-items:stretch}:host.fk-timeline--vertical .fk-timeline__separator{flex-direction:column;align-items:center;flex-shrink:0}:host.fk-timeline--vertical .fk-timeline__connector{width:var(--fk-timeline-connector-width, 2px);flex:1;min-height:var(--fk-rhythm-2, .5rem)}:host.fk-timeline--vertical .fk-timeline__content{padding-bottom:var(--fk-timeline-item-gap, var(--fk-rhythm-3, .75rem))}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__content{padding-left:var(--fk-rhythm-2, .5rem);padding-top:0}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.125rem}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.25rem}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__item{flex-direction:row-reverse}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__content{padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item{display:grid;grid-template-columns:1fr auto 1fr}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__separator{grid-column:2}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(odd) .fk-timeline__content{grid-column:3;padding-left:var(--fk-rhythm-3, .75rem);padding-right:0;text-align:left}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__content{grid-column:1;grid-row:1;padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__separator{grid-row:1}:host.fk-timeline--horizontal .fk-timeline__item{display:flex;flex-direction:column;align-items:center;flex:1 1 0;min-width:0}:host.fk-timeline--horizontal .fk-timeline__item:last-child{flex:0 0 auto}:host.fk-timeline--horizontal .fk-timeline__separator{flex-direction:row;align-items:center;width:100%}:host.fk-timeline--horizontal .fk-timeline__connector{height:var(--fk-timeline-connector-width, 2px);flex:1;min-width:var(--fk-rhythm-3, .75rem)}:host.fk-timeline--horizontal .fk-timeline__content{align-items:center;text-align:center;padding-top:var(--fk-rhythm-2, .5rem);max-width:8rem}:host.fk-timeline--horizontal.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--horizontal.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--horizontal.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}@media(prefers-reduced-motion:reduce){.fk-timeline__connector,.fk-timeline__marker{transition:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
55
58
  }
56
59
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TimelineComponent, decorators: [{
57
60
  type: Component,
58
- args: [{ selector: 'fk-timeline', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (item of orderedItems(); track item.id ?? $index; let last = $last) {\n <div\n class=\"fk-timeline__item\"\n [class.fk-timeline__item--active]=\"item.status === 'active'\"\n [class.fk-timeline__item--completed]=\"item.status === 'completed'\"\n [class.fk-timeline__item--error]=\"item.status === 'error'\"\n [class.fk-timeline__item--warning]=\"item.status === 'warning'\"\n role=\"listitem\"\n >\n <div class=\"fk-timeline__separator\">\n <div class=\"fk-timeline__marker\">\n @if (item.icon) {\n <fk-icon [name]=\"item.icon\" size=\"xs\" />\n }\n </div>\n\n @if (!last) {\n <div class=\"fk-timeline__connector\"></div>\n }\n </div>\n\n <div class=\"fk-timeline__content\">\n @if (item.title) {\n <span class=\"fk-timeline__title\">{{ item.title }}</span>\n }\n\n @if (item.description) {\n <span class=\"fk-timeline__description\">{{ item.description }}</span>\n }\n\n @if (item.timestamp) {\n <span class=\"fk-timeline__timestamp\">{{ item.timestamp }}</span>\n }\n </div>\n </div>\n}\n\n<ng-content />\n", styles: [":host{display:flex;gap:var(--fk-timeline-gap, 0)}:host.fk-timeline--vertical{flex-direction:column}:host.fk-timeline--horizontal{flex-direction:row;overflow-x:auto}.fk-timeline__item{display:flex;position:relative}.fk-timeline__separator{display:flex;flex-shrink:0;align-items:flex-start}.fk-timeline__marker{display:flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:50%;background:var(--fk-timeline-marker-bg, var(--fk-color-surface, #ffffff));border:var(--fk-timeline-marker-border-width, 2px) solid var(--fk-timeline-marker-border-color, var(--fk-color-border, #d9e2ee));color:var(--fk-timeline-marker-color, var(--fk-color-muted, #8a98a8));overflow:hidden;z-index:1}.fk-timeline__connector{background:var(--fk-timeline-connector-color, var(--fk-color-border, #d9e2ee));flex-shrink:0}.fk-timeline__content{display:flex;flex-direction:column;gap:var(--fk-timeline-content-gap, var(--fk-rhythm-1, .25rem));min-width:0}.fk-timeline__title{font-size:var(--fk-timeline-title-font-size, var(--fk-typography-body-font-size, .9375rem));font-weight:var(--fk-timeline-title-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-timeline-title-color, var(--fk-color-text, #1f2d3d))}.fk-timeline__description{font-size:var(--fk-timeline-description-font-size, var(--fk-typography-small-font-size, .8125rem));color:var(--fk-timeline-description-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__timestamp{font-size:var(--fk-timeline-timestamp-font-size, var(--fk-typography-caption-font-size, .6875rem));color:var(--fk-timeline-timestamp-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__item--active .fk-timeline__marker{background:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));border-color:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--completed .fk-timeline__marker{background:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));border-color:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--error .fk-timeline__marker{background:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));border-color:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--warning .fk-timeline__marker{background:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));border-color:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));color:var(--fk-color-surface, #ffffff)}:host.fk-timeline--vertical .fk-timeline__item{flex-direction:row;align-items:stretch}:host.fk-timeline--vertical .fk-timeline__separator{flex-direction:column;align-items:center;flex-shrink:0}:host.fk-timeline--vertical .fk-timeline__connector{width:var(--fk-timeline-connector-width, 2px);flex:1;min-height:var(--fk-rhythm-2, .5rem)}:host.fk-timeline--vertical .fk-timeline__content{padding-bottom:var(--fk-timeline-item-gap, var(--fk-rhythm-3, .75rem))}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__content{padding-left:var(--fk-rhythm-2, .5rem);padding-top:0}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.125rem}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.25rem}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__item{flex-direction:row-reverse}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__content{padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item{display:grid;grid-template-columns:1fr auto 1fr}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__separator{grid-column:2}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(odd) .fk-timeline__content{grid-column:3;padding-left:var(--fk-rhythm-3, .75rem);padding-right:0;text-align:left}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__content{grid-column:1;grid-row:1;padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__separator{grid-row:1}:host.fk-timeline--horizontal .fk-timeline__item{display:flex;flex-direction:column;align-items:center;flex:1 1 0;min-width:0}:host.fk-timeline--horizontal .fk-timeline__item:last-child{flex:0 0 auto}:host.fk-timeline--horizontal .fk-timeline__separator{flex-direction:row;align-items:center;width:100%}:host.fk-timeline--horizontal .fk-timeline__connector{height:var(--fk-timeline-connector-width, 2px);flex:1;min-width:var(--fk-rhythm-3, .75rem)}:host.fk-timeline--horizontal .fk-timeline__content{align-items:center;text-align:center;padding-top:var(--fk-rhythm-2, .5rem);max-width:8rem}:host.fk-timeline--horizontal.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--horizontal.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--horizontal.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}@media(prefers-reduced-motion:reduce){.fk-timeline__connector,.fk-timeline__marker{transition:none}}\n"] }]
59
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], reverse: [{ type: i0.Input, args: [{ isSignal: true, alias: "reverse", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], hostClass: [{
61
+ args: [{ selector: 'fk-timeline', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (item of orderedItems(); track item.id ?? $index; let last = $last) {\n <div\n class=\"fk-timeline__item\"\n [class.fk-timeline__item--active]=\"item.status === 'active'\"\n [class.fk-timeline__item--completed]=\"item.status === 'completed'\"\n [class.fk-timeline__item--error]=\"item.status === 'error'\"\n [class.fk-timeline__item--warning]=\"item.status === 'warning'\"\n role=\"listitem\"\n >\n <div class=\"fk-timeline__separator\">\n <div class=\"fk-timeline__marker\">\n @if (item.icon && iconTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n }\n </div>\n\n @if (!last) {\n <div class=\"fk-timeline__connector\"></div>\n }\n </div>\n\n <div class=\"fk-timeline__content\">\n @if (item.title) {\n <span class=\"fk-timeline__title\">{{ item.title }}</span>\n }\n\n @if (item.description) {\n <span class=\"fk-timeline__description\">{{ item.description }}</span>\n }\n\n @if (item.timestamp) {\n <span class=\"fk-timeline__timestamp\">{{ item.timestamp }}</span>\n }\n </div>\n </div>\n}\n\n<ng-content />\n", styles: [":host{display:flex;gap:var(--fk-timeline-gap, 0)}:host.fk-timeline--vertical{flex-direction:column}:host.fk-timeline--horizontal{flex-direction:row;overflow-x:auto}.fk-timeline__item{display:flex;position:relative}.fk-timeline__separator{display:flex;flex-shrink:0;align-items:flex-start}.fk-timeline__marker{display:flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:50%;background:var(--fk-timeline-marker-bg, var(--fk-color-surface, #ffffff));border:var(--fk-timeline-marker-border-width, 2px) solid var(--fk-timeline-marker-border-color, var(--fk-color-border, #d9e2ee));color:var(--fk-timeline-marker-color, var(--fk-color-muted, #8a98a8));overflow:hidden;z-index:1}.fk-timeline__connector{background:var(--fk-timeline-connector-color, var(--fk-color-border, #d9e2ee));flex-shrink:0}.fk-timeline__content{display:flex;flex-direction:column;gap:var(--fk-timeline-content-gap, var(--fk-rhythm-1, .25rem));min-width:0}.fk-timeline__title{font-size:var(--fk-timeline-title-font-size, var(--fk-typography-body-font-size, .9375rem));font-weight:var(--fk-timeline-title-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-timeline-title-color, var(--fk-color-text, #1f2d3d))}.fk-timeline__description{font-size:var(--fk-timeline-description-font-size, var(--fk-typography-small-font-size, .8125rem));color:var(--fk-timeline-description-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__timestamp{font-size:var(--fk-timeline-timestamp-font-size, var(--fk-typography-caption-font-size, .6875rem));color:var(--fk-timeline-timestamp-color, var(--fk-color-muted, #8a98a8))}.fk-timeline__item--active .fk-timeline__marker{background:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));border-color:var(--fk-timeline-marker-active, var(--fk-color-primary, #0a84ff));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--completed .fk-timeline__marker{background:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));border-color:var(--fk-timeline-marker-completed, var(--fk-color-success, #10b981));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--error .fk-timeline__marker{background:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));border-color:var(--fk-timeline-marker-error, var(--fk-color-danger, #e02424));color:var(--fk-color-surface, #ffffff)}.fk-timeline__item--warning .fk-timeline__marker{background:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));border-color:var(--fk-timeline-marker-warning, var(--fk-color-warning, #f59e0b));color:var(--fk-color-surface, #ffffff)}:host.fk-timeline--vertical .fk-timeline__item{flex-direction:row;align-items:stretch}:host.fk-timeline--vertical .fk-timeline__separator{flex-direction:column;align-items:center;flex-shrink:0}:host.fk-timeline--vertical .fk-timeline__connector{width:var(--fk-timeline-connector-width, 2px);flex:1;min-height:var(--fk-rhythm-2, .5rem)}:host.fk-timeline--vertical .fk-timeline__content{padding-bottom:var(--fk-timeline-item-gap, var(--fk-rhythm-3, .75rem))}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--vertical.fk-timeline--sm .fk-timeline__content{padding-left:var(--fk-rhythm-2, .5rem);padding-top:0}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--vertical.fk-timeline--md .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.125rem}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}:host.fk-timeline--vertical.fk-timeline--lg .fk-timeline__content{padding-left:var(--fk-rhythm-3, .75rem);padding-top:.25rem}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__item{flex-direction:row-reverse}:host.fk-timeline--vertical.fk-timeline--end .fk-timeline__content{padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item{display:grid;grid-template-columns:1fr auto 1fr}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__separator{grid-column:2}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(odd) .fk-timeline__content{grid-column:3;padding-left:var(--fk-rhythm-3, .75rem);padding-right:0;text-align:left}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__content{grid-column:1;grid-row:1;padding-left:0;padding-right:var(--fk-rhythm-3, .75rem);text-align:right}:host.fk-timeline--vertical.fk-timeline--alternate .fk-timeline__item:nth-child(2n) .fk-timeline__separator{grid-row:1}:host.fk-timeline--horizontal .fk-timeline__item{display:flex;flex-direction:column;align-items:center;flex:1 1 0;min-width:0}:host.fk-timeline--horizontal .fk-timeline__item:last-child{flex:0 0 auto}:host.fk-timeline--horizontal .fk-timeline__separator{flex-direction:row;align-items:center;width:100%}:host.fk-timeline--horizontal .fk-timeline__connector{height:var(--fk-timeline-connector-width, 2px);flex:1;min-width:var(--fk-rhythm-3, .75rem)}:host.fk-timeline--horizontal .fk-timeline__content{align-items:center;text-align:center;padding-top:var(--fk-rhythm-2, .5rem);max-width:8rem}:host.fk-timeline--horizontal.fk-timeline--sm .fk-timeline__marker{width:var(--fk-timeline-marker-size-sm, 1rem);height:var(--fk-timeline-marker-size-sm, 1rem)}:host.fk-timeline--horizontal.fk-timeline--md .fk-timeline__marker{width:var(--fk-timeline-marker-size-md, 1.5rem);height:var(--fk-timeline-marker-size-md, 1.5rem)}:host.fk-timeline--horizontal.fk-timeline--lg .fk-timeline__marker{width:var(--fk-timeline-marker-size-lg, 2rem);height:var(--fk-timeline-marker-size-lg, 2rem)}@media(prefers-reduced-motion:reduce){.fk-timeline__connector,.fk-timeline__marker{transition:none}}\n"] }]
62
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], reverse: [{ type: i0.Input, args: [{ isSignal: true, alias: "reverse", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], hostClass: [{
60
63
  type: HostBinding,
61
64
  args: ['class']
62
65
  }], hostRole: [{
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-ui-timeline.mjs","sources":["../../../../packages/ui-ng/ui/timeline/timeline.component.ts","../../../../packages/ui-ng/ui/timeline/timeline.component.html","../../../../packages/ui-ng/ui/timeline/frame-kit-ui-ng-ui-timeline.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport type {\n TimelineAlign,\n TimelineItemData,\n TimelineOrientation,\n TimelineSize,\n} from './timeline.types';\n\n@Component({\n selector: 'fk-timeline',\n standalone: true,\n imports: [IconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './timeline.component.html',\n styleUrl: './timeline.component.scss',\n})\nexport class TimelineComponent {\n // ===== INPUTS =====\n /** Array of timeline item data objects rendered in order. */\n readonly items = input<TimelineItemData[]>([]);\n /** Direction the timeline runs — vertical stacks items top-to-bottom, horizontal left-to-right. */\n readonly orientation = input<TimelineOrientation>('vertical');\n /** Alignment of the item content relative to the connector line. */\n readonly align = input<TimelineAlign>('start');\n /** Size variant controlling the dot and spacing of each item. */\n readonly size = input<TimelineSize>('md');\n /** When true, the items array is rendered in reverse order. */\n readonly reverse = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly ariaLabel = input<string | null>(null);\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly orderedItems = computed(() => {\n const list = this.items();\n\n return this.reverse() ? [...list].reverse() : list;\n });\n\n readonly classes = computed(() => {\n return [\n 'fk-timeline',\n `fk-timeline--${this.orientation()}`,\n `fk-timeline--${this.align()}`,\n `fk-timeline--${this.size()}`,\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n // ===== HOST BINDINGS =====\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.role')\n get hostRole() {\n return 'list';\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel() {\n return this.ariaLabel();\n }\n\n @HostBinding('attr.aria-orientation')\n get hostAriaOrientation() {\n return this.orientation();\n }\n\n @HostBinding('attr.id')\n get hostId() {\n return this.id();\n }\n}\n","@for (item of orderedItems(); track item.id ?? $index; let last = $last) {\n <div\n class=\"fk-timeline__item\"\n [class.fk-timeline__item--active]=\"item.status === 'active'\"\n [class.fk-timeline__item--completed]=\"item.status === 'completed'\"\n [class.fk-timeline__item--error]=\"item.status === 'error'\"\n [class.fk-timeline__item--warning]=\"item.status === 'warning'\"\n role=\"listitem\"\n >\n <div class=\"fk-timeline__separator\">\n <div class=\"fk-timeline__marker\">\n @if (item.icon) {\n <fk-icon [name]=\"item.icon\" size=\"xs\" />\n }\n </div>\n\n @if (!last) {\n <div class=\"fk-timeline__connector\"></div>\n }\n </div>\n\n <div class=\"fk-timeline__content\">\n @if (item.title) {\n <span class=\"fk-timeline__title\">{{ item.title }}</span>\n }\n\n @if (item.description) {\n <span class=\"fk-timeline__description\">{{ item.description }}</span>\n }\n\n @if (item.timestamp) {\n <span class=\"fk-timeline__timestamp\">{{ item.timestamp }}</span>\n }\n </div>\n </div>\n}\n\n<ng-content />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frame-kit-ui-ng-ui-timeline.mjs","sources":["../../../../packages/ui-ng/ui/timeline/timeline.component.ts","../../../../packages/ui-ng/ui/timeline/timeline.component.html","../../../../packages/ui-ng/ui/timeline/frame-kit-ui-ng-ui-timeline.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n TemplateRef,\n} from '@angular/core';\n\nimport type {\n TimelineAlign,\n TimelineItemData,\n TimelineOrientation,\n TimelineSize,\n} from './timeline.types';\n\n@Component({\n selector: 'fk-timeline',\n standalone: true,\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './timeline.component.html',\n styleUrl: './timeline.component.scss',\n})\nexport class TimelineComponent {\n // ===== INPUTS =====\n /** Array of timeline item data objects rendered in order. */\n readonly items = input<TimelineItemData[]>([]);\n /** Optional template rendering each item's marker icon (the app owns the icon\n * system). Receives the item as `$implicit`; render it from `item.icon`. */\n readonly iconTemplate = input<\n TemplateRef<{ $implicit: TimelineItemData }> | undefined\n >(undefined);\n /** Direction the timeline runs — vertical stacks items top-to-bottom, horizontal left-to-right. */\n readonly orientation = input<TimelineOrientation>('vertical');\n /** Alignment of the item content relative to the connector line. */\n readonly align = input<TimelineAlign>('start');\n /** Size variant controlling the dot and spacing of each item. */\n readonly size = input<TimelineSize>('md');\n /** When true, the items array is rendered in reverse order. */\n readonly reverse = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly ariaLabel = input<string | null>(null);\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly orderedItems = computed(() => {\n const list = this.items();\n\n return this.reverse() ? [...list].reverse() : list;\n });\n\n readonly classes = computed(() => {\n return [\n 'fk-timeline',\n `fk-timeline--${this.orientation()}`,\n `fk-timeline--${this.align()}`,\n `fk-timeline--${this.size()}`,\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n // ===== HOST BINDINGS =====\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.role')\n get hostRole() {\n return 'list';\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel() {\n return this.ariaLabel();\n }\n\n @HostBinding('attr.aria-orientation')\n get hostAriaOrientation() {\n return this.orientation();\n }\n\n @HostBinding('attr.id')\n get hostId() {\n return this.id();\n }\n}\n","@for (item of orderedItems(); track item.id ?? $index; let last = $last) {\n <div\n class=\"fk-timeline__item\"\n [class.fk-timeline__item--active]=\"item.status === 'active'\"\n [class.fk-timeline__item--completed]=\"item.status === 'completed'\"\n [class.fk-timeline__item--error]=\"item.status === 'error'\"\n [class.fk-timeline__item--warning]=\"item.status === 'warning'\"\n role=\"listitem\"\n >\n <div class=\"fk-timeline__separator\">\n <div class=\"fk-timeline__marker\">\n @if (item.icon && iconTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n }\n </div>\n\n @if (!last) {\n <div class=\"fk-timeline__connector\"></div>\n }\n </div>\n\n <div class=\"fk-timeline__content\">\n @if (item.title) {\n <span class=\"fk-timeline__title\">{{ item.title }}</span>\n }\n\n @if (item.description) {\n <span class=\"fk-timeline__description\">{{ item.description }}</span>\n }\n\n @if (item.timestamp) {\n <span class=\"fk-timeline__timestamp\">{{ item.timestamp }}</span>\n }\n </div>\n </div>\n}\n\n<ng-content />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
+ import { NgTemplateOutlet } from '@angular/common';
1
2
  import * as i0 from '@angular/core';
2
3
  import { input, output, viewChild, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
3
4
  import { AvatarComponent } from '@frame-kit/ui-ng/ui/avatar';
4
5
  import { DropdownMenuComponent, DropdownTriggerDirective, DropdownPanelDirective } from '@frame-kit/ui-ng/ui/dropdown-menu';
5
- import { MenuItemComponent, MenuSeparatorComponent } from '@frame-kit/ui-ng/ui/menu-item';
6
+ import { MenuItemComponent, MenuSeparatorComponent, FkMenuItemIconDirective } from '@frame-kit/ui-ng/ui/menu-item';
6
7
 
7
8
  class UserMenuComponent {
8
9
  // ===== IDENTITY =====
@@ -24,6 +25,12 @@ class UserMenuComponent {
24
25
  // ===== MENU =====
25
26
  /** Array of menu item configurations rendered in the dropdown. */
26
27
  menuItems = input([], ...(ngDevMode ? [{ debugName: "menuItems" }] : /* istanbul ignore next */ []));
28
+ /**
29
+ * Optional template used to render each item's leading icon (the app owns the
30
+ * icon system). Receives the `MenuItem` as `$implicit`; render the icon from
31
+ * `item.icon`. When omitted, items render without an icon.
32
+ */
33
+ iconTemplate = input(null, ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
27
34
  /** Preferred placement of the dropdown panel relative to the trigger. */
28
35
  placement = input('bottom-end', ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
29
36
  // ===== DISPLAY =====
@@ -115,19 +122,21 @@ class UserMenuComponent {
115
122
  this.dropdownRef()?.toggle();
116
123
  }
117
124
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UserMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
118
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: UserMenuComponent, isStandalone: true, selector: "fk-user-menu", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: false, transformFunction: null }, avatarUrl: { classPropertyName: "avatarUrl", publicName: "avatarUrl", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, userId: { classPropertyName: "userId", publicName: "userId", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, showStatus: { classPropertyName: "showStatus", publicName: "showStatus", isSignal: true, isRequired: false, transformFunction: null }, menuItems: { classPropertyName: "menuItems", publicName: "menuItems", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, showName: { classPropertyName: "showName", publicName: "showName", isSignal: true, isRequired: false, transformFunction: null }, showEmail: { classPropertyName: "showEmail", publicName: "showEmail", isSignal: true, isRequired: false, transformFunction: null }, showChevron: { classPropertyName: "showChevron", publicName: "showChevron", isSignal: true, isRequired: false, transformFunction: null }, infoPlacement: { classPropertyName: "infoPlacement", publicName: "infoPlacement", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { avatarClick: "avatarClick", menuOpen: "menuOpen", menuClose: "menuClose", menuItemClick: "menuItemClick", logoutClick: "logoutClick" }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: DropdownMenuComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<fk-dropdown-menu\n [placement]=\"placement()\"\n [disabled]=\"disabled() || loading()\"\n [ariaLabel]=\"'Menu for ' + name()\"\n (menuOpen)=\"onMenuOpen()\"\n (menuClose)=\"onMenuClose()\"\n>\n <!-- Trigger button -->\n <button\n fkDropdownTrigger\n class=\"fk-user-menu__trigger\"\n type=\"button\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel() ?? 'User menu for ' + name()\"\n >\n <!-- Avatar -->\n <fk-avatar\n [name]=\"name()\"\n [avatarUrl]=\"avatarUrl()\"\n [initials]=\"initials()\"\n [size]=\"size()\"\n [status]=\"status()\"\n [showStatus]=\"showStatus()\"\n />\n\n <!-- Name & email block -->\n @if (showName() || showEmail()) {\n <span class=\"fk-user-menu__info\">\n @if (showName()) {\n <span class=\"fk-user-menu__name\">{{ name() }}</span>\n }\n @if (showEmail() && email()) {\n <span class=\"fk-user-menu__email\">{{ email() }}</span>\n }\n </span>\n }\n\n <!-- Badge -->\n @if (badge()) {\n <span class=\"fk-user-menu__badge\">{{ badge() }}</span>\n }\n\n <!-- Chevron -->\n @if (showChevron()) {\n <span\n class=\"fk-user-menu__chevron\"\n [class.fk-user-menu__chevron--open]=\"isOpen()\"\n aria-hidden=\"true\"\n >\n <svg\n class=\"fk-user-menu__chevron-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 18 18\"\n >\n <path\n d=\"M4.5 6.75L9 11.25L13.5 6.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n }\n </button>\n\n <!-- Panel content -->\n <ng-template fkDropdownPanel>\n <!-- User header inside panel (popover variant) -->\n @if (variant() === 'popover') {\n <div class=\"fk-user-menu__panel-header\">\n <span class=\"fk-user-menu__panel-name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"fk-user-menu__panel-email\">{{ email() }}</span>\n }\n </div>\n }\n\n <!-- Menu items -->\n @for (item of menuItems(); track item.value) {\n @if (item.separator) {\n <fk-menu-separator />\n } @else {\n <fk-menu-item\n [icon]=\"item.icon ?? null\"\n [danger]=\"item.danger ?? false\"\n [disabled]=\"item.disabled ?? false\"\n (itemClick)=\"selectItem(item)\"\n >\n {{ item.label }}\n </fk-menu-item>\n }\n }\n </ng-template>\n</fk-dropdown-menu>\n", styles: [":host{display:inline-block;position:relative;--fk-dropdown-menu-panel-z: var(--fk-user-menu-panel-z, 100);--fk-dropdown-menu-panel-min-width: var( --fk-user-menu-panel-min-width, 12rem );--fk-dropdown-menu-panel-padding: var( --fk-user-menu-panel-padding, var(--fk-rhythm-1, .25rem) );--fk-dropdown-menu-panel-radius: var( --fk-user-menu-panel-radius, var(--fk-radius-lg, .75rem) );--fk-dropdown-menu-panel-bg: var( --fk-user-menu-panel-bg, var(--fk-color-surface, #ffffff) );--fk-dropdown-menu-panel-border: var( --fk-user-menu-panel-border, var(--fk-color-border, #d9e2ee) );--fk-dropdown-menu-panel-shadow: var( --fk-user-menu-panel-shadow, 0 4px 16px rgba(0, 0, 0, .08), 0 1px 4px rgba(0, 0, 0, .04) );--fk-menu-item-gap: var(--fk-user-menu-item-gap, var(--fk-rhythm-2, .5rem));--fk-menu-item-padding: var( --fk-user-menu-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) );--fk-menu-item-radius: var( --fk-user-menu-item-radius, var(--fk-radius-md, .375rem) );--fk-menu-item-font-family: var( --fk-user-menu-item-font-family, var(--fk-font-family-base) );--fk-menu-item-font-size: var(--fk-user-menu-item-font-size, .875rem);--fk-menu-item-color: var( --fk-user-menu-item-color, var(--fk-color-text, #1f2d3d) );--fk-menu-item-bg-hover: var( --fk-user-menu-item-bg-hover, var(--fk-color-surface-muted, #f7f9fb) );--fk-menu-item-danger-color: var( --fk-user-menu-item-danger-color, var(--fk-color-danger, #e02424) );--fk-menu-item-danger-bg-hover: var( --fk-user-menu-item-danger-bg-hover, #fef2f2 );--fk-menu-item-focus-ring: var( --fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)) );--fk-menu-separator-color: var( --fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee) )}.fk-user-menu__trigger{display:inline-flex;align-items:center;gap:var(--fk-user-menu-trigger-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-user-menu-trigger-padding, var(--fk-rhythm-1, .25rem));border:none;border-radius:var(--fk-user-menu-trigger-radius, var(--fk-radius-md, .375rem));background:var(--fk-user-menu-trigger-bg, transparent);cursor:pointer;transition:background-color .15s ease}.fk-user-menu__trigger:hover{background-color:var(--fk-user-menu-trigger-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}.fk-user-menu__trigger:focus-visible{outline:none;box-shadow:var(--fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-user-menu__trigger:disabled{opacity:var(--fk-user-menu-opacity-disabled, .6);cursor:not-allowed}.fk-user-menu__info{display:flex;flex-direction:column;align-items:flex-start;text-align:left;line-height:1.3}.fk-user-menu__name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8))}.fk-user-menu__badge{display:inline-flex;align-items:center;padding:.125rem .5rem;border-radius:var(--fk-user-menu-badge-radius, var(--fk-radius-full, 9999px));background-color:var(--fk-user-menu-badge-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-user-menu-badge-color, var(--fk-color-surface, #ffffff));font-family:var(--fk-user-menu-badge-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-badge-font-size, .625rem);font-weight:var(--fk-user-menu-badge-font-weight, var(--fk-font-weight-semibold, 600));text-transform:uppercase;letter-spacing:.04em;line-height:1.4}.fk-user-menu__chevron{display:inline-flex;color:var(--fk-user-menu-chevron-color, var(--fk-color-muted, #8a98a8));transition:transform .15s ease}.fk-user-menu__chevron--open{transform:rotate(180deg)}.fk-user-menu__chevron-svg{display:block}.fk-user-menu__panel-header{display:flex;flex-direction:column;padding:var(--fk-rhythm-3, .75rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-2, .5rem);border-bottom:1px solid var(--fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee));margin-bottom:var(--fk-rhythm-1, .25rem)}.fk-user-menu__panel-name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__panel-email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8));margin-top:.125rem}:host.fk-user-menu--info-start .fk-user-menu__info{order:-1;align-items:flex-end;text-align:right}:host.fk-user-menu--disabled{pointer-events:none}\n"], dependencies: [{ kind: "component", type: AvatarComponent, selector: "fk-avatar", inputs: ["name", "avatarUrl", "initials", "status", "showStatus", "size", "className", "id", "ariaLabel"] }, { kind: "component", type: DropdownMenuComponent, selector: "fk-dropdown-menu", inputs: ["placement", "disabled", "portal", "panelClass", "ariaLabel", "className", "id"], outputs: ["menuOpen", "menuClose"] }, { kind: "directive", type: DropdownTriggerDirective, selector: "[fkDropdownTrigger]" }, { kind: "directive", type: DropdownPanelDirective, selector: "[fkDropdownPanel]" }, { kind: "component", type: MenuItemComponent, selector: "fk-menu-item", inputs: ["icon", "danger", "disabled"], outputs: ["itemClick"] }, { kind: "component", type: MenuSeparatorComponent, selector: "fk-menu-separator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: UserMenuComponent, isStandalone: true, selector: "fk-user-menu", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: false, transformFunction: null }, avatarUrl: { classPropertyName: "avatarUrl", publicName: "avatarUrl", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, userId: { classPropertyName: "userId", publicName: "userId", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, showStatus: { classPropertyName: "showStatus", publicName: "showStatus", isSignal: true, isRequired: false, transformFunction: null }, menuItems: { classPropertyName: "menuItems", publicName: "menuItems", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, showName: { classPropertyName: "showName", publicName: "showName", isSignal: true, isRequired: false, transformFunction: null }, showEmail: { classPropertyName: "showEmail", publicName: "showEmail", isSignal: true, isRequired: false, transformFunction: null }, showChevron: { classPropertyName: "showChevron", publicName: "showChevron", isSignal: true, isRequired: false, transformFunction: null }, infoPlacement: { classPropertyName: "infoPlacement", publicName: "infoPlacement", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { avatarClick: "avatarClick", menuOpen: "menuOpen", menuClose: "menuClose", menuItemClick: "menuItemClick", logoutClick: "logoutClick" }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: DropdownMenuComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<fk-dropdown-menu\n [placement]=\"placement()\"\n [disabled]=\"disabled() || loading()\"\n [ariaLabel]=\"'Menu for ' + name()\"\n (menuOpen)=\"onMenuOpen()\"\n (menuClose)=\"onMenuClose()\"\n>\n <!-- Trigger button -->\n <button\n fkDropdownTrigger\n class=\"fk-user-menu__trigger\"\n type=\"button\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel() ?? 'User menu for ' + name()\"\n >\n <!-- Avatar -->\n <fk-avatar\n [name]=\"name()\"\n [avatarUrl]=\"avatarUrl()\"\n [initials]=\"initials()\"\n [size]=\"size()\"\n [status]=\"status()\"\n [showStatus]=\"showStatus()\"\n />\n\n <!-- Name & email block -->\n @if (showName() || showEmail()) {\n <span class=\"fk-user-menu__info\">\n @if (showName()) {\n <span class=\"fk-user-menu__name\">{{ name() }}</span>\n }\n @if (showEmail() && email()) {\n <span class=\"fk-user-menu__email\">{{ email() }}</span>\n }\n </span>\n }\n\n <!-- Badge -->\n @if (badge()) {\n <span class=\"fk-user-menu__badge\">{{ badge() }}</span>\n }\n\n <!-- Chevron -->\n @if (showChevron()) {\n <span\n class=\"fk-user-menu__chevron\"\n [class.fk-user-menu__chevron--open]=\"isOpen()\"\n aria-hidden=\"true\"\n >\n <svg\n class=\"fk-user-menu__chevron-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 18 18\"\n >\n <path\n d=\"M4.5 6.75L9 11.25L13.5 6.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n }\n </button>\n\n <!-- Panel content -->\n <ng-template fkDropdownPanel>\n <!-- User header inside panel (popover variant) -->\n @if (variant() === 'popover') {\n <div class=\"fk-user-menu__panel-header\">\n <span class=\"fk-user-menu__panel-name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"fk-user-menu__panel-email\">{{ email() }}</span>\n }\n </div>\n }\n\n <!-- Menu items -->\n @for (item of menuItems(); track item.value) {\n @if (item.separator) {\n <fk-menu-separator />\n } @else {\n <fk-menu-item\n [danger]=\"item.danger ?? false\"\n [disabled]=\"item.disabled ?? false\"\n (itemClick)=\"selectItem(item)\"\n >\n @if (item.icon && iconTemplate(); as tpl) {\n <span fkMenuItemIcon>\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n </span>\n }\n {{ item.label }}\n </fk-menu-item>\n }\n }\n </ng-template>\n</fk-dropdown-menu>\n", styles: [":host{display:inline-block;position:relative;--fk-dropdown-menu-panel-z: var(--fk-user-menu-panel-z, 100);--fk-dropdown-menu-panel-min-width: var( --fk-user-menu-panel-min-width, 12rem );--fk-dropdown-menu-panel-padding: var( --fk-user-menu-panel-padding, var(--fk-rhythm-1, .25rem) );--fk-dropdown-menu-panel-radius: var( --fk-user-menu-panel-radius, var(--fk-radius-lg, .75rem) );--fk-dropdown-menu-panel-bg: var( --fk-user-menu-panel-bg, var(--fk-color-surface, #ffffff) );--fk-dropdown-menu-panel-border: var( --fk-user-menu-panel-border, var(--fk-color-border, #d9e2ee) );--fk-dropdown-menu-panel-shadow: var( --fk-user-menu-panel-shadow, 0 4px 16px rgba(0, 0, 0, .08), 0 1px 4px rgba(0, 0, 0, .04) );--fk-menu-item-gap: var(--fk-user-menu-item-gap, var(--fk-rhythm-2, .5rem));--fk-menu-item-padding: var( --fk-user-menu-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) );--fk-menu-item-radius: var( --fk-user-menu-item-radius, var(--fk-radius-md, .375rem) );--fk-menu-item-font-family: var( --fk-user-menu-item-font-family, var(--fk-font-family-base) );--fk-menu-item-font-size: var(--fk-user-menu-item-font-size, .875rem);--fk-menu-item-color: var( --fk-user-menu-item-color, var(--fk-color-text, #1f2d3d) );--fk-menu-item-bg-hover: var( --fk-user-menu-item-bg-hover, var(--fk-color-surface-muted, #f7f9fb) );--fk-menu-item-danger-color: var( --fk-user-menu-item-danger-color, var(--fk-color-danger, #e02424) );--fk-menu-item-danger-bg-hover: var( --fk-user-menu-item-danger-bg-hover, #fef2f2 );--fk-menu-item-focus-ring: var( --fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)) );--fk-menu-separator-color: var( --fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee) )}.fk-user-menu__trigger{display:inline-flex;align-items:center;gap:var(--fk-user-menu-trigger-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-user-menu-trigger-padding, var(--fk-rhythm-1, .25rem));border:none;border-radius:var(--fk-user-menu-trigger-radius, var(--fk-radius-md, .375rem));background:var(--fk-user-menu-trigger-bg, transparent);cursor:pointer;transition:background-color .15s ease}.fk-user-menu__trigger:hover{background-color:var(--fk-user-menu-trigger-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}.fk-user-menu__trigger:focus-visible{outline:none;box-shadow:var(--fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-user-menu__trigger:disabled{opacity:var(--fk-user-menu-opacity-disabled, .6);cursor:not-allowed}.fk-user-menu__info{display:flex;flex-direction:column;align-items:flex-start;text-align:left;line-height:1.3}.fk-user-menu__name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8))}.fk-user-menu__badge{display:inline-flex;align-items:center;padding:.125rem .5rem;border-radius:var(--fk-user-menu-badge-radius, var(--fk-radius-full, 9999px));background-color:var(--fk-user-menu-badge-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-user-menu-badge-color, var(--fk-color-surface, #ffffff));font-family:var(--fk-user-menu-badge-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-badge-font-size, .625rem);font-weight:var(--fk-user-menu-badge-font-weight, var(--fk-font-weight-semibold, 600));text-transform:uppercase;letter-spacing:.04em;line-height:1.4}.fk-user-menu__chevron{display:inline-flex;color:var(--fk-user-menu-chevron-color, var(--fk-color-muted, #8a98a8));transition:transform .15s ease}.fk-user-menu__chevron--open{transform:rotate(180deg)}.fk-user-menu__chevron-svg{display:block}.fk-user-menu__panel-header{display:flex;flex-direction:column;padding:var(--fk-rhythm-3, .75rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-2, .5rem);border-bottom:1px solid var(--fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee));margin-bottom:var(--fk-rhythm-1, .25rem)}.fk-user-menu__panel-name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__panel-email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8));margin-top:.125rem}:host.fk-user-menu--info-start .fk-user-menu__info{order:-1;align-items:flex-end;text-align:right}:host.fk-user-menu--disabled{pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: AvatarComponent, selector: "fk-avatar", inputs: ["name", "avatarUrl", "initials", "status", "showStatus", "size", "className", "id", "ariaLabel"] }, { kind: "component", type: DropdownMenuComponent, selector: "fk-dropdown-menu", inputs: ["placement", "disabled", "portal", "panelClass", "ariaLabel", "className", "id"], outputs: ["menuOpen", "menuClose"] }, { kind: "directive", type: DropdownTriggerDirective, selector: "[fkDropdownTrigger]" }, { kind: "directive", type: DropdownPanelDirective, selector: "[fkDropdownPanel]" }, { kind: "component", type: MenuItemComponent, selector: "fk-menu-item", inputs: ["danger", "disabled"], outputs: ["itemClick"] }, { kind: "component", type: MenuSeparatorComponent, selector: "fk-menu-separator" }, { kind: "directive", type: FkMenuItemIconDirective, selector: "[fkMenuItemIcon]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
119
126
  }
120
127
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UserMenuComponent, decorators: [{
121
128
  type: Component,
122
129
  args: [{ selector: 'fk-user-menu', standalone: true, imports: [
130
+ NgTemplateOutlet,
123
131
  AvatarComponent,
124
132
  DropdownMenuComponent,
125
133
  DropdownTriggerDirective,
126
134
  DropdownPanelDirective,
127
135
  MenuItemComponent,
128
136
  MenuSeparatorComponent,
129
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fk-dropdown-menu\n [placement]=\"placement()\"\n [disabled]=\"disabled() || loading()\"\n [ariaLabel]=\"'Menu for ' + name()\"\n (menuOpen)=\"onMenuOpen()\"\n (menuClose)=\"onMenuClose()\"\n>\n <!-- Trigger button -->\n <button\n fkDropdownTrigger\n class=\"fk-user-menu__trigger\"\n type=\"button\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel() ?? 'User menu for ' + name()\"\n >\n <!-- Avatar -->\n <fk-avatar\n [name]=\"name()\"\n [avatarUrl]=\"avatarUrl()\"\n [initials]=\"initials()\"\n [size]=\"size()\"\n [status]=\"status()\"\n [showStatus]=\"showStatus()\"\n />\n\n <!-- Name & email block -->\n @if (showName() || showEmail()) {\n <span class=\"fk-user-menu__info\">\n @if (showName()) {\n <span class=\"fk-user-menu__name\">{{ name() }}</span>\n }\n @if (showEmail() && email()) {\n <span class=\"fk-user-menu__email\">{{ email() }}</span>\n }\n </span>\n }\n\n <!-- Badge -->\n @if (badge()) {\n <span class=\"fk-user-menu__badge\">{{ badge() }}</span>\n }\n\n <!-- Chevron -->\n @if (showChevron()) {\n <span\n class=\"fk-user-menu__chevron\"\n [class.fk-user-menu__chevron--open]=\"isOpen()\"\n aria-hidden=\"true\"\n >\n <svg\n class=\"fk-user-menu__chevron-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 18 18\"\n >\n <path\n d=\"M4.5 6.75L9 11.25L13.5 6.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n }\n </button>\n\n <!-- Panel content -->\n <ng-template fkDropdownPanel>\n <!-- User header inside panel (popover variant) -->\n @if (variant() === 'popover') {\n <div class=\"fk-user-menu__panel-header\">\n <span class=\"fk-user-menu__panel-name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"fk-user-menu__panel-email\">{{ email() }}</span>\n }\n </div>\n }\n\n <!-- Menu items -->\n @for (item of menuItems(); track item.value) {\n @if (item.separator) {\n <fk-menu-separator />\n } @else {\n <fk-menu-item\n [icon]=\"item.icon ?? null\"\n [danger]=\"item.danger ?? false\"\n [disabled]=\"item.disabled ?? false\"\n (itemClick)=\"selectItem(item)\"\n >\n {{ item.label }}\n </fk-menu-item>\n }\n }\n </ng-template>\n</fk-dropdown-menu>\n", styles: [":host{display:inline-block;position:relative;--fk-dropdown-menu-panel-z: var(--fk-user-menu-panel-z, 100);--fk-dropdown-menu-panel-min-width: var( --fk-user-menu-panel-min-width, 12rem );--fk-dropdown-menu-panel-padding: var( --fk-user-menu-panel-padding, var(--fk-rhythm-1, .25rem) );--fk-dropdown-menu-panel-radius: var( --fk-user-menu-panel-radius, var(--fk-radius-lg, .75rem) );--fk-dropdown-menu-panel-bg: var( --fk-user-menu-panel-bg, var(--fk-color-surface, #ffffff) );--fk-dropdown-menu-panel-border: var( --fk-user-menu-panel-border, var(--fk-color-border, #d9e2ee) );--fk-dropdown-menu-panel-shadow: var( --fk-user-menu-panel-shadow, 0 4px 16px rgba(0, 0, 0, .08), 0 1px 4px rgba(0, 0, 0, .04) );--fk-menu-item-gap: var(--fk-user-menu-item-gap, var(--fk-rhythm-2, .5rem));--fk-menu-item-padding: var( --fk-user-menu-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) );--fk-menu-item-radius: var( --fk-user-menu-item-radius, var(--fk-radius-md, .375rem) );--fk-menu-item-font-family: var( --fk-user-menu-item-font-family, var(--fk-font-family-base) );--fk-menu-item-font-size: var(--fk-user-menu-item-font-size, .875rem);--fk-menu-item-color: var( --fk-user-menu-item-color, var(--fk-color-text, #1f2d3d) );--fk-menu-item-bg-hover: var( --fk-user-menu-item-bg-hover, var(--fk-color-surface-muted, #f7f9fb) );--fk-menu-item-danger-color: var( --fk-user-menu-item-danger-color, var(--fk-color-danger, #e02424) );--fk-menu-item-danger-bg-hover: var( --fk-user-menu-item-danger-bg-hover, #fef2f2 );--fk-menu-item-focus-ring: var( --fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)) );--fk-menu-separator-color: var( --fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee) )}.fk-user-menu__trigger{display:inline-flex;align-items:center;gap:var(--fk-user-menu-trigger-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-user-menu-trigger-padding, var(--fk-rhythm-1, .25rem));border:none;border-radius:var(--fk-user-menu-trigger-radius, var(--fk-radius-md, .375rem));background:var(--fk-user-menu-trigger-bg, transparent);cursor:pointer;transition:background-color .15s ease}.fk-user-menu__trigger:hover{background-color:var(--fk-user-menu-trigger-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}.fk-user-menu__trigger:focus-visible{outline:none;box-shadow:var(--fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-user-menu__trigger:disabled{opacity:var(--fk-user-menu-opacity-disabled, .6);cursor:not-allowed}.fk-user-menu__info{display:flex;flex-direction:column;align-items:flex-start;text-align:left;line-height:1.3}.fk-user-menu__name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8))}.fk-user-menu__badge{display:inline-flex;align-items:center;padding:.125rem .5rem;border-radius:var(--fk-user-menu-badge-radius, var(--fk-radius-full, 9999px));background-color:var(--fk-user-menu-badge-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-user-menu-badge-color, var(--fk-color-surface, #ffffff));font-family:var(--fk-user-menu-badge-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-badge-font-size, .625rem);font-weight:var(--fk-user-menu-badge-font-weight, var(--fk-font-weight-semibold, 600));text-transform:uppercase;letter-spacing:.04em;line-height:1.4}.fk-user-menu__chevron{display:inline-flex;color:var(--fk-user-menu-chevron-color, var(--fk-color-muted, #8a98a8));transition:transform .15s ease}.fk-user-menu__chevron--open{transform:rotate(180deg)}.fk-user-menu__chevron-svg{display:block}.fk-user-menu__panel-header{display:flex;flex-direction:column;padding:var(--fk-rhythm-3, .75rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-2, .5rem);border-bottom:1px solid var(--fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee));margin-bottom:var(--fk-rhythm-1, .25rem)}.fk-user-menu__panel-name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__panel-email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8));margin-top:.125rem}:host.fk-user-menu--info-start .fk-user-menu__info{order:-1;align-items:flex-end;text-align:right}:host.fk-user-menu--disabled{pointer-events:none}\n"] }]
130
- }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], email: [{ type: i0.Input, args: [{ isSignal: true, alias: "email", required: false }] }], avatarUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarUrl", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], userId: [{ type: i0.Input, args: [{ isSignal: true, alias: "userId", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], showStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStatus", required: false }] }], menuItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuItems", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], showName: [{ type: i0.Input, args: [{ isSignal: true, alias: "showName", required: false }] }], showEmail: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmail", required: false }] }], showChevron: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChevron", required: false }] }], infoPlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "infoPlacement", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], avatarClick: [{ type: i0.Output, args: ["avatarClick"] }], menuOpen: [{ type: i0.Output, args: ["menuOpen"] }], menuClose: [{ type: i0.Output, args: ["menuClose"] }], menuItemClick: [{ type: i0.Output, args: ["menuItemClick"] }], logoutClick: [{ type: i0.Output, args: ["logoutClick"] }], dropdownRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DropdownMenuComponent), { isSignal: true }] }], hostClass: [{
137
+ FkMenuItemIconDirective,
138
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fk-dropdown-menu\n [placement]=\"placement()\"\n [disabled]=\"disabled() || loading()\"\n [ariaLabel]=\"'Menu for ' + name()\"\n (menuOpen)=\"onMenuOpen()\"\n (menuClose)=\"onMenuClose()\"\n>\n <!-- Trigger button -->\n <button\n fkDropdownTrigger\n class=\"fk-user-menu__trigger\"\n type=\"button\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel() ?? 'User menu for ' + name()\"\n >\n <!-- Avatar -->\n <fk-avatar\n [name]=\"name()\"\n [avatarUrl]=\"avatarUrl()\"\n [initials]=\"initials()\"\n [size]=\"size()\"\n [status]=\"status()\"\n [showStatus]=\"showStatus()\"\n />\n\n <!-- Name & email block -->\n @if (showName() || showEmail()) {\n <span class=\"fk-user-menu__info\">\n @if (showName()) {\n <span class=\"fk-user-menu__name\">{{ name() }}</span>\n }\n @if (showEmail() && email()) {\n <span class=\"fk-user-menu__email\">{{ email() }}</span>\n }\n </span>\n }\n\n <!-- Badge -->\n @if (badge()) {\n <span class=\"fk-user-menu__badge\">{{ badge() }}</span>\n }\n\n <!-- Chevron -->\n @if (showChevron()) {\n <span\n class=\"fk-user-menu__chevron\"\n [class.fk-user-menu__chevron--open]=\"isOpen()\"\n aria-hidden=\"true\"\n >\n <svg\n class=\"fk-user-menu__chevron-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 18 18\"\n >\n <path\n d=\"M4.5 6.75L9 11.25L13.5 6.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n }\n </button>\n\n <!-- Panel content -->\n <ng-template fkDropdownPanel>\n <!-- User header inside panel (popover variant) -->\n @if (variant() === 'popover') {\n <div class=\"fk-user-menu__panel-header\">\n <span class=\"fk-user-menu__panel-name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"fk-user-menu__panel-email\">{{ email() }}</span>\n }\n </div>\n }\n\n <!-- Menu items -->\n @for (item of menuItems(); track item.value) {\n @if (item.separator) {\n <fk-menu-separator />\n } @else {\n <fk-menu-item\n [danger]=\"item.danger ?? false\"\n [disabled]=\"item.disabled ?? false\"\n (itemClick)=\"selectItem(item)\"\n >\n @if (item.icon && iconTemplate(); as tpl) {\n <span fkMenuItemIcon>\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n </span>\n }\n {{ item.label }}\n </fk-menu-item>\n }\n }\n </ng-template>\n</fk-dropdown-menu>\n", styles: [":host{display:inline-block;position:relative;--fk-dropdown-menu-panel-z: var(--fk-user-menu-panel-z, 100);--fk-dropdown-menu-panel-min-width: var( --fk-user-menu-panel-min-width, 12rem );--fk-dropdown-menu-panel-padding: var( --fk-user-menu-panel-padding, var(--fk-rhythm-1, .25rem) );--fk-dropdown-menu-panel-radius: var( --fk-user-menu-panel-radius, var(--fk-radius-lg, .75rem) );--fk-dropdown-menu-panel-bg: var( --fk-user-menu-panel-bg, var(--fk-color-surface, #ffffff) );--fk-dropdown-menu-panel-border: var( --fk-user-menu-panel-border, var(--fk-color-border, #d9e2ee) );--fk-dropdown-menu-panel-shadow: var( --fk-user-menu-panel-shadow, 0 4px 16px rgba(0, 0, 0, .08), 0 1px 4px rgba(0, 0, 0, .04) );--fk-menu-item-gap: var(--fk-user-menu-item-gap, var(--fk-rhythm-2, .5rem));--fk-menu-item-padding: var( --fk-user-menu-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) );--fk-menu-item-radius: var( --fk-user-menu-item-radius, var(--fk-radius-md, .375rem) );--fk-menu-item-font-family: var( --fk-user-menu-item-font-family, var(--fk-font-family-base) );--fk-menu-item-font-size: var(--fk-user-menu-item-font-size, .875rem);--fk-menu-item-color: var( --fk-user-menu-item-color, var(--fk-color-text, #1f2d3d) );--fk-menu-item-bg-hover: var( --fk-user-menu-item-bg-hover, var(--fk-color-surface-muted, #f7f9fb) );--fk-menu-item-danger-color: var( --fk-user-menu-item-danger-color, var(--fk-color-danger, #e02424) );--fk-menu-item-danger-bg-hover: var( --fk-user-menu-item-danger-bg-hover, #fef2f2 );--fk-menu-item-focus-ring: var( --fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)) );--fk-menu-separator-color: var( --fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee) )}.fk-user-menu__trigger{display:inline-flex;align-items:center;gap:var(--fk-user-menu-trigger-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-user-menu-trigger-padding, var(--fk-rhythm-1, .25rem));border:none;border-radius:var(--fk-user-menu-trigger-radius, var(--fk-radius-md, .375rem));background:var(--fk-user-menu-trigger-bg, transparent);cursor:pointer;transition:background-color .15s ease}.fk-user-menu__trigger:hover{background-color:var(--fk-user-menu-trigger-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}.fk-user-menu__trigger:focus-visible{outline:none;box-shadow:var(--fk-user-menu-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-user-menu__trigger:disabled{opacity:var(--fk-user-menu-opacity-disabled, .6);cursor:not-allowed}.fk-user-menu__info{display:flex;flex-direction:column;align-items:flex-start;text-align:left;line-height:1.3}.fk-user-menu__name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8))}.fk-user-menu__badge{display:inline-flex;align-items:center;padding:.125rem .5rem;border-radius:var(--fk-user-menu-badge-radius, var(--fk-radius-full, 9999px));background-color:var(--fk-user-menu-badge-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-user-menu-badge-color, var(--fk-color-surface, #ffffff));font-family:var(--fk-user-menu-badge-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-badge-font-size, .625rem);font-weight:var(--fk-user-menu-badge-font-weight, var(--fk-font-weight-semibold, 600));text-transform:uppercase;letter-spacing:.04em;line-height:1.4}.fk-user-menu__chevron{display:inline-flex;color:var(--fk-user-menu-chevron-color, var(--fk-color-muted, #8a98a8));transition:transform .15s ease}.fk-user-menu__chevron--open{transform:rotate(180deg)}.fk-user-menu__chevron-svg{display:block}.fk-user-menu__panel-header{display:flex;flex-direction:column;padding:var(--fk-rhythm-3, .75rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-2, .5rem);border-bottom:1px solid var(--fk-user-menu-separator-color, var(--fk-color-border, #d9e2ee));margin-bottom:var(--fk-rhythm-1, .25rem)}.fk-user-menu__panel-name{font-family:var(--fk-user-menu-name-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-name-font-size, .875rem);font-weight:var(--fk-user-menu-name-font-weight, var(--fk-font-weight-semibold, 600));color:var(--fk-user-menu-name-color, var(--fk-color-text, #1f2d3d))}.fk-user-menu__panel-email{font-family:var(--fk-user-menu-email-font-family, var(--fk-font-family-base));font-size:var(--fk-user-menu-email-font-size, .75rem);color:var(--fk-user-menu-email-color, var(--fk-color-muted, #8a98a8));margin-top:.125rem}:host.fk-user-menu--info-start .fk-user-menu__info{order:-1;align-items:flex-end;text-align:right}:host.fk-user-menu--disabled{pointer-events:none}\n"] }]
139
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], email: [{ type: i0.Input, args: [{ isSignal: true, alias: "email", required: false }] }], avatarUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarUrl", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], userId: [{ type: i0.Input, args: [{ isSignal: true, alias: "userId", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], showStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStatus", required: false }] }], menuItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuItems", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], showName: [{ type: i0.Input, args: [{ isSignal: true, alias: "showName", required: false }] }], showEmail: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmail", required: false }] }], showChevron: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChevron", required: false }] }], infoPlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "infoPlacement", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], avatarClick: [{ type: i0.Output, args: ["avatarClick"] }], menuOpen: [{ type: i0.Output, args: ["menuOpen"] }], menuClose: [{ type: i0.Output, args: ["menuClose"] }], menuItemClick: [{ type: i0.Output, args: ["menuItemClick"] }], logoutClick: [{ type: i0.Output, args: ["logoutClick"] }], dropdownRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DropdownMenuComponent), { isSignal: true }] }], hostClass: [{
131
140
  type: HostBinding,
132
141
  args: ['class']
133
142
  }], hostId: [{
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-ui-user-menu.mjs","sources":["../../../../packages/ui-ng/ui/user-menu/user-menu.component.ts","../../../../packages/ui-ng/ui/user-menu/user-menu.component.html","../../../../packages/ui-ng/ui/user-menu/frame-kit-ui-ng-ui-user-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n output,\n viewChild,\n} from '@angular/core';\n\nimport { AvatarComponent } from '@frame-kit/ui-ng/ui/avatar';\nimport type { AvatarSize, AvatarStatus } from '@frame-kit/ui-ng/ui/avatar';\nimport { DropdownMenuComponent } from '@frame-kit/ui-ng/ui/dropdown-menu';\nimport { DropdownPanelDirective } from '@frame-kit/ui-ng/ui/dropdown-menu';\nimport { DropdownTriggerDirective } from '@frame-kit/ui-ng/ui/dropdown-menu';\nimport { MenuItemComponent } from '@frame-kit/ui-ng/ui/menu-item';\nimport { MenuSeparatorComponent } from '@frame-kit/ui-ng/ui/menu-item';\nimport type {\n InfoPlacement,\n MenuItem,\n MenuPlacement,\n UserMenuVariant,\n} from './user-menu.types';\n\n@Component({\n selector: 'fk-user-menu',\n standalone: true,\n imports: [\n AvatarComponent,\n DropdownMenuComponent,\n DropdownTriggerDirective,\n DropdownPanelDirective,\n MenuItemComponent,\n MenuSeparatorComponent,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './user-menu.component.html',\n styleUrl: './user-menu.component.scss',\n})\nexport class UserMenuComponent {\n // ===== IDENTITY =====\n /** Full display name of the user shown in the avatar and optional info section. */\n readonly name = input.required<string>();\n /** User's email address shown in the optional info section. */\n readonly email = input<string | null>(null);\n /** URL of the user's avatar image. */\n readonly avatarUrl = input<string | null>(null);\n /** Explicit two-character initials that override the name-derived fallback. */\n readonly initials = input<string | null>(null);\n /** Optional user ID displayed in the info section for debugging or display. */\n readonly userId = input<string | null>(null);\n\n // ===== STATUS =====\n /** Online/offline/away status reflected on the avatar indicator dot. */\n readonly status = input<AvatarStatus | null>(null);\n /** When true, renders the status indicator dot on the avatar. */\n readonly showStatus = input<boolean>(false);\n\n // ===== MENU =====\n /** Array of menu item configurations rendered in the dropdown. */\n readonly menuItems = input<MenuItem[]>([]);\n /** Preferred placement of the dropdown panel relative to the trigger. */\n readonly placement = input<MenuPlacement>('bottom-end');\n\n // ===== DISPLAY =====\n /** Size of the avatar trigger. */\n readonly size = input<AvatarSize>('md');\n /** Layout variant — \"dropdown\" renders a full avatar menu, \"compact\" renders a minimal trigger. */\n readonly variant = input<UserMenuVariant>('dropdown');\n /** When true, renders the user's display name next to the avatar. */\n readonly showName = input<boolean>(false);\n /** When true, renders the user's email next to the avatar. */\n readonly showEmail = input<boolean>(false);\n /** When true, renders a chevron indicator showing the menu is expandable. */\n readonly showChevron = input<boolean>(true);\n /** Side where the name/email info block appears relative to the avatar. */\n readonly infoPlacement = input<InfoPlacement>('end');\n /** Optional badge text overlaid on the avatar. */\n readonly badge = input<string | null>(null);\n /** When true, prevents the menu from opening. */\n readonly disabled = input<boolean>(false);\n /** When true, shows a loading state on the trigger. */\n readonly loading = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires when the user clicks the avatar trigger to open the menu. */\n readonly avatarClick = output<void>();\n /** Fires when the dropdown menu opens. */\n readonly menuOpen = output<void>();\n /** Fires when the dropdown menu closes. */\n readonly menuClose = output<void>();\n /** Fires when the user selects a menu item, emitting the selected `MenuItem`. */\n readonly menuItemClick = output<MenuItem>();\n /** Fires when the user selects the item with `value === \"logout\"`. */\n readonly logoutClick = output<void>();\n\n // ===== REFS =====\n readonly dropdownRef = viewChild(DropdownMenuComponent);\n\n // ===== COMPUTED =====\n\n readonly isOpen = computed(() => this.dropdownRef()?.isOpen() ?? false);\n\n readonly classes = computed(() => {\n return [\n 'fk-user-menu',\n `fk-user-menu--${this.size()}`,\n `fk-user-menu--${this.variant()}`,\n this.infoPlacement() === 'start' ? 'fk-user-menu--info-start' : '',\n this.isOpen() ? 'fk-user-menu--open' : '',\n this.disabled() ? 'fk-user-menu--disabled' : '',\n this.loading() ? 'fk-user-menu--loading' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n // ===== ACTIONS =====\n\n /** Emits `menuItemClick` (and `logoutClick` when applicable) for the given menu item. */\n selectItem(item: MenuItem): void {\n if (item.disabled) {\n return;\n }\n\n this.menuItemClick.emit(item);\n\n if (item.value === 'logout') {\n this.logoutClick.emit();\n }\n }\n\n onMenuOpen(): void {\n this.avatarClick.emit();\n this.menuOpen.emit();\n }\n\n onMenuClose(): void {\n this.menuClose.emit();\n }\n\n /** Opens the user-menu dropdown programmatically. */\n open(): void {\n this.dropdownRef()?.open();\n }\n\n /** Closes the user-menu dropdown programmatically. */\n close(): void {\n this.dropdownRef()?.close();\n }\n\n /** Toggles the user-menu dropdown programmatically. */\n toggle(): void {\n this.dropdownRef()?.toggle();\n }\n}\n","<fk-dropdown-menu\n [placement]=\"placement()\"\n [disabled]=\"disabled() || loading()\"\n [ariaLabel]=\"'Menu for ' + name()\"\n (menuOpen)=\"onMenuOpen()\"\n (menuClose)=\"onMenuClose()\"\n>\n <!-- Trigger button -->\n <button\n fkDropdownTrigger\n class=\"fk-user-menu__trigger\"\n type=\"button\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel() ?? 'User menu for ' + name()\"\n >\n <!-- Avatar -->\n <fk-avatar\n [name]=\"name()\"\n [avatarUrl]=\"avatarUrl()\"\n [initials]=\"initials()\"\n [size]=\"size()\"\n [status]=\"status()\"\n [showStatus]=\"showStatus()\"\n />\n\n <!-- Name & email block -->\n @if (showName() || showEmail()) {\n <span class=\"fk-user-menu__info\">\n @if (showName()) {\n <span class=\"fk-user-menu__name\">{{ name() }}</span>\n }\n @if (showEmail() && email()) {\n <span class=\"fk-user-menu__email\">{{ email() }}</span>\n }\n </span>\n }\n\n <!-- Badge -->\n @if (badge()) {\n <span class=\"fk-user-menu__badge\">{{ badge() }}</span>\n }\n\n <!-- Chevron -->\n @if (showChevron()) {\n <span\n class=\"fk-user-menu__chevron\"\n [class.fk-user-menu__chevron--open]=\"isOpen()\"\n aria-hidden=\"true\"\n >\n <svg\n class=\"fk-user-menu__chevron-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 18 18\"\n >\n <path\n d=\"M4.5 6.75L9 11.25L13.5 6.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n }\n </button>\n\n <!-- Panel content -->\n <ng-template fkDropdownPanel>\n <!-- User header inside panel (popover variant) -->\n @if (variant() === 'popover') {\n <div class=\"fk-user-menu__panel-header\">\n <span class=\"fk-user-menu__panel-name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"fk-user-menu__panel-email\">{{ email() }}</span>\n }\n </div>\n }\n\n <!-- Menu items -->\n @for (item of menuItems(); track item.value) {\n @if (item.separator) {\n <fk-menu-separator />\n } @else {\n <fk-menu-item\n [icon]=\"item.icon ?? null\"\n [danger]=\"item.danger ?? false\"\n [disabled]=\"item.disabled ?? false\"\n (itemClick)=\"selectItem(item)\"\n >\n {{ item.label }}\n </fk-menu-item>\n }\n }\n </ng-template>\n</fk-dropdown-menu>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frame-kit-ui-ng-ui-user-menu.mjs","sources":["../../../../packages/ui-ng/ui/user-menu/user-menu.component.ts","../../../../packages/ui-ng/ui/user-menu/user-menu.component.html","../../../../packages/ui-ng/ui/user-menu/frame-kit-ui-ng-ui-user-menu.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n output,\n TemplateRef,\n viewChild,\n} from '@angular/core';\n\nimport { AvatarComponent } from '@frame-kit/ui-ng/ui/avatar';\nimport type { AvatarSize, AvatarStatus } from '@frame-kit/ui-ng/ui/avatar';\nimport { DropdownMenuComponent } from '@frame-kit/ui-ng/ui/dropdown-menu';\nimport { DropdownPanelDirective } from '@frame-kit/ui-ng/ui/dropdown-menu';\nimport { DropdownTriggerDirective } from '@frame-kit/ui-ng/ui/dropdown-menu';\nimport { FkMenuItemIconDirective } from '@frame-kit/ui-ng/ui/menu-item';\nimport { MenuItemComponent } from '@frame-kit/ui-ng/ui/menu-item';\nimport { MenuSeparatorComponent } from '@frame-kit/ui-ng/ui/menu-item';\nimport type {\n InfoPlacement,\n MenuItem,\n MenuPlacement,\n UserMenuVariant,\n} from './user-menu.types';\n\n@Component({\n selector: 'fk-user-menu',\n standalone: true,\n imports: [\n NgTemplateOutlet,\n AvatarComponent,\n DropdownMenuComponent,\n DropdownTriggerDirective,\n DropdownPanelDirective,\n MenuItemComponent,\n MenuSeparatorComponent,\n FkMenuItemIconDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './user-menu.component.html',\n styleUrl: './user-menu.component.scss',\n})\nexport class UserMenuComponent {\n // ===== IDENTITY =====\n /** Full display name of the user shown in the avatar and optional info section. */\n readonly name = input.required<string>();\n /** User's email address shown in the optional info section. */\n readonly email = input<string | null>(null);\n /** URL of the user's avatar image. */\n readonly avatarUrl = input<string | null>(null);\n /** Explicit two-character initials that override the name-derived fallback. */\n readonly initials = input<string | null>(null);\n /** Optional user ID displayed in the info section for debugging or display. */\n readonly userId = input<string | null>(null);\n\n // ===== STATUS =====\n /** Online/offline/away status reflected on the avatar indicator dot. */\n readonly status = input<AvatarStatus | null>(null);\n /** When true, renders the status indicator dot on the avatar. */\n readonly showStatus = input<boolean>(false);\n\n // ===== MENU =====\n /** Array of menu item configurations rendered in the dropdown. */\n readonly menuItems = input<MenuItem[]>([]);\n /**\n * Optional template used to render each item's leading icon (the app owns the\n * icon system). Receives the `MenuItem` as `$implicit`; render the icon from\n * `item.icon`. When omitted, items render without an icon.\n */\n readonly iconTemplate = input<TemplateRef<{ $implicit: MenuItem }> | null>(\n null,\n );\n /** Preferred placement of the dropdown panel relative to the trigger. */\n readonly placement = input<MenuPlacement>('bottom-end');\n\n // ===== DISPLAY =====\n /** Size of the avatar trigger. */\n readonly size = input<AvatarSize>('md');\n /** Layout variant — \"dropdown\" renders a full avatar menu, \"compact\" renders a minimal trigger. */\n readonly variant = input<UserMenuVariant>('dropdown');\n /** When true, renders the user's display name next to the avatar. */\n readonly showName = input<boolean>(false);\n /** When true, renders the user's email next to the avatar. */\n readonly showEmail = input<boolean>(false);\n /** When true, renders a chevron indicator showing the menu is expandable. */\n readonly showChevron = input<boolean>(true);\n /** Side where the name/email info block appears relative to the avatar. */\n readonly infoPlacement = input<InfoPlacement>('end');\n /** Optional badge text overlaid on the avatar. */\n readonly badge = input<string | null>(null);\n /** When true, prevents the menu from opening. */\n readonly disabled = input<boolean>(false);\n /** When true, shows a loading state on the trigger. */\n readonly loading = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires when the user clicks the avatar trigger to open the menu. */\n readonly avatarClick = output<void>();\n /** Fires when the dropdown menu opens. */\n readonly menuOpen = output<void>();\n /** Fires when the dropdown menu closes. */\n readonly menuClose = output<void>();\n /** Fires when the user selects a menu item, emitting the selected `MenuItem`. */\n readonly menuItemClick = output<MenuItem>();\n /** Fires when the user selects the item with `value === \"logout\"`. */\n readonly logoutClick = output<void>();\n\n // ===== REFS =====\n readonly dropdownRef = viewChild(DropdownMenuComponent);\n\n // ===== COMPUTED =====\n\n readonly isOpen = computed(() => this.dropdownRef()?.isOpen() ?? false);\n\n readonly classes = computed(() => {\n return [\n 'fk-user-menu',\n `fk-user-menu--${this.size()}`,\n `fk-user-menu--${this.variant()}`,\n this.infoPlacement() === 'start' ? 'fk-user-menu--info-start' : '',\n this.isOpen() ? 'fk-user-menu--open' : '',\n this.disabled() ? 'fk-user-menu--disabled' : '',\n this.loading() ? 'fk-user-menu--loading' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n // ===== ACTIONS =====\n\n /** Emits `menuItemClick` (and `logoutClick` when applicable) for the given menu item. */\n selectItem(item: MenuItem): void {\n if (item.disabled) {\n return;\n }\n\n this.menuItemClick.emit(item);\n\n if (item.value === 'logout') {\n this.logoutClick.emit();\n }\n }\n\n onMenuOpen(): void {\n this.avatarClick.emit();\n this.menuOpen.emit();\n }\n\n onMenuClose(): void {\n this.menuClose.emit();\n }\n\n /** Opens the user-menu dropdown programmatically. */\n open(): void {\n this.dropdownRef()?.open();\n }\n\n /** Closes the user-menu dropdown programmatically. */\n close(): void {\n this.dropdownRef()?.close();\n }\n\n /** Toggles the user-menu dropdown programmatically. */\n toggle(): void {\n this.dropdownRef()?.toggle();\n }\n}\n","<fk-dropdown-menu\n [placement]=\"placement()\"\n [disabled]=\"disabled() || loading()\"\n [ariaLabel]=\"'Menu for ' + name()\"\n (menuOpen)=\"onMenuOpen()\"\n (menuClose)=\"onMenuClose()\"\n>\n <!-- Trigger button -->\n <button\n fkDropdownTrigger\n class=\"fk-user-menu__trigger\"\n type=\"button\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel() ?? 'User menu for ' + name()\"\n >\n <!-- Avatar -->\n <fk-avatar\n [name]=\"name()\"\n [avatarUrl]=\"avatarUrl()\"\n [initials]=\"initials()\"\n [size]=\"size()\"\n [status]=\"status()\"\n [showStatus]=\"showStatus()\"\n />\n\n <!-- Name & email block -->\n @if (showName() || showEmail()) {\n <span class=\"fk-user-menu__info\">\n @if (showName()) {\n <span class=\"fk-user-menu__name\">{{ name() }}</span>\n }\n @if (showEmail() && email()) {\n <span class=\"fk-user-menu__email\">{{ email() }}</span>\n }\n </span>\n }\n\n <!-- Badge -->\n @if (badge()) {\n <span class=\"fk-user-menu__badge\">{{ badge() }}</span>\n }\n\n <!-- Chevron -->\n @if (showChevron()) {\n <span\n class=\"fk-user-menu__chevron\"\n [class.fk-user-menu__chevron--open]=\"isOpen()\"\n aria-hidden=\"true\"\n >\n <svg\n class=\"fk-user-menu__chevron-svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 18 18\"\n >\n <path\n d=\"M4.5 6.75L9 11.25L13.5 6.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n }\n </button>\n\n <!-- Panel content -->\n <ng-template fkDropdownPanel>\n <!-- User header inside panel (popover variant) -->\n @if (variant() === 'popover') {\n <div class=\"fk-user-menu__panel-header\">\n <span class=\"fk-user-menu__panel-name\">{{ name() }}</span>\n @if (email()) {\n <span class=\"fk-user-menu__panel-email\">{{ email() }}</span>\n }\n </div>\n }\n\n <!-- Menu items -->\n @for (item of menuItems(); track item.value) {\n @if (item.separator) {\n <fk-menu-separator />\n } @else {\n <fk-menu-item\n [danger]=\"item.danger ?? false\"\n [disabled]=\"item.disabled ?? false\"\n (itemClick)=\"selectItem(item)\"\n >\n @if (item.icon && iconTemplate(); as tpl) {\n <span fkMenuItemIcon>\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n </span>\n }\n {{ item.label }}\n </fk-menu-item>\n }\n }\n </ng-template>\n</fk-dropdown-menu>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frame-kit/ui-ng",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Style-agnostic, token-driven Angular UI component library for FrameKit.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { InjectionToken, Type, OnInit, ElementRef, TemplateRef } from '@angular/core';
2
+ import { InjectionToken, TemplateRef, Type, OnInit, ElementRef } from '@angular/core';
3
3
  import { NgControl, AsyncValidatorFn, ValidatorFn, AbstractControl, FormArray, FormGroup, FormControl, ControlValueAccessor } from '@angular/forms';
4
4
  import { IconSize, IconColor } from '@frame-kit/ui-ng/core/icon';
5
5
 
@@ -425,6 +425,10 @@ declare class FieldArrayOutletComponent {
425
425
  readonly field: _angular_core.InputSignal<FieldSchema>;
426
426
  /** The FormArray backing the repeatable rows. */
427
427
  readonly formArray: _angular_core.InputSignal<FormArray<any>>;
428
+ /** Prefix-icon template threaded to each child field (the app owns the icon). */
429
+ readonly prefixIconTemplate: _angular_core.InputSignal<TemplateRef<{
430
+ $implicit: FieldSchema;
431
+ }> | undefined>;
428
432
  /** Whether the parent form has been submitted; propagated to each fk-field-outlet. */
429
433
  readonly submitted: _angular_core.InputSignal<boolean>;
430
434
  /** Fires with the index of the newly added row. */
@@ -445,7 +449,7 @@ declare class FieldArrayOutletComponent {
445
449
  /** Removes the row at the given index from the FormArray. */
446
450
  removeRow(index: number): void;
447
451
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldArrayOutletComponent, never>;
448
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldArrayOutletComponent, "fk-field-array-outlet", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "field": { "alias": "field"; "required": true; "isSignal": true; }; "formArray": { "alias": "formArray"; "required": true; "isSignal": true; }; "submitted": { "alias": "submitted"; "required": false; "isSignal": true; }; }, { "rowAdded": "rowAdded"; "rowRemoved": "rowRemoved"; }, never, never, true, never>;
452
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldArrayOutletComponent, "fk-field-array-outlet", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "field": { "alias": "field"; "required": true; "isSignal": true; }; "formArray": { "alias": "formArray"; "required": true; "isSignal": true; }; "prefixIconTemplate": { "alias": "prefixIconTemplate"; "required": false; "isSignal": true; }; "submitted": { "alias": "submitted"; "required": false; "isSignal": true; }; }, { "rowAdded": "rowAdded"; "rowRemoved": "rowRemoved"; }, never, never, true, never>;
449
453
  }
450
454
 
451
455
  /**
@@ -472,6 +476,12 @@ declare class FieldOutletComponent {
472
476
  readonly form: _angular_core.InputSignal<FormGroup<any>>;
473
477
  /** Whether the parent form has been submitted; propagated to fk-form-field. */
474
478
  readonly submitted: _angular_core.InputSignal<boolean>;
479
+ /** Optional template rendering a field's prefix icon (the app owns the icon
480
+ * system). Receives the field as `$implicit`; render it from
481
+ * `field.ui.prefixIcon`. */
482
+ readonly prefixIconTemplate: _angular_core.InputSignal<TemplateRef<{
483
+ $implicit: FieldSchema;
484
+ }> | undefined>;
475
485
  /** Whether this field is visible (for conditional visibility). */
476
486
  readonly visible: _angular_core.WritableSignal<boolean>;
477
487
  readonly classes: _angular_core.Signal<string>;
@@ -493,7 +503,7 @@ declare class FieldOutletComponent {
493
503
  private setupVisibility;
494
504
  private evaluateVisibility;
495
505
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldOutletComponent, never>;
496
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldOutletComponent, "fk-field-outlet", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "field": { "alias": "field"; "required": true; "isSignal": true; }; "form": { "alias": "form"; "required": true; "isSignal": true; }; "submitted": { "alias": "submitted"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
506
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldOutletComponent, "fk-field-outlet", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "field": { "alias": "field"; "required": true; "isSignal": true; }; "form": { "alias": "form"; "required": true; "isSignal": true; }; "submitted": { "alias": "submitted"; "required": false; "isSignal": true; }; "prefixIconTemplate": { "alias": "prefixIconTemplate"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
497
507
  }
498
508
 
499
509
  /**
@@ -529,6 +539,14 @@ declare class FormRendererComponent implements OnInit {
529
539
  * If not provided, one is auto-generated from the schema.
530
540
  */
531
541
  readonly form: _angular_core.InputSignal<FormGroup<any> | null>;
542
+ /**
543
+ * Optional template rendering a field's prefix icon (the app owns the icon
544
+ * system). Receives the field as `$implicit`; render it from
545
+ * `field.ui.prefixIcon`. Fields without a `prefixIcon` render no icon.
546
+ */
547
+ readonly prefixIconTemplate: _angular_core.InputSignal<TemplateRef<{
548
+ $implicit: FieldSchema;
549
+ }> | undefined>;
532
550
  /** Emits the FormGroup value when the form is submitted. */
533
551
  readonly formSubmit: _angular_core.OutputEmitterRef<Record<string, unknown>>;
534
552
  /** The resolved FormGroup (either provided or auto-generated). */
@@ -551,7 +569,7 @@ declare class FormRendererComponent implements OnInit {
551
569
  */
552
570
  focusFirstInvalidField(): void;
553
571
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FormRendererComponent, never>;
554
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FormRendererComponent, "fk-form-renderer", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "schema": { "alias": "schema"; "required": true; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; }, { "formSubmit": "formSubmit"; }, never, ["*"], true, never>;
572
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FormRendererComponent, "fk-form-renderer", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "schema": { "alias": "schema"; "required": true; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "prefixIconTemplate": { "alias": "prefixIconTemplate"; "required": false; "isSignal": true; }; }, { "formSubmit": "formSubmit"; }, never, ["*"], true, never>;
555
573
  }
556
574
 
557
575
  /**
@@ -593,12 +611,16 @@ declare class SectionOutletComponent {
593
611
  readonly form: _angular_core.InputSignal<FormGroup<any>>;
594
612
  /** Whether the parent form has been submitted; propagated to each fk-field-outlet. */
595
613
  readonly submitted: _angular_core.InputSignal<boolean>;
614
+ /** Prefix-icon template threaded to each field (the app owns the icon). */
615
+ readonly prefixIconTemplate: _angular_core.InputSignal<TemplateRef<{
616
+ $implicit: FieldSchema;
617
+ }> | undefined>;
596
618
  readonly classes: _angular_core.Signal<string>;
597
619
  get hostClass(): string;
598
620
  /** Looks up a field definition within this section by its key. */
599
621
  getField(key: string): FormSchemaSection['fields'][number] | undefined;
600
622
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SectionOutletComponent, never>;
601
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SectionOutletComponent, "fk-section-outlet", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "section": { "alias": "section"; "required": true; "isSignal": true; }; "form": { "alias": "form"; "required": true; "isSignal": true; }; "submitted": { "alias": "submitted"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
623
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SectionOutletComponent, "fk-section-outlet", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "section": { "alias": "section"; "required": true; "isSignal": true; }; "form": { "alias": "form"; "required": true; "isSignal": true; }; "submitted": { "alias": "submitted"; "required": false; "isSignal": true; }; "prefixIconTemplate": { "alias": "prefixIconTemplate"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
602
624
  }
603
625
 
604
626
  declare class FormSectionComponent {
@@ -1128,8 +1150,6 @@ declare class FileDropzoneComponent {
1128
1150
  readonly multiple: _angular_core.InputSignal<boolean>;
1129
1151
  /** When true, prevents drag-and-drop and click-to-browse interaction. */
1130
1152
  readonly disabled: _angular_core.InputSignal<boolean>;
1131
- /** Icon name rendered inside the dropzone surface. */
1132
- readonly icon: _angular_core.InputSignal<string>;
1133
1153
  /** Primary prompt text displayed inside the dropzone. */
1134
1154
  readonly prompt: _angular_core.InputSignal<string>;
1135
1155
  /** Secondary hint text shown below the prompt. */
@@ -1148,7 +1168,25 @@ declare class FileDropzoneComponent {
1148
1168
  onChange(event: Event): void;
1149
1169
  private emit;
1150
1170
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FileDropzoneComponent, never>;
1151
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FileDropzoneComponent, "fk-file-dropzone", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "prompt": { "alias": "prompt"; "required": true; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "filesSelected": "filesSelected"; }, never, never, true, never>;
1171
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FileDropzoneComponent, "fk-file-dropzone", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "prompt": { "alias": "prompt"; "required": true; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "filesSelected": "filesSelected"; }, never, ["[fkFileDropzoneIcon]"], true, never>;
1172
+ }
1173
+
1174
+ /** Injection token for the icon slot of `fk-file-dropzone`. */
1175
+ declare const FK_FILE_DROPZONE_ICON: InjectionToken<FkFileDropzoneIconDirective>;
1176
+ /**
1177
+ * Marks projected content as the icon of an `fk-file-dropzone`, overriding the
1178
+ * built-in upload glyph. Project any icon element (the app owns the icon
1179
+ * system):
1180
+ *
1181
+ * ```html
1182
+ * <fk-file-dropzone prompt="Drop a file">
1183
+ * <fk-icon fkFileDropzoneIcon name="file-content" size="lg" />
1184
+ * </fk-file-dropzone>
1185
+ * ```
1186
+ */
1187
+ declare class FkFileDropzoneIconDirective {
1188
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FkFileDropzoneIconDirective, never>;
1189
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FkFileDropzoneIconDirective, "[fkFileDropzoneIcon]", never, {}, {}, never, never, true, never>;
1152
1190
  }
1153
1191
 
1154
1192
  declare class FileUploadComponent implements ControlValueAccessor, FieldControl {
@@ -1670,5 +1708,5 @@ declare class TimeInputComponent implements ControlValueAccessor, FieldControl {
1670
1708
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<TimeInputComponent, "fk-time-input", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "isRequired": { "alias": "required"; "required": false; "isSignal": true; }; "isReadonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1671
1709
  }
1672
1710
 
1673
- export { AutocompleteComponent, CheckboxComponent, DEFAULT_ERROR_MESSAGES, DateInputComponent, DatetimeInputComponent, ERROR_MESSAGES, ErrorComponent, FIELD_CONTROL, FK_AUTOCOMPLETE_OPTION_TPL, FK_PREFIX, FK_SUFFIX, FORM, FieldArrayOutletComponent, FieldGroupComponent, FieldOutletComponent, FieldRegistry, FileDropzoneComponent, FileUploadComponent, FkAutocompleteOptionTplDirective, FkPrefixDirective, FkSuffixDirective, FormComponent, FormFieldComponent, FormRendererComponent, FormSectionComponent, HintComponent, InputComponent, LabelComponent, NumberInputComponent, PasswordInputComponent, RadioComponent, SchemaParser, SectionOutletComponent, SegmentedBarComponent, SelectComponent, SliderComponent, SwitchComponent, TagInputComponent, TextareaComponent, TimeInputComponent, ValidationRegistry, getError, getFieldState, getInvalidFields, hasError, interpolateMessage, isFormValid, markAllTouched, resolveErrorMessage };
1711
+ export { AutocompleteComponent, CheckboxComponent, DEFAULT_ERROR_MESSAGES, DateInputComponent, DatetimeInputComponent, ERROR_MESSAGES, ErrorComponent, FIELD_CONTROL, FK_AUTOCOMPLETE_OPTION_TPL, FK_FILE_DROPZONE_ICON, FK_PREFIX, FK_SUFFIX, FORM, FieldArrayOutletComponent, FieldGroupComponent, FieldOutletComponent, FieldRegistry, FileDropzoneComponent, FileUploadComponent, FkAutocompleteOptionTplDirective, FkFileDropzoneIconDirective, FkPrefixDirective, FkSuffixDirective, FormComponent, FormFieldComponent, FormRendererComponent, FormSectionComponent, HintComponent, InputComponent, LabelComponent, NumberInputComponent, PasswordInputComponent, RadioComponent, SchemaParser, SectionOutletComponent, SegmentedBarComponent, SelectComponent, SliderComponent, SwitchComponent, TagInputComponent, TextareaComponent, TimeInputComponent, ValidationRegistry, getError, getFieldState, getInvalidFields, hasError, interpolateMessage, isFormValid, markAllTouched, resolveErrorMessage };
1674
1712
  export type { AsyncValidatorConfig, AsyncValidatorFactory, AutocompleteFilterMode, AutocompleteOption, ErrorMessages, FieldControl, FieldGroupLayout, FieldSchema, FieldState, FieldUiConfig, FkFileDropzoneSelection, FormRendererSubmitValue, FormSchema, FormSchemaSection, FormStatus, InputType, LabelEndLink, LayoutColumn, LayoutRow, Option, PasswordAutoComplete, ProgressSegment, RadioOption, SegmentedBarSize, SelectOption, ShowErrorsOn, ValidatorConfig, ValidatorFactory, VisibilityRule };