@frame-kit/ui-ng 0.1.8 → 0.1.10

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.
@@ -87,11 +87,11 @@ class ButtonComponent {
87
87
  return this.isDisabled() ? 'true' : null;
88
88
  }
89
89
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
90
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ButtonComponent, isStandalone: true, selector: "fk-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass", "attr.aria-disabled": "this.ariaDisabledAttr" } }, queries: [{ propertyName: "iconStartRef", first: true, predicate: FK_BUTTON_ICON_START, descendants: true, isSignal: true }, { propertyName: "iconEndRef", first: true, predicate: FK_BUTTON_ICON_END, descendants: true, isSignal: true }], ngImport: i0, template: "<button\n class=\"fk-button__native\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n>\n @if (loading()) {\n <fk-loader\n className=\"fk-button__loader\"\n size=\"sm\"\n color=\"inherit\"\n ariaLabel=\"Loading\"\n ></fk-loader>\n }\n <span\n class=\"fk-button__content\"\n [class.fk-button__content--hidden]=\"loading()\"\n >\n <ng-content select=\"[fkButtonIconStart]\" />\n <ng-content />\n <ng-content select=\"[fkButtonIconEnd]\" />\n </span>\n</button>\n", styles: [":host{display:inline-block}:host.fk-button--full-width{display:block;width:100%}.fk-button__native{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--fk-button-icon-gap, .5rem);border:var(--fk-button-border-width, 1px) solid transparent;border-radius:var(--fk-button-border-radius, .5rem);font-weight:var(--fk-button-font-weight, var(--fk-typography-button-font-weight, 400));line-height:var(--fk-button-line-height, var(--fk-typography-button-line-height, 1.5));cursor:var(--fk-button-cursor, pointer);transition:var(--fk-button-transition, background-color .15s ease, border-color .15s ease, color .15s ease);text-decoration:none;white-space:nowrap;width:100%}.fk-button__native:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-button__content{display:inline-flex;align-items:center;gap:var(--fk-button-icon-gap, .5rem)}.fk-button__content--hidden{visibility:hidden}.fk-button__loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}:host.fk-button--sm .fk-button__native{padding:var(--fk-button-padding-sm, .375rem .75rem);font-size:var(--fk-button-font-size-sm, .875rem)}:host.fk-button--md .fk-button__native{padding:var(--fk-button-padding-md, .5rem 1rem);font-size:var(--fk-button-font-size-md, 1rem)}:host.fk-button--lg .fk-button__native{padding:var(--fk-button-padding-lg, .625rem 1.25rem);font-size:var(--fk-button-font-size-lg, 1.125rem)}:host.fk-button--primary .fk-button__native{background-color:var(--fk-button-primary-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-button-primary-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-primary-border-color, transparent)}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-primary-bg-hover, var(--fk-color-primary-hover, #0670e0))}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-primary-bg-active, var(--fk-color-primary-active, #055fc3))}:host.fk-button--secondary .fk-button__native{background-color:var(--fk-button-secondary-bg, transparent);color:var(--fk-button-secondary-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-secondary-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-secondary-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-secondary-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline .fk-button__native{background-color:var(--fk-button-outline-bg, transparent);color:var(--fk-button-outline-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-outline-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-outline-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-outline-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--danger .fk-button__native{background-color:var(--fk-button-danger-bg, var(--fk-color-danger, #e02424));color:var(--fk-button-danger-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-danger-border-color, transparent)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-danger-bg-hover, #b91c1c)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-danger-bg-active, #991b1b)}:host.fk-button--disabled .fk-button__native{opacity:var(--fk-button-opacity-disabled, .6);cursor:var(--fk-button-cursor-disabled, not-allowed)}\n"], dependencies: [{ kind: "component", type: LoaderComponent, selector: "fk-loader", inputs: ["size", "color", "className", "id", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
90
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ButtonComponent, isStandalone: true, selector: "fk-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass", "attr.aria-disabled": "this.ariaDisabledAttr" } }, queries: [{ propertyName: "iconStartRef", first: true, predicate: FK_BUTTON_ICON_START, descendants: true, isSignal: true }, { propertyName: "iconEndRef", first: true, predicate: FK_BUTTON_ICON_END, descendants: true, isSignal: true }], ngImport: i0, template: "<button\n class=\"fk-button__native\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n>\n @if (loading()) {\n <fk-loader\n className=\"fk-button__loader\"\n size=\"sm\"\n color=\"inherit\"\n ariaLabel=\"Loading\"\n ></fk-loader>\n }\n <span\n class=\"fk-button__content\"\n [class.fk-button__content--hidden]=\"loading()\"\n >\n <ng-content select=\"[fkButtonIconStart]\" />\n <ng-content />\n <ng-content select=\"[fkButtonIconEnd]\" />\n </span>\n</button>\n", styles: [":host{display:inline-block}:host.fk-button--full-width{display:block;width:100%}.fk-button__native{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--fk-button-icon-gap, .5rem);border:var(--fk-button-border-width, 1px) solid transparent;border-radius:var(--fk-button-border-radius, .5rem);font-weight:var(--fk-button-font-weight, var(--fk-typography-button-font-weight, 400));line-height:var(--fk-button-line-height, var(--fk-typography-button-line-height, 1.5));cursor:var(--fk-button-cursor, pointer);transition:var(--fk-button-transition, background-color .15s ease, border-color .15s ease, color .15s ease);text-decoration:none;white-space:nowrap;width:100%}.fk-button__native:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-button__content{display:inline-flex;align-items:center;gap:var(--fk-button-icon-gap, .5rem)}.fk-button__content--hidden{visibility:hidden}.fk-button__loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}:host.fk-button--xxsm .fk-button__native{padding:var(--fk-button-padding-xxsm, .125rem .375rem);font-size:var(--fk-button-font-size-xxsm, .6875rem)}:host.fk-button--xsm .fk-button__native{padding:var(--fk-button-padding-xsm, .25rem .625rem);font-size:var(--fk-button-font-size-xsm, .75rem)}:host.fk-button--sm .fk-button__native{padding:var(--fk-button-padding-sm, .375rem .75rem);font-size:var(--fk-button-font-size-sm, .875rem)}:host.fk-button--md .fk-button__native{padding:var(--fk-button-padding-md, .5rem 1rem);font-size:var(--fk-button-font-size-md, 1rem)}:host.fk-button--lg .fk-button__native{padding:var(--fk-button-padding-lg, .625rem 1.25rem);font-size:var(--fk-button-font-size-lg, 1.125rem)}:host.fk-button--xlg .fk-button__native{padding:var(--fk-button-padding-xlg, .75rem 1.5rem);font-size:var(--fk-button-font-size-xlg, 1.25rem)}:host.fk-button--xxlg .fk-button__native{padding:var(--fk-button-padding-xxlg, .875rem 1.75rem);font-size:var(--fk-button-font-size-xxlg, 1.375rem)}:host.fk-button--primary .fk-button__native{background-color:var(--fk-button-primary-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-button-primary-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-primary-border-color, transparent)}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-primary-bg-hover, var(--fk-color-primary-hover, #0670e0))}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-primary-bg-active, var(--fk-color-primary-active, #055fc3))}:host.fk-button--secondary .fk-button__native{background-color:var(--fk-button-secondary-bg, transparent);color:var(--fk-button-secondary-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-secondary-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-secondary-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-secondary-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline .fk-button__native{background-color:var(--fk-button-outline-bg, transparent);color:var(--fk-button-outline-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-outline-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-outline-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-outline-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--danger .fk-button__native{background-color:var(--fk-button-danger-bg, var(--fk-color-danger, #e02424));color:var(--fk-button-danger-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-danger-border-color, transparent)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-danger-bg-hover, #b91c1c)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-danger-bg-active, #991b1b)}:host.fk-button--disabled .fk-button__native{opacity:var(--fk-button-opacity-disabled, .6);cursor:var(--fk-button-cursor-disabled, not-allowed)}\n"], dependencies: [{ kind: "component", type: LoaderComponent, selector: "fk-loader", inputs: ["size", "color", "className", "id", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
91
91
  }
92
92
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ButtonComponent, decorators: [{
93
93
  type: Component,
94
- args: [{ selector: 'fk-button', standalone: true, imports: [LoaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n class=\"fk-button__native\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n>\n @if (loading()) {\n <fk-loader\n className=\"fk-button__loader\"\n size=\"sm\"\n color=\"inherit\"\n ariaLabel=\"Loading\"\n ></fk-loader>\n }\n <span\n class=\"fk-button__content\"\n [class.fk-button__content--hidden]=\"loading()\"\n >\n <ng-content select=\"[fkButtonIconStart]\" />\n <ng-content />\n <ng-content select=\"[fkButtonIconEnd]\" />\n </span>\n</button>\n", styles: [":host{display:inline-block}:host.fk-button--full-width{display:block;width:100%}.fk-button__native{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--fk-button-icon-gap, .5rem);border:var(--fk-button-border-width, 1px) solid transparent;border-radius:var(--fk-button-border-radius, .5rem);font-weight:var(--fk-button-font-weight, var(--fk-typography-button-font-weight, 400));line-height:var(--fk-button-line-height, var(--fk-typography-button-line-height, 1.5));cursor:var(--fk-button-cursor, pointer);transition:var(--fk-button-transition, background-color .15s ease, border-color .15s ease, color .15s ease);text-decoration:none;white-space:nowrap;width:100%}.fk-button__native:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-button__content{display:inline-flex;align-items:center;gap:var(--fk-button-icon-gap, .5rem)}.fk-button__content--hidden{visibility:hidden}.fk-button__loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}:host.fk-button--sm .fk-button__native{padding:var(--fk-button-padding-sm, .375rem .75rem);font-size:var(--fk-button-font-size-sm, .875rem)}:host.fk-button--md .fk-button__native{padding:var(--fk-button-padding-md, .5rem 1rem);font-size:var(--fk-button-font-size-md, 1rem)}:host.fk-button--lg .fk-button__native{padding:var(--fk-button-padding-lg, .625rem 1.25rem);font-size:var(--fk-button-font-size-lg, 1.125rem)}:host.fk-button--primary .fk-button__native{background-color:var(--fk-button-primary-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-button-primary-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-primary-border-color, transparent)}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-primary-bg-hover, var(--fk-color-primary-hover, #0670e0))}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-primary-bg-active, var(--fk-color-primary-active, #055fc3))}:host.fk-button--secondary .fk-button__native{background-color:var(--fk-button-secondary-bg, transparent);color:var(--fk-button-secondary-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-secondary-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-secondary-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-secondary-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline .fk-button__native{background-color:var(--fk-button-outline-bg, transparent);color:var(--fk-button-outline-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-outline-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-outline-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-outline-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--danger .fk-button__native{background-color:var(--fk-button-danger-bg, var(--fk-color-danger, #e02424));color:var(--fk-button-danger-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-danger-border-color, transparent)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-danger-bg-hover, #b91c1c)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-danger-bg-active, #991b1b)}:host.fk-button--disabled .fk-button__native{opacity:var(--fk-button-opacity-disabled, .6);cursor:var(--fk-button-cursor-disabled, not-allowed)}\n"] }]
94
+ args: [{ selector: 'fk-button', standalone: true, imports: [LoaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n class=\"fk-button__native\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n>\n @if (loading()) {\n <fk-loader\n className=\"fk-button__loader\"\n size=\"sm\"\n color=\"inherit\"\n ariaLabel=\"Loading\"\n ></fk-loader>\n }\n <span\n class=\"fk-button__content\"\n [class.fk-button__content--hidden]=\"loading()\"\n >\n <ng-content select=\"[fkButtonIconStart]\" />\n <ng-content />\n <ng-content select=\"[fkButtonIconEnd]\" />\n </span>\n</button>\n", styles: [":host{display:inline-block}:host.fk-button--full-width{display:block;width:100%}.fk-button__native{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--fk-button-icon-gap, .5rem);border:var(--fk-button-border-width, 1px) solid transparent;border-radius:var(--fk-button-border-radius, .5rem);font-weight:var(--fk-button-font-weight, var(--fk-typography-button-font-weight, 400));line-height:var(--fk-button-line-height, var(--fk-typography-button-line-height, 1.5));cursor:var(--fk-button-cursor, pointer);transition:var(--fk-button-transition, background-color .15s ease, border-color .15s ease, color .15s ease);text-decoration:none;white-space:nowrap;width:100%}.fk-button__native:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-button__content{display:inline-flex;align-items:center;gap:var(--fk-button-icon-gap, .5rem)}.fk-button__content--hidden{visibility:hidden}.fk-button__loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}:host.fk-button--xxsm .fk-button__native{padding:var(--fk-button-padding-xxsm, .125rem .375rem);font-size:var(--fk-button-font-size-xxsm, .6875rem)}:host.fk-button--xsm .fk-button__native{padding:var(--fk-button-padding-xsm, .25rem .625rem);font-size:var(--fk-button-font-size-xsm, .75rem)}:host.fk-button--sm .fk-button__native{padding:var(--fk-button-padding-sm, .375rem .75rem);font-size:var(--fk-button-font-size-sm, .875rem)}:host.fk-button--md .fk-button__native{padding:var(--fk-button-padding-md, .5rem 1rem);font-size:var(--fk-button-font-size-md, 1rem)}:host.fk-button--lg .fk-button__native{padding:var(--fk-button-padding-lg, .625rem 1.25rem);font-size:var(--fk-button-font-size-lg, 1.125rem)}:host.fk-button--xlg .fk-button__native{padding:var(--fk-button-padding-xlg, .75rem 1.5rem);font-size:var(--fk-button-font-size-xlg, 1.25rem)}:host.fk-button--xxlg .fk-button__native{padding:var(--fk-button-padding-xxlg, .875rem 1.75rem);font-size:var(--fk-button-font-size-xxlg, 1.375rem)}:host.fk-button--primary .fk-button__native{background-color:var(--fk-button-primary-bg, var(--fk-color-primary, #0a84ff));color:var(--fk-button-primary-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-primary-border-color, transparent)}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-primary-bg-hover, var(--fk-color-primary-hover, #0670e0))}:host.fk-button--primary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-primary-bg-active, var(--fk-color-primary-active, #055fc3))}:host.fk-button--secondary .fk-button__native{background-color:var(--fk-button-secondary-bg, transparent);color:var(--fk-button-secondary-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-secondary-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-secondary-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--secondary:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-secondary-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline .fk-button__native{background-color:var(--fk-button-outline-bg, transparent);color:var(--fk-button-outline-color, var(--fk-color-primary, #0a84ff));border-color:var(--fk-button-outline-border-color, var(--fk-color-border, #d9e2ee))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-outline-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}:host.fk-button--outline:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-outline-bg-active, var(--fk-color-border, #d9e2ee))}:host.fk-button--danger .fk-button__native{background-color:var(--fk-button-danger-bg, var(--fk-color-danger, #e02424));color:var(--fk-button-danger-color, var(--fk-color-surface, #ffffff));border-color:var(--fk-button-danger-border-color, transparent)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:hover{background-color:var(--fk-button-danger-bg-hover, #b91c1c)}:host.fk-button--danger:not(.fk-button--disabled) .fk-button__native:active{background-color:var(--fk-button-danger-bg-active, #991b1b)}:host.fk-button--disabled .fk-button__native{opacity:var(--fk-button-opacity-disabled, .6);cursor:var(--fk-button-cursor-disabled, not-allowed)}\n"] }]
95
95
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], iconStartRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_BUTTON_ICON_START), { isSignal: true }] }], iconEndRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_BUTTON_ICON_END), { isSignal: true }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], hostClass: [{
96
96
  type: HostBinding,
97
97
  args: ['class']
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-ui-button.mjs","sources":["../../../../packages/ui-ng/ui/button/button-icon.directive.ts","../../../../packages/ui-ng/ui/button/button.component.ts","../../../../packages/ui-ng/ui/button/button.component.html","../../../../packages/ui-ng/ui/button/frame-kit-ui-ng-ui-button.ts"],"sourcesContent":["import { Directive, InjectionToken } from '@angular/core';\n\nexport const FK_BUTTON_ICON_START =\n new InjectionToken<FkButtonIconStartDirective>('FK_BUTTON_ICON_START');\n\nexport const FK_BUTTON_ICON_END = new InjectionToken<FkButtonIconEndDirective>(\n 'FK_BUTTON_ICON_END',\n);\n\n@Directive({\n selector: '[fkButtonIconStart]',\n standalone: true,\n providers: [\n { provide: FK_BUTTON_ICON_START, useExisting: FkButtonIconStartDirective },\n ],\n host: {\n 'aria-hidden': 'true',\n },\n})\nexport class FkButtonIconStartDirective {}\n\n@Directive({\n selector: '[fkButtonIconEnd]',\n standalone: true,\n providers: [\n { provide: FK_BUTTON_ICON_END, useExisting: FkButtonIconEndDirective },\n ],\n host: {\n 'aria-hidden': 'true',\n },\n})\nexport class FkButtonIconEndDirective {}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { LoaderComponent } from '@frame-kit/ui-ng/ui/loader';\nimport type { ButtonSize, ButtonType, ButtonVariant } from './button.types';\nimport {\n FK_BUTTON_ICON_END,\n FK_BUTTON_ICON_START,\n} from './button-icon.directive';\n\n@Component({\n selector: 'fk-button',\n standalone: true,\n imports: [LoaderComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './button.component.html',\n styleUrl: './button.component.scss',\n})\nexport class ButtonComponent {\n // ===== BEHAVIOR =====\n /** Visual style variant of the button (primary, secondary, ghost, etc.). */\n readonly variant = input<ButtonVariant>('primary');\n /** Size of the button, affecting padding and font size. */\n readonly size = input<ButtonSize>('md');\n /** When true, shows a spinner and disables interaction. */\n readonly loading = input<boolean>(false);\n /** When true, prevents interaction and applies disabled styling. */\n readonly disabled = input<boolean>(false);\n /** HTML type attribute forwarded to the inner `<button>` element. */\n readonly type = input<ButtonType>('button');\n /** When true, the button stretches to fill its container width. */\n readonly fullWidth = input<boolean>(false);\n\n // ===== CONTENT CHILDREN =====\n readonly iconStartRef = contentChild(FK_BUTTON_ICON_START);\n readonly iconEndRef = contentChild(FK_BUTTON_ICON_END);\n\n // ===== BASE PROPS =====\n readonly id = input<string | null>(null);\n readonly className = input<string>('');\n readonly ariaLabel = input<string | null>(null);\n readonly ariaDescribedBy = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly isDisabled = computed(() => this.disabled() || this.loading());\n\n readonly classes = computed(() => {\n return [\n 'fk-button',\n `fk-button--${this.variant()}`,\n `fk-button--${this.size()}`,\n this.isDisabled() ? 'fk-button--disabled' : '',\n this.loading() ? 'fk-button--loading' : '',\n this.fullWidth() ? 'fk-button--full-width' : '',\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.aria-disabled')\n get ariaDisabledAttr(): string | null {\n return this.isDisabled() ? 'true' : null;\n }\n}\n","<button\n class=\"fk-button__native\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n>\n @if (loading()) {\n <fk-loader\n className=\"fk-button__loader\"\n size=\"sm\"\n color=\"inherit\"\n ariaLabel=\"Loading\"\n ></fk-loader>\n }\n <span\n class=\"fk-button__content\"\n [class.fk-button__content--hidden]=\"loading()\"\n >\n <ng-content select=\"[fkButtonIconStart]\" />\n <ng-content />\n <ng-content select=\"[fkButtonIconEnd]\" />\n </span>\n</button>\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-button.mjs","sources":["../../../../packages/ui-ng/ui/button/button-icon.directive.ts","../../../../packages/ui-ng/ui/button/button.component.ts","../../../../packages/ui-ng/ui/button/button.component.html","../../../../packages/ui-ng/ui/button/frame-kit-ui-ng-ui-button.ts"],"sourcesContent":["import { Directive, InjectionToken } from '@angular/core';\n\nexport const FK_BUTTON_ICON_START =\n new InjectionToken<FkButtonIconStartDirective>('FK_BUTTON_ICON_START');\n\nexport const FK_BUTTON_ICON_END = new InjectionToken<FkButtonIconEndDirective>(\n 'FK_BUTTON_ICON_END',\n);\n\n@Directive({\n selector: '[fkButtonIconStart]',\n standalone: true,\n providers: [\n { provide: FK_BUTTON_ICON_START, useExisting: FkButtonIconStartDirective },\n ],\n host: {\n 'aria-hidden': 'true',\n },\n})\nexport class FkButtonIconStartDirective {}\n\n@Directive({\n selector: '[fkButtonIconEnd]',\n standalone: true,\n providers: [\n { provide: FK_BUTTON_ICON_END, useExisting: FkButtonIconEndDirective },\n ],\n host: {\n 'aria-hidden': 'true',\n },\n})\nexport class FkButtonIconEndDirective {}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { LoaderComponent } from '@frame-kit/ui-ng/ui/loader';\nimport type { ButtonSize, ButtonType, ButtonVariant } from './button.types';\nimport {\n FK_BUTTON_ICON_END,\n FK_BUTTON_ICON_START,\n} from './button-icon.directive';\n\n@Component({\n selector: 'fk-button',\n standalone: true,\n imports: [LoaderComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './button.component.html',\n styleUrl: './button.component.scss',\n})\nexport class ButtonComponent {\n // ===== BEHAVIOR =====\n /** Visual style variant of the button (primary, secondary, ghost, etc.). */\n readonly variant = input<ButtonVariant>('primary');\n /** Size of the button, affecting padding and font size. */\n readonly size = input<ButtonSize>('md');\n /** When true, shows a spinner and disables interaction. */\n readonly loading = input<boolean>(false);\n /** When true, prevents interaction and applies disabled styling. */\n readonly disabled = input<boolean>(false);\n /** HTML type attribute forwarded to the inner `<button>` element. */\n readonly type = input<ButtonType>('button');\n /** When true, the button stretches to fill its container width. */\n readonly fullWidth = input<boolean>(false);\n\n // ===== CONTENT CHILDREN =====\n readonly iconStartRef = contentChild(FK_BUTTON_ICON_START);\n readonly iconEndRef = contentChild(FK_BUTTON_ICON_END);\n\n // ===== BASE PROPS =====\n readonly id = input<string | null>(null);\n readonly className = input<string>('');\n readonly ariaLabel = input<string | null>(null);\n readonly ariaDescribedBy = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly isDisabled = computed(() => this.disabled() || this.loading());\n\n readonly classes = computed(() => {\n return [\n 'fk-button',\n `fk-button--${this.variant()}`,\n `fk-button--${this.size()}`,\n this.isDisabled() ? 'fk-button--disabled' : '',\n this.loading() ? 'fk-button--loading' : '',\n this.fullWidth() ? 'fk-button--full-width' : '',\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.aria-disabled')\n get ariaDisabledAttr(): string | null {\n return this.isDisabled() ? 'true' : null;\n }\n}\n","<button\n class=\"fk-button__native\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n>\n @if (loading()) {\n <fk-loader\n className=\"fk-button__loader\"\n size=\"sm\"\n color=\"inherit\"\n ariaLabel=\"Loading\"\n ></fk-loader>\n }\n <span\n class=\"fk-button__content\"\n [class.fk-button__content--hidden]=\"loading()\"\n >\n <ng-content select=\"[fkButtonIconStart]\" />\n <ng-content />\n <ng-content select=\"[fkButtonIconEnd]\" />\n </span>\n</button>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,10 +1,40 @@
1
1
  import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle, CdkDragPlaceholder } from '@angular/cdk/drag-drop';
2
+ import { NgTemplateOutlet } from '@angular/common';
2
3
  import * as i0 from '@angular/core';
3
- import { model, input, output, signal, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { inject, TemplateRef, Directive, model, input, output, contentChild, signal, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
4
5
  import * as i1 from '@angular/forms';
5
6
  import { FormsModule } from '@angular/forms';
6
7
  import { ButtonComponent, FkButtonIconStartDirective } from '@frame-kit/ui-ng/ui/button';
7
8
 
9
+ /**
10
+ * Marks an `<ng-template>` as the per-row renderer for `fk-list-editor`. When
11
+ * present, the editor renders this template for each item instead of its
12
+ * default editable input + remove button, so the consumer owns the row markup
13
+ * (scheme tag, status, custom actions, …). The add-input, empty state, and
14
+ * optional drag/order chrome are still provided by the editor.
15
+ *
16
+ * ```html
17
+ * <fk-list-editor [items]="origins">
18
+ * <ng-template fkListEditorItem let-origin let-remove="remove">
19
+ * <span>{{ origin }}</span>
20
+ * <button (click)="remove()">Remove</button>
21
+ * </ng-template>
22
+ * </fk-list-editor>
23
+ * ```
24
+ */
25
+ class FkListEditorItemDirective {
26
+ templateRef = inject((TemplateRef));
27
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FkListEditorItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
28
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: FkListEditorItemDirective, isStandalone: true, selector: "[fkListEditorItem]", ngImport: i0 });
29
+ }
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FkListEditorItemDirective, decorators: [{
31
+ type: Directive,
32
+ args: [{
33
+ selector: '[fkListEditorItem]',
34
+ standalone: true,
35
+ }]
36
+ }] });
37
+
8
38
  class ListEditorComponent {
9
39
  // ===== INPUTS =====
10
40
  /** The current list of string items; two-way bindable via `[(items)]`. */
@@ -34,6 +64,13 @@ class ListEditorComponent {
34
64
  itemAdded = output();
35
65
  /** Fires when an item is removed, emitting the removed value and its former index. */
36
66
  itemRemoved = output();
67
+ // ===== CONTENT =====
68
+ /**
69
+ * Optional custom row template (`*fkListEditorItem`). When provided, each
70
+ * item renders through it instead of the default editable input + remove
71
+ * button.
72
+ */
73
+ itemTemplate = contentChild(FkListEditorItemDirective, ...(ngDevMode ? [{ debugName: "itemTemplate" }] : /* istanbul ignore next */ []));
37
74
  // ===== LOCAL STATE =====
38
75
  newItemValue = signal('', ...(ngDevMode ? [{ debugName: "newItemValue" }] : /* istanbul ignore next */ []));
39
76
  // ===== COMPUTED =====
@@ -100,6 +137,16 @@ class ListEditorComponent {
100
137
  isLocked(item) {
101
138
  return this.lockedItems().includes(item.trim().toLowerCase());
102
139
  }
140
+ /** Builds the `let-` context for a custom row template. */
141
+ contextFor(item, index) {
142
+ return {
143
+ $implicit: item,
144
+ index,
145
+ locked: this.isLocked(item),
146
+ remove: () => this.removeItem(index),
147
+ update: (value) => this.updateItem(index, value),
148
+ };
149
+ }
103
150
  onKeydown(event) {
104
151
  if (event.key === 'Enter') {
105
152
  event.preventDefault();
@@ -107,20 +154,21 @@ class ListEditorComponent {
107
154
  }
108
155
  }
109
156
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ListEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
110
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ListEditorComponent, isStandalone: true, selector: "fk-list-editor", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, addLabel: { classPropertyName: "addLabel", publicName: "addLabel", isSignal: true, isRequired: false, transformFunction: null }, orderable: { classPropertyName: "orderable", publicName: "orderable", isSignal: true, isRequired: false, transformFunction: null }, showOrder: { classPropertyName: "showOrder", publicName: "showOrder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, lockedItems: { classPropertyName: "lockedItems", publicName: "lockedItems", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", itemsChange: "itemsChange", itemAdded: "itemAdded", itemRemoved: "itemRemoved" }, host: { properties: { "class": "this.hostClass" } }, ngImport: i0, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"isLocked(item) ? 'This item cannot be removed' : 'Remove item'\"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__input{flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: ButtonComponent, selector: "fk-button", inputs: ["variant", "size", "loading", "disabled", "type", "fullWidth", "id", "className", "ariaLabel", "ariaDescribedBy"] }, { kind: "directive", type: FkButtonIconStartDirective, selector: "[fkButtonIconStart]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
157
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ListEditorComponent, isStandalone: true, selector: "fk-list-editor", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, addLabel: { classPropertyName: "addLabel", publicName: "addLabel", isSignal: true, isRequired: false, transformFunction: null }, orderable: { classPropertyName: "orderable", publicName: "orderable", isSignal: true, isRequired: false, transformFunction: null }, showOrder: { classPropertyName: "showOrder", publicName: "showOrder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, lockedItems: { classPropertyName: "lockedItems", publicName: "lockedItems", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", itemsChange: "itemsChange", itemAdded: "itemAdded", itemRemoved: "itemRemoved" }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "itemTemplate", first: true, predicate: FkListEditorItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__item-custom{flex:1;min-width:0}.fk-list-editor__input{flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: ButtonComponent, selector: "fk-button", inputs: ["variant", "size", "loading", "disabled", "type", "fullWidth", "id", "className", "ariaLabel", "ariaDescribedBy"] }, { kind: "directive", type: FkButtonIconStartDirective, selector: "[fkButtonIconStart]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
111
158
  }
112
159
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ListEditorComponent, decorators: [{
113
160
  type: Component,
114
161
  args: [{ selector: 'fk-list-editor', standalone: true, imports: [
115
162
  FormsModule,
163
+ NgTemplateOutlet,
116
164
  CdkDropList,
117
165
  CdkDrag,
118
166
  CdkDragHandle,
119
167
  CdkDragPlaceholder,
120
168
  ButtonComponent,
121
169
  FkButtonIconStartDirective,
122
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"isLocked(item) ? 'This item cannot be removed' : 'Remove item'\"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__input{flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"] }]
123
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }, { type: i0.Output, args: ["itemsChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], addLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addLabel", required: false }] }], orderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderable", required: false }] }], showOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOrder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], lockedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockedItems", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], itemsChange: [{ type: i0.Output, args: ["itemsChange"] }], itemAdded: [{ type: i0.Output, args: ["itemAdded"] }], itemRemoved: [{ type: i0.Output, args: ["itemRemoved"] }], hostClass: [{
170
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__item-custom{flex:1;min-width:0}.fk-list-editor__input{flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"] }]
171
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }, { type: i0.Output, args: ["itemsChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], addLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addLabel", required: false }] }], orderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderable", required: false }] }], showOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOrder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], lockedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockedItems", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], itemsChange: [{ type: i0.Output, args: ["itemsChange"] }], itemAdded: [{ type: i0.Output, args: ["itemAdded"] }], itemRemoved: [{ type: i0.Output, args: ["itemRemoved"] }], itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FkListEditorItemDirective), { isSignal: true }] }], hostClass: [{
124
172
  type: HostBinding,
125
173
  args: ['class']
126
174
  }] } });
@@ -129,5 +177,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
129
177
  * Generated bundle index. Do not edit.
130
178
  */
131
179
 
132
- export { ListEditorComponent };
180
+ export { FkListEditorItemDirective, ListEditorComponent };
133
181
  //# sourceMappingURL=frame-kit-ui-ng-ui-list-editor.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-ui-list-editor.mjs","sources":["../../../../packages/ui-ng/ui/list-editor/list-editor.component.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.html","../../../../packages/ui-ng/ui/list-editor/frame-kit-ui-ng-ui-list-editor.ts"],"sourcesContent":["import {\n CdkDrag,\n CdkDragDrop,\n CdkDragHandle,\n CdkDragPlaceholder,\n CdkDropList,\n moveItemInArray,\n} from '@angular/cdk/drag-drop';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\nimport { FkButtonIconStartDirective } from '@frame-kit/ui-ng/ui/button';\nimport type { ListEditorSize } from './list-editor.types';\n\n@Component({\n selector: 'fk-list-editor',\n standalone: true,\n imports: [\n FormsModule,\n CdkDropList,\n CdkDrag,\n CdkDragHandle,\n CdkDragPlaceholder,\n ButtonComponent,\n FkButtonIconStartDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './list-editor.component.html',\n styleUrl: './list-editor.component.scss',\n})\nexport class ListEditorComponent {\n // ===== INPUTS =====\n /** The current list of string items; two-way bindable via `[(items)]`. */\n readonly items = model<string[]>([]);\n /** Placeholder text for the new-item input field. */\n readonly placeholder = input('Add an item...');\n /** Message displayed when the list is empty. */\n readonly emptyMessage = input('No items added yet.');\n /** Label for the add button. */\n readonly addLabel = input('Add');\n /** When true, items can be reordered via drag-and-drop. */\n readonly orderable = input(true);\n /** When true, shows a numeric position indicator next to each item. */\n readonly showOrder = input(true);\n /** Size variant controlling the spacing and font of the component. */\n readonly size = input<ListEditorSize>('md');\n /** Items that cannot be removed by the user (matched case-insensitively). */\n readonly lockedItems = input<string[]>([]);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly disabled = input(false);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires whenever the items array changes, emitting the full updated array. */\n readonly itemsChange = output<string[]>();\n /** Fires when a new item is successfully added, emitting the added value. */\n readonly itemAdded = output<string>();\n /** Fires when an item is removed, emitting the removed value and its former index. */\n readonly itemRemoved = output<{ item: string; index: number }>();\n\n // ===== LOCAL STATE =====\n readonly newItemValue = signal('');\n\n // ===== COMPUTED =====\n readonly canAdd = computed(() => {\n const value = this.newItemValue().trim();\n\n if (!value) {\n return false;\n }\n\n const existing = this.items().map((n) => n.trim().toLowerCase());\n\n return !existing.includes(value.toLowerCase());\n });\n\n readonly hasDuplicates = computed(() => {\n const names = this.items().map((n) => n.trim().toLowerCase());\n\n return new Set(names).size !== names.length;\n });\n\n readonly hasEmptyItems = computed(() => {\n return this.items().some((n) => n.trim() === '');\n });\n\n readonly classes = computed(() =>\n [\n 'fk-list-editor',\n `fk-list-editor--${this.size()}`,\n this.disabled() ? 'fk-list-editor--disabled' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n // ===== ACTIONS =====\n\n /** Adds the current input value as a new item if it is non-empty and not a duplicate. */\n addItem(): void {\n const value = this.newItemValue().trim();\n\n if (!value || !this.canAdd() || this.disabled()) {\n return;\n }\n\n this.items.update((prev) => [...prev, value]);\n this.newItemValue.set('');\n this.itemsChange.emit(this.items());\n this.itemAdded.emit(value);\n }\n\n /** Removes the item at the given index unless it is locked or the component is disabled. */\n removeItem(index: number): void {\n const item = this.items()[index];\n\n if (this.disabled() || this.isLocked(item)) {\n return;\n }\n\n this.items.update((prev) => prev.filter((_, i) => i !== index));\n this.itemsChange.emit(this.items());\n this.itemRemoved.emit({ item, index });\n }\n\n /** Updates the item at the given index with a new value and emits the changed array. */\n updateItem(index: number, value: string): void {\n this.items.update((prev) =>\n prev.map((item, i) => (i === index ? value : item)),\n );\n this.itemsChange.emit(this.items());\n }\n\n onDrop(event: CdkDragDrop<string[]>): void {\n const updated = [...this.items()];\n\n moveItemInArray(updated, event.previousIndex, event.currentIndex);\n this.items.set(updated);\n this.itemsChange.emit(this.items());\n }\n\n /** Returns true if the given item matches any entry in `lockedItems`. */\n isLocked(item: string): boolean {\n return this.lockedItems().includes(item.trim().toLowerCase());\n }\n\n onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.addItem();\n }\n }\n}\n","<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"isLocked(item) ? 'This item cannot be removed' : 'Remove item'\"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\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-list-editor.mjs","sources":["../../../../packages/ui-ng/ui/list-editor/list-editor-item.directive.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.html","../../../../packages/ui-ng/ui/list-editor/frame-kit-ui-ng-ui-list-editor.ts"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { ListEditorItemContext } from './list-editor.types';\n\n/**\n * Marks an `<ng-template>` as the per-row renderer for `fk-list-editor`. When\n * present, the editor renders this template for each item instead of its\n * default editable input + remove button, so the consumer owns the row markup\n * (scheme tag, status, custom actions, …). The add-input, empty state, and\n * optional drag/order chrome are still provided by the editor.\n *\n * ```html\n * <fk-list-editor [items]=\"origins\">\n * <ng-template fkListEditorItem let-origin let-remove=\"remove\">\n * <span>{{ origin }}</span>\n * <button (click)=\"remove()\">Remove</button>\n * </ng-template>\n * </fk-list-editor>\n * ```\n */\n@Directive({\n selector: '[fkListEditorItem]',\n standalone: true,\n})\nexport class FkListEditorItemDirective {\n readonly templateRef = inject(TemplateRef<ListEditorItemContext>);\n}\n","import {\n CdkDrag,\n CdkDragDrop,\n CdkDragHandle,\n CdkDragPlaceholder,\n CdkDropList,\n moveItemInArray,\n} from '@angular/cdk/drag-drop';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n HostBinding,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\nimport { FkButtonIconStartDirective } from '@frame-kit/ui-ng/ui/button';\nimport { FkListEditorItemDirective } from './list-editor-item.directive';\nimport type {\n ListEditorItemContext,\n ListEditorSize,\n} from './list-editor.types';\n\n@Component({\n selector: 'fk-list-editor',\n standalone: true,\n imports: [\n FormsModule,\n NgTemplateOutlet,\n CdkDropList,\n CdkDrag,\n CdkDragHandle,\n CdkDragPlaceholder,\n ButtonComponent,\n FkButtonIconStartDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './list-editor.component.html',\n styleUrl: './list-editor.component.scss',\n})\nexport class ListEditorComponent {\n // ===== INPUTS =====\n /** The current list of string items; two-way bindable via `[(items)]`. */\n readonly items = model<string[]>([]);\n /** Placeholder text for the new-item input field. */\n readonly placeholder = input('Add an item...');\n /** Message displayed when the list is empty. */\n readonly emptyMessage = input('No items added yet.');\n /** Label for the add button. */\n readonly addLabel = input('Add');\n /** When true, items can be reordered via drag-and-drop. */\n readonly orderable = input(true);\n /** When true, shows a numeric position indicator next to each item. */\n readonly showOrder = input(true);\n /** Size variant controlling the spacing and font of the component. */\n readonly size = input<ListEditorSize>('md');\n /** Items that cannot be removed by the user (matched case-insensitively). */\n readonly lockedItems = input<string[]>([]);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly disabled = input(false);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires whenever the items array changes, emitting the full updated array. */\n readonly itemsChange = output<string[]>();\n /** Fires when a new item is successfully added, emitting the added value. */\n readonly itemAdded = output<string>();\n /** Fires when an item is removed, emitting the removed value and its former index. */\n readonly itemRemoved = output<{ item: string; index: number }>();\n\n // ===== CONTENT =====\n /**\n * Optional custom row template (`*fkListEditorItem`). When provided, each\n * item renders through it instead of the default editable input + remove\n * button.\n */\n readonly itemTemplate = contentChild(FkListEditorItemDirective);\n\n // ===== LOCAL STATE =====\n readonly newItemValue = signal('');\n\n // ===== COMPUTED =====\n readonly canAdd = computed(() => {\n const value = this.newItemValue().trim();\n\n if (!value) {\n return false;\n }\n\n const existing = this.items().map((n) => n.trim().toLowerCase());\n\n return !existing.includes(value.toLowerCase());\n });\n\n readonly hasDuplicates = computed(() => {\n const names = this.items().map((n) => n.trim().toLowerCase());\n\n return new Set(names).size !== names.length;\n });\n\n readonly hasEmptyItems = computed(() => {\n return this.items().some((n) => n.trim() === '');\n });\n\n readonly classes = computed(() =>\n [\n 'fk-list-editor',\n `fk-list-editor--${this.size()}`,\n this.disabled() ? 'fk-list-editor--disabled' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n // ===== ACTIONS =====\n\n /** Adds the current input value as a new item if it is non-empty and not a duplicate. */\n addItem(): void {\n const value = this.newItemValue().trim();\n\n if (!value || !this.canAdd() || this.disabled()) {\n return;\n }\n\n this.items.update((prev) => [...prev, value]);\n this.newItemValue.set('');\n this.itemsChange.emit(this.items());\n this.itemAdded.emit(value);\n }\n\n /** Removes the item at the given index unless it is locked or the component is disabled. */\n removeItem(index: number): void {\n const item = this.items()[index];\n\n if (this.disabled() || this.isLocked(item)) {\n return;\n }\n\n this.items.update((prev) => prev.filter((_, i) => i !== index));\n this.itemsChange.emit(this.items());\n this.itemRemoved.emit({ item, index });\n }\n\n /** Updates the item at the given index with a new value and emits the changed array. */\n updateItem(index: number, value: string): void {\n this.items.update((prev) =>\n prev.map((item, i) => (i === index ? value : item)),\n );\n this.itemsChange.emit(this.items());\n }\n\n onDrop(event: CdkDragDrop<string[]>): void {\n const updated = [...this.items()];\n\n moveItemInArray(updated, event.previousIndex, event.currentIndex);\n this.items.set(updated);\n this.itemsChange.emit(this.items());\n }\n\n /** Returns true if the given item matches any entry in `lockedItems`. */\n isLocked(item: string): boolean {\n return this.lockedItems().includes(item.trim().toLowerCase());\n }\n\n /** Builds the `let-` context for a custom row template. */\n contextFor(item: string, index: number): ListEditorItemContext {\n return {\n $implicit: item,\n index,\n locked: this.isLocked(item),\n remove: () => this.removeItem(index),\n update: (value: string) => this.updateItem(index, value),\n };\n }\n\n onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.addItem();\n }\n }\n}\n","<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\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.8",
3
+ "version": "0.1.10",
4
4
  "description": "Style-agnostic, token-driven Angular UI component library for FrameKit.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -3,7 +3,7 @@ import * as _angular_core from '@angular/core';
3
3
  import { InjectionToken } from '@angular/core';
4
4
 
5
5
  type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'danger';
6
- type ButtonSize = 'sm' | 'md' | 'lg';
6
+ type ButtonSize = 'xxsm' | 'xsm' | 'sm' | 'md' | 'lg' | 'xlg' | 'xxlg';
7
7
  type ButtonType = 'button' | 'submit' | 'reset';
8
8
 
9
9
  declare class ButtonComponent {
@@ -1,7 +1,47 @@
1
1
  import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
2
3
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
3
4
 
5
+ /**
6
+ * Marks an `<ng-template>` as the per-row renderer for `fk-list-editor`. When
7
+ * present, the editor renders this template for each item instead of its
8
+ * default editable input + remove button, so the consumer owns the row markup
9
+ * (scheme tag, status, custom actions, …). The add-input, empty state, and
10
+ * optional drag/order chrome are still provided by the editor.
11
+ *
12
+ * ```html
13
+ * <fk-list-editor [items]="origins">
14
+ * <ng-template fkListEditorItem let-origin let-remove="remove">
15
+ * <span>{{ origin }}</span>
16
+ * <button (click)="remove()">Remove</button>
17
+ * </ng-template>
18
+ * </fk-list-editor>
19
+ * ```
20
+ */
21
+ declare class FkListEditorItemDirective {
22
+ readonly templateRef: TemplateRef<any>;
23
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FkListEditorItemDirective, never>;
24
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FkListEditorItemDirective, "[fkListEditorItem]", never, {}, {}, never, never, true, never>;
25
+ }
26
+
4
27
  type ListEditorSize = 'sm' | 'md';
28
+ /**
29
+ * Context passed to a custom `fk-list-editor` row template (`*fkListEditorItem`)
30
+ * via the `let-` microsyntax. `$implicit` is the item value; `remove` / `update`
31
+ * act on this specific row.
32
+ */
33
+ interface ListEditorItemContext {
34
+ /** The item value. */
35
+ $implicit: string;
36
+ /** The item's position in the list. */
37
+ index: number;
38
+ /** True when the item is locked (non-removable). */
39
+ locked: boolean;
40
+ /** Remove this item from the list. */
41
+ remove: () => void;
42
+ /** Replace this item's value. */
43
+ update: (value: string) => void;
44
+ }
5
45
 
6
46
  declare class ListEditorComponent {
7
47
  /** The current list of string items; two-way bindable via `[(items)]`. */
@@ -32,6 +72,12 @@ declare class ListEditorComponent {
32
72
  item: string;
33
73
  index: number;
34
74
  }>;
75
+ /**
76
+ * Optional custom row template (`*fkListEditorItem`). When provided, each
77
+ * item renders through it instead of the default editable input + remove
78
+ * button.
79
+ */
80
+ readonly itemTemplate: _angular_core.Signal<FkListEditorItemDirective | undefined>;
35
81
  readonly newItemValue: _angular_core.WritableSignal<string>;
36
82
  readonly canAdd: _angular_core.Signal<boolean>;
37
83
  readonly hasDuplicates: _angular_core.Signal<boolean>;
@@ -47,10 +93,12 @@ declare class ListEditorComponent {
47
93
  onDrop(event: CdkDragDrop<string[]>): void;
48
94
  /** Returns true if the given item matches any entry in `lockedItems`. */
49
95
  isLocked(item: string): boolean;
96
+ /** Builds the `let-` context for a custom row template. */
97
+ contextFor(item: string, index: number): ListEditorItemContext;
50
98
  onKeydown(event: KeyboardEvent): void;
51
99
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ListEditorComponent, never>;
52
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ListEditorComponent, "fk-list-editor", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "addLabel": { "alias": "addLabel"; "required": false; "isSignal": true; }; "orderable": { "alias": "orderable"; "required": false; "isSignal": true; }; "showOrder": { "alias": "showOrder"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "lockedItems": { "alias": "lockedItems"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "items": "itemsChange"; "itemsChange": "itemsChange"; "itemAdded": "itemAdded"; "itemRemoved": "itemRemoved"; }, never, never, true, never>;
100
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ListEditorComponent, "fk-list-editor", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "addLabel": { "alias": "addLabel"; "required": false; "isSignal": true; }; "orderable": { "alias": "orderable"; "required": false; "isSignal": true; }; "showOrder": { "alias": "showOrder"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "lockedItems": { "alias": "lockedItems"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "items": "itemsChange"; "itemsChange": "itemsChange"; "itemAdded": "itemAdded"; "itemRemoved": "itemRemoved"; }, ["itemTemplate"], never, true, never>;
53
101
  }
54
102
 
55
- export { ListEditorComponent };
56
- export type { ListEditorSize };
103
+ export { FkListEditorItemDirective, ListEditorComponent };
104
+ export type { ListEditorItemContext, ListEditorSize };
@@ -11,7 +11,7 @@ A token-driven button component for Angular that supports visual variants, sizes
11
11
  | Input | Type | Default | Description |
12
12
  | ----------------- | ---------------- | ----------- | ------------------------------------------------------------------------ |
13
13
  | `variant` | `ButtonVariant` | `"primary"` | Visual style of the button (for example `primary`, `secondary`, `ghost`) |
14
- | `size` | `ButtonSize` | `"md"` | Size of the button (`sm`, `md`, `lg`) |
14
+ | `size` | `ButtonSize` | `"md"` | Size (`xxsm`, `xsm`, `sm`, `md`, `lg`, `xlg`, `xxlg`) |
15
15
  | `loading` | `boolean` | `false` | Shows a loader and disables interaction |
16
16
  | `disabled` | `boolean` | `false` | Disables the button |
17
17
  | `fullWidth` | `boolean` | `false` | Stretches the button host to fill its parent's inline size |
@@ -103,10 +103,16 @@ export class ExampleComponent {}
103
103
 
104
104
  ### Sizes
105
105
 
106
+ Seven-step scale, smallest → largest:
107
+
106
108
  ```html
109
+ <fk-button size="xxsm">XX-Small</fk-button>
110
+ <fk-button size="xsm">X-Small</fk-button>
107
111
  <fk-button size="sm">Small</fk-button>
108
112
  <fk-button size="md">Medium</fk-button>
109
113
  <fk-button size="lg">Large</fk-button>
114
+ <fk-button size="xlg">X-Large</fk-button>
115
+ <fk-button size="xxlg">XX-Large</fk-button>
110
116
  ```
111
117
 
112
118
  ### With icon (start)
@@ -30,13 +30,37 @@ A token-driven list editor for building ordered string lists with add, remove, i
30
30
 
31
31
  ### Content
32
32
 
33
- `fk-list-editor` does not use content projection. All configuration is via inputs.
33
+ By default the editor renders each item as an editable text input with a remove
34
+ button. To take over the row markup (status badges, custom actions, read-only
35
+ display, …), project an `<ng-template fkListEditorItem>`. When present, it
36
+ replaces the per-row input/remove for every item; the add-input, empty state,
37
+ and optional drag/order chrome are still provided by the editor.
38
+
39
+ The template receives a `ListEditorItemContext` via the `let-` microsyntax:
40
+
41
+ | Context | Type | Description |
42
+ | ----------- | ------------------------- | ------------------------------- |
43
+ | `$implicit` | `string` | The item value (`let-item`) |
44
+ | `index` | `number` | The item's position in the list |
45
+ | `locked` | `boolean` | Whether the item is locked |
46
+ | `remove` | `() => void` | Remove this item |
47
+ | `update` | `(value: string) => void` | Replace this item's value |
48
+
49
+ ```html
50
+ <fk-list-editor [items]="origins">
51
+ <ng-template fkListEditorItem let-origin let-remove="remove">
52
+ <span>{{ origin }}</span>
53
+ <button (click)="remove()">Remove</button>
54
+ </ng-template>
55
+ </fk-list-editor>
56
+ ```
34
57
 
35
58
  ## Features
36
59
 
37
60
  - Add items via text input with Enter key or button click
38
61
  - Remove items with the remove button
39
62
  - Inline edit existing items
63
+ - Custom per-row rendering via `*fkListEditorItem`
40
64
  - Drag-to-reorder with CDK drag-drop
41
65
  - Duplicate detection with error message
42
66
  - Lock specific items from editing or removal
@@ -53,13 +77,14 @@ A token-driven list editor for building ordered string lists with add, remove, i
53
77
  ## Import
54
78
 
55
79
  ```ts
56
- import { ListEditorComponent } from '@frame-kit/ui-ng';
80
+ import { ListEditorComponent, FkListEditorItemDirective } from '@frame-kit/ui-ng';
57
81
  ```
58
82
 
59
83
  ```ts
60
84
  @Component({
61
85
  selector: 'app-example',
62
- imports: [ListEditorComponent],
86
+ // FkListEditorItemDirective only needed when projecting a custom row template
87
+ imports: [ListEditorComponent, FkListEditorItemDirective],
63
88
  templateUrl: './example.component.html',
64
89
  })
65
90
  export class ExampleComponent {}
@@ -91,6 +116,21 @@ export class ExampleComponent {}
91
116
  <fk-list-editor [(items)]="levels" [lockedItems]="inUseLevels" placeholder="Add a level..." addLabel="Add Level" />
92
117
  ```
93
118
 
119
+ ### Custom row template
120
+
121
+ Render each row yourself (e.g. an allowed-origins editor with a scheme tag) via
122
+ `*fkListEditorItem`. The editor still supplies the add-input and empty state.
123
+
124
+ ```html
125
+ <fk-list-editor [(items)]="origins" [orderable]="false" [showOrder]="false" placeholder="https://app.example.com" addLabel="Add">
126
+ <ng-template fkListEditorItem let-origin let-remove="remove">
127
+ <span class="scheme">{{ origin.startsWith('https') ? 'https' : 'http' }}</span>
128
+ <span class="url">{{ origin }}</span>
129
+ <button type="button" (click)="remove()">Remove</button>
130
+ </ng-template>
131
+ </fk-list-editor>
132
+ ```
133
+
94
134
  ## Accessibility
95
135
 
96
136
  - The list container supports `ariaLabel` for screen readers