UNPKG

@synerity/ui

Version:
477 lines (473 loc) 1.55 MB
import * as i0 from '@angular/core'; import { EventEmitter, forwardRef, Output, Input, Component, ChangeDetectionStrategy, ViewChild, HostListener, ViewChildren, ElementRef } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'; import * as i2 from '@angular/forms'; import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms'; import { fromEvent, interval } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; class Button { variant = 'primary'; size = 'md'; disabled = false; loading = false; type = 'button'; fullWidth = false; icon = null; iconPosition = 'left'; click = new EventEmitter(); // ControlValueAccessor implementation _value = false; onChange = (value) => { }; onTouched = () => { }; get value() { return this._value; } set value(val) { this._value = val; this.onChange(val); } onButtonClick(event) { if (this.disabled || this.loading) { event.preventDefault(); event.stopPropagation(); return; } // Emit the click event for external bindings this.click.emit(event); // Toggle value for button group usage if (this.type === 'button') { this.value = !this.value; } } writeValue(value) { this._value = value; } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this.disabled = isDisabled; } get buttonClasses() { const baseClasses = 'sui-button'; const sizeClass = `sui-button-${this.size}`; const variantClass = `sui-button-${this.variant}`; const widthClass = this.fullWidth ? 'sui-button-full-width' : ''; const loadingClass = this.loading ? 'sui-button-loading' : ''; return `${baseClasses} ${sizeClass} ${variantClass} ${widthClass} ${loadingClass}`.trim(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: Button, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: Button, isStandalone: true, selector: "sui-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type", fullWidth: "fullWidth", icon: "icon", iconPosition: "iconPosition" }, outputs: { click: "click" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Button), multi: true } ], ngImport: i0, template: "<button \n [type]=\"type\"\n [disabled]=\"disabled || loading\"\n [class]=\"buttonClasses\"\n (click)=\"onButtonClick($event); $event.stopPropagation()\"\n [attr.aria-disabled]=\"disabled || loading\"\n [attr.aria-busy]=\"loading\"\n role=\"button\"\n tabindex=\"0\">\n \n <!-- Loading Spinner -->\n <svg *ngIf=\"loading\" \n class=\"sui-button-spinner\" \n xmlns=\"http://www.w3.org/2000/svg\" \n fill=\"none\" \n viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n\n <!-- Left Icon -->\n <ng-container *ngIf=\"icon && iconPosition === 'left' && !loading\">\n <i class=\"sui-button-icon-left\" [ngClass]=\"icon\"></i>\n </ng-container>\n\n <!-- Button Content -->\n <ng-content></ng-content>\n\n <!-- Right Icon -->\n <ng-container *ngIf=\"icon && iconPosition === 'right' && !loading\">\n <i class=\"sui-button-icon-right\" [ngClass]=\"icon\"></i>\n </ng-container>\n</button>\n", styles: [".sui-button{display:inline-flex;align-items:center;justify-content:center;font-weight:500;transition:all .2s ease-in-out;border-radius:.375rem;border:1px solid transparent;cursor:pointer;text-decoration:none;outline:none;position:relative;overflow:hidden}.sui-button:focus{outline:2px solid transparent;outline-offset:2px}.sui-button:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.sui-button-sm{padding:.375rem .75rem;font-size:.875rem;line-height:1.25rem}.sui-button-md{padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.sui-button-lg{padding:.75rem 1.5rem;font-size:1rem;line-height:1.5rem}.sui-button-primary{background-color:#3b82f6;color:#fff;border-color:#3b82f6}.sui-button-primary:hover:not(:disabled){background-color:#2563eb;border-color:#2563eb}.sui-button-primary:focus{box-shadow:0 0 0 3px #3b82f680}.sui-button-secondary{background-color:#6b7280;color:#fff;border-color:#6b7280}.sui-button-secondary:hover:not(:disabled){background-color:#4b5563;border-color:#4b5563}.sui-button-outline{background-color:transparent;color:#374151;border-color:#d1d5db}.sui-button-outline:hover:not(:disabled){background-color:#f9fafb;border-color:#9ca3af}.sui-button-ghost{background-color:transparent;color:#374151;border-color:transparent}.sui-button-ghost:hover:not(:disabled){background-color:#f3f4f6}.sui-button-danger{background-color:#dc2626;color:#fff;border-color:#dc2626}.sui-button-danger:hover:not(:disabled){background-color:#b91c1c;border-color:#b91c1c}.sui-button-full-width{width:100%}.sui-button-loading{position:relative;color:transparent}.sui-button-loading:after{content:\"\";position:absolute;width:1rem;height:1rem;top:50%;left:50%;margin-left:-.5rem;margin-top:-.5rem;border:2px solid transparent;border-top-color:currentColor;border-radius:50%;animation:sui-button-spin 1s linear infinite}@keyframes sui-button-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: Button, decorators: [{ type: Component, args: [{ selector: 'sui-button', standalone: true, imports: [CommonModule], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Button), multi: true } ], template: "<button \n [type]=\"type\"\n [disabled]=\"disabled || loading\"\n [class]=\"buttonClasses\"\n (click)=\"onButtonClick($event); $event.stopPropagation()\"\n [attr.aria-disabled]=\"disabled || loading\"\n [attr.aria-busy]=\"loading\"\n role=\"button\"\n tabindex=\"0\">\n \n <!-- Loading Spinner -->\n <svg *ngIf=\"loading\" \n class=\"sui-button-spinner\" \n xmlns=\"http://www.w3.org/2000/svg\" \n fill=\"none\" \n viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n\n <!-- Left Icon -->\n <ng-container *ngIf=\"icon && iconPosition === 'left' && !loading\">\n <i class=\"sui-button-icon-left\" [ngClass]=\"icon\"></i>\n </ng-container>\n\n <!-- Button Content -->\n <ng-content></ng-content>\n\n <!-- Right Icon -->\n <ng-container *ngIf=\"icon && iconPosition === 'right' && !loading\">\n <i class=\"sui-button-icon-right\" [ngClass]=\"icon\"></i>\n </ng-container>\n</button>\n", styles: [".sui-button{display:inline-flex;align-items:center;justify-content:center;font-weight:500;transition:all .2s ease-in-out;border-radius:.375rem;border:1px solid transparent;cursor:pointer;text-decoration:none;outline:none;position:relative;overflow:hidden}.sui-button:focus{outline:2px solid transparent;outline-offset:2px}.sui-button:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.sui-button-sm{padding:.375rem .75rem;font-size:.875rem;line-height:1.25rem}.sui-button-md{padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.sui-button-lg{padding:.75rem 1.5rem;font-size:1rem;line-height:1.5rem}.sui-button-primary{background-color:#3b82f6;color:#fff;border-color:#3b82f6}.sui-button-primary:hover:not(:disabled){background-color:#2563eb;border-color:#2563eb}.sui-button-primary:focus{box-shadow:0 0 0 3px #3b82f680}.sui-button-secondary{background-color:#6b7280;color:#fff;border-color:#6b7280}.sui-button-secondary:hover:not(:disabled){background-color:#4b5563;border-color:#4b5563}.sui-button-outline{background-color:transparent;color:#374151;border-color:#d1d5db}.sui-button-outline:hover:not(:disabled){background-color:#f9fafb;border-color:#9ca3af}.sui-button-ghost{background-color:transparent;color:#374151;border-color:transparent}.sui-button-ghost:hover:not(:disabled){background-color:#f3f4f6}.sui-button-danger{background-color:#dc2626;color:#fff;border-color:#dc2626}.sui-button-danger:hover:not(:disabled){background-color:#b91c1c;border-color:#b91c1c}.sui-button-full-width{width:100%}.sui-button-loading{position:relative;color:transparent}.sui-button-loading:after{content:\"\";position:absolute;width:1rem;height:1rem;top:50%;left:50%;margin-left:-.5rem;margin-top:-.5rem;border:2px solid transparent;border-top-color:currentColor;border-radius:50%;animation:sui-button-spin 1s linear infinite}@keyframes sui-button-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }] }], propDecorators: { variant: [{ type: Input }], size: [{ type: Input }], disabled: [{ type: Input }], loading: [{ type: Input }], type: [{ type: Input }], fullWidth: [{ type: Input }], icon: [{ type: Input }], iconPosition: [{ type: Input }], click: [{ type: Output }] } }); class InputText { placeholder = ''; disabled = false; readonly = false; required = false; size = 'md'; variant = 'default'; validationState = 'none'; errorMessage = ''; helperText = ''; label = ''; type = 'text'; maxlength = null; minlength = null; pattern = null; autocomplete = null; autofocus = false; spellcheck = true; prefix = null; suffix = null; clearable = false; showPasswordToggle = false; blur = new EventEmitter(); focus = new EventEmitter(); input = new EventEmitter(); clear = new EventEmitter(); // ControlValueAccessor implementation _value = ''; onChange = (value) => { }; onTouched = () => { }; // Internal state _showPassword = false; _focused = false; get value() { return this._value; } set value(val) { this._value = val; this.onChange(val); } get showPassword() { return this._showPassword; } get focused() { return this._focused; } get inputType() { if (this.type === 'password' && this.showPasswordToggle) { return this._showPassword ? 'text' : 'password'; } return this.type; } ngOnInit() { // Component initialization } ngOnDestroy() { // Cleanup } onInput(event) { const target = event.target; this.value = target.value; this.input.emit(event); } onBlur(event) { this._focused = false; this.onTouched(); this.blur.emit(event); } onFocus(event) { this._focused = true; this.focus.emit(event); } onClear() { this.value = ''; this.clear.emit(); } togglePasswordVisibility() { this._showPassword = !this._showPassword; } writeValue(value) { this._value = value || ''; } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this.disabled = isDisabled; } get inputClasses() { const baseClasses = 'sui-input-text'; const sizeClass = `sui-input-text-${this.size}`; const variantClass = `sui-input-text-${this.variant}`; const stateClass = this.validationState !== 'none' ? `sui-input-text-${this.validationState}` : ''; const disabledClass = this.disabled ? 'sui-input-text-disabled' : ''; const readonlyClass = this.readonly ? 'sui-input-text-readonly' : ''; return `${baseClasses} ${sizeClass} ${variantClass} ${stateClass} ${disabledClass} ${readonlyClass}`.trim(); } get containerClasses() { return 'relative'; } get hasValue() { return !!(this.value && this.value.length > 0); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: InputText, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: InputText, isStandalone: true, selector: "sui-input-text", inputs: { placeholder: "placeholder", disabled: "disabled", readonly: "readonly", required: "required", size: "size", variant: "variant", validationState: "validationState", errorMessage: "errorMessage", helperText: "helperText", label: "label", type: "type", maxlength: "maxlength", minlength: "minlength", pattern: "pattern", autocomplete: "autocomplete", autofocus: "autofocus", spellcheck: "spellcheck", prefix: "prefix", suffix: "suffix", clearable: "clearable", showPasswordToggle: "showPasswordToggle" }, outputs: { blur: "blur", focus: "focus", input: "input", clear: "clear" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputText), multi: true } ], ngImport: i0, template: "<div class=\"sui-input-text-container\">\n <!-- Label -->\n <label *ngIf=\"label\" \n [for]=\"label\"\n class=\"sui-input-text-label\">\n {{ label }}\n <span *ngIf=\"required\" class=\"sui-input-text-required\">*</span>\n </label>\n\n <!-- Input Container -->\n <div class=\"sui-input-text-wrapper\">\n <!-- Prefix -->\n <div *ngIf=\"prefix\" \n class=\"sui-input-text-prefix\">\n <span>{{ prefix }}</span>\n </div>\n\n <!-- Input Field -->\n <input\n [type]=\"inputType\"\n [value]=\"value\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [attr.maxlength]=\"maxlength\"\n [attr.minlength]=\"minlength\"\n [attr.pattern]=\"pattern\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.autofocus]=\"autofocus\"\n [attr.spellcheck]=\"spellcheck\"\n [class]=\"inputClasses\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur($event)\"\n (focus)=\"onFocus($event)\"\n [attr.aria-invalid]=\"validationState === 'invalid'\"\n [attr.aria-describedby]=\"(errorMessage || helperText) ? (label + '-description') : null\"\n role=\"textbox\"\n tabindex=\"0\">\n\n <!-- Suffix / Clear Button / Password Toggle -->\n <div class=\"sui-input-text-suffix\">\n <!-- Clear Button -->\n <button *ngIf=\"clearable && hasValue && !disabled && !readonly\"\n type=\"button\"\n (click)=\"onClear()\"\n class=\"sui-input-text-clear\"\n aria-label=\"Clear input\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n </button>\n\n <!-- Password Toggle -->\n <button *ngIf=\"type === 'password' && showPasswordToggle && !disabled && !readonly\"\n type=\"button\"\n (click)=\"togglePasswordVisibility()\"\n class=\"sui-input-text-password-toggle\"\n [attr.aria-label]=\"showPassword ? 'Hide password' : 'Show password'\">\n <svg *ngIf=\"!showPassword\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"></path>\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z\"></path>\n </svg>\n <svg *ngIf=\"showPassword\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21\"></path>\n </svg>\n </button>\n\n <!-- Suffix -->\n <span *ngIf=\"suffix\" class=\"sui-input-text-suffix-text\">{{ suffix }}</span>\n </div>\n </div>\n\n <!-- Helper Text / Error Message -->\n <div *ngIf=\"errorMessage || helperText\" \n [id]=\"label + '-description'\"\n class=\"sui-input-text-helper\"\n [class.sui-input-text-error]=\"validationState === 'invalid'\">\n {{ errorMessage || helperText }}\n </div>\n</div>\n", styles: [".sui-input-text-container{width:100%;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif}.sui-input-text-label{display:inline-block;font-size:.875rem;font-weight:600;color:var(--sui-gray-700, #374151);margin-bottom:.5rem;letter-spacing:.01em;transition:color .2s ease}.sui-input-text-label .sui-input-text-required{color:var(--sui-danger-500, #ef4444);margin-left:.125rem;font-weight:700}.sui-input-text-wrapper{position:relative;display:flex;align-items:center;width:100%}.sui-input-text{width:100%;border:2px solid var(--sui-gray-300, #d1d5db);border-radius:.5rem;padding:.625rem .875rem;font-size:.9375rem;font-weight:400;line-height:1.5;color:var(--sui-gray-900, #111827);background-color:var(--sui-white, #ffffff);transition:all .2s cubic-bezier(.4,0,.2,1);outline:none;box-shadow:0 1px 2px #00000008}.sui-input-text::placeholder{color:var(--sui-gray-400, #9ca3af);opacity:1;transition:opacity .2s ease}.sui-input-text:hover:not(:disabled):not(:read-only){border-color:var(--sui-gray-400, #9ca3af);box-shadow:0 1px 3px #00000014}.sui-input-text:focus{border-color:var(--sui-primary-500, #3b82f6);box-shadow:0 0 0 4px #3b82f61f,0 1px 3px #0000001a;background-color:var(--sui-white, #ffffff)}.sui-input-text:focus::placeholder{opacity:.6}.sui-input-text:disabled{background-color:var(--sui-gray-50, #f9fafb);border-color:var(--sui-gray-200, #e5e7eb);color:var(--sui-gray-500, #6b7280);cursor:not-allowed;box-shadow:none;opacity:.7}.sui-input-text:read-only{background-color:var(--sui-gray-50, #f9fafb);border-color:var(--sui-gray-200, #e5e7eb);cursor:default;box-shadow:none}.sui-input-text-sm{padding:.5rem .75rem;font-size:.8125rem;border-radius:.375rem;line-height:1.4}.sui-input-text-md{padding:.625rem .875rem;font-size:.9375rem;border-radius:.5rem;line-height:1.5}.sui-input-text-lg{padding:.875rem 1.125rem;font-size:1rem;border-radius:.625rem;line-height:1.6;font-weight:500}.sui-input-text-filled{background-color:var(--sui-gray-100, #f3f4f6);border-color:transparent;box-shadow:inset 0 1px 2px #0000000d}.sui-input-text-filled:hover:not(:disabled):not(:read-only){background-color:var(--sui-gray-200, #e5e7eb);border-color:transparent}.sui-input-text-filled:focus{background-color:var(--sui-white, #ffffff);border-color:var(--sui-primary-500, #3b82f6);box-shadow:0 0 0 4px #3b82f61f,inset 0 1px 2px #0000000d}.sui-input-text-outlined{background-color:transparent;border-width:2px;border-color:var(--sui-gray-300, #d1d5db)}.sui-input-text-outlined:focus{background-color:var(--sui-white, #ffffff)}.sui-input-text-valid{border-color:var(--sui-success-500, #10b981);background-color:#10b98105}.sui-input-text-valid:focus{border-color:var(--sui-success-600, #059669);box-shadow:0 0 0 4px #10b9811f,0 1px 3px #0000001a}.sui-input-text-valid:hover:not(:disabled):not(:read-only){border-color:var(--sui-success-600, #059669)}.sui-input-text-invalid{border-color:var(--sui-danger-500, #ef4444);background-color:#ef444405}.sui-input-text-invalid:focus{border-color:var(--sui-danger-600, #dc2626);box-shadow:0 0 0 4px #ef44441f,0 1px 3px #0000001a}.sui-input-text-invalid:hover:not(:disabled):not(:read-only){border-color:var(--sui-danger-600, #dc2626)}.sui-input-text-prefix,.sui-input-text-suffix{position:absolute;display:flex;align-items:center;gap:.375rem;pointer-events:none;z-index:1}.sui-input-text-prefix{left:.875rem;font-size:.9375rem;font-weight:500;color:var(--sui-gray-500, #6b7280)}.sui-input-text-prefix+.sui-input-text{padding-left:2.5rem}.sui-input-text-suffix{right:.875rem;pointer-events:auto}.sui-input-text-suffix-text{font-size:.9375rem;font-weight:500;color:var(--sui-gray-500, #6b7280)}.sui-input-text-clear,.sui-input-text-password-toggle{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;background:transparent;border:none;border-radius:.375rem;color:var(--sui-gray-500, #6b7280);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);pointer-events:auto}.sui-input-text-clear svg,.sui-input-text-password-toggle svg{width:1rem;height:1rem;stroke-width:2.5}.sui-input-text-clear:hover,.sui-input-text-password-toggle:hover{color:var(--sui-gray-700, #374151);background-color:var(--sui-gray-100, #f3f4f6);transform:scale(1.05)}.sui-input-text-clear:active,.sui-input-text-password-toggle:active{transform:scale(.95);background-color:var(--sui-gray-200, #e5e7eb)}.sui-input-text-clear:focus-visible,.sui-input-text-password-toggle:focus-visible{outline:2px solid var(--sui-primary-500, #3b82f6);outline-offset:2px}.sui-input-text-wrapper:has(.sui-input-text-clear) .sui-input-text,.sui-input-text-wrapper:has(.sui-input-text-password-toggle) .sui-input-text{padding-right:2.75rem}.sui-input-text-wrapper:has(.sui-input-text-suffix-text) .sui-input-text{padding-right:3rem}.sui-input-text-helper{display:block;margin-top:.375rem;font-size:.8125rem;line-height:1.4;color:var(--sui-gray-600, #4b5563);font-weight:400;transition:color .2s ease}.sui-input-text-helper.sui-input-text-error{color:var(--sui-danger-600, #dc2626);font-weight:500}.sui-input-text-disabled .sui-input-text-label{color:var(--sui-gray-500, #6b7280);opacity:.7}.sui-input-text-readonly .sui-input-text-label{color:var(--sui-gray-600, #4b5563)}.sui-input-text-wrapper:focus-within .sui-input-text-prefix,.sui-input-text-wrapper:focus-within .sui-input-text-suffix-text{color:var(--sui-primary-600, #2563eb)}@keyframes shake{0%,to{transform:translate(0)}25%{transform:translate(-4px)}75%{transform:translate(4px)}}.sui-input-text-invalid:focus{animation:shake .3s ease-in-out}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: InputText, decorators: [{ type: Component, args: [{ selector: 'sui-input-text', standalone: true, imports: [CommonModule], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputText), multi: true } ], template: "<div class=\"sui-input-text-container\">\n <!-- Label -->\n <label *ngIf=\"label\" \n [for]=\"label\"\n class=\"sui-input-text-label\">\n {{ label }}\n <span *ngIf=\"required\" class=\"sui-input-text-required\">*</span>\n </label>\n\n <!-- Input Container -->\n <div class=\"sui-input-text-wrapper\">\n <!-- Prefix -->\n <div *ngIf=\"prefix\" \n class=\"sui-input-text-prefix\">\n <span>{{ prefix }}</span>\n </div>\n\n <!-- Input Field -->\n <input\n [type]=\"inputType\"\n [value]=\"value\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [attr.maxlength]=\"maxlength\"\n [attr.minlength]=\"minlength\"\n [attr.pattern]=\"pattern\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.autofocus]=\"autofocus\"\n [attr.spellcheck]=\"spellcheck\"\n [class]=\"inputClasses\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur($event)\"\n (focus)=\"onFocus($event)\"\n [attr.aria-invalid]=\"validationState === 'invalid'\"\n [attr.aria-describedby]=\"(errorMessage || helperText) ? (label + '-description') : null\"\n role=\"textbox\"\n tabindex=\"0\">\n\n <!-- Suffix / Clear Button / Password Toggle -->\n <div class=\"sui-input-text-suffix\">\n <!-- Clear Button -->\n <button *ngIf=\"clearable && hasValue && !disabled && !readonly\"\n type=\"button\"\n (click)=\"onClear()\"\n class=\"sui-input-text-clear\"\n aria-label=\"Clear input\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n </button>\n\n <!-- Password Toggle -->\n <button *ngIf=\"type === 'password' && showPasswordToggle && !disabled && !readonly\"\n type=\"button\"\n (click)=\"togglePasswordVisibility()\"\n class=\"sui-input-text-password-toggle\"\n [attr.aria-label]=\"showPassword ? 'Hide password' : 'Show password'\">\n <svg *ngIf=\"!showPassword\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"></path>\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z\"></path>\n </svg>\n <svg *ngIf=\"showPassword\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21\"></path>\n </svg>\n </button>\n\n <!-- Suffix -->\n <span *ngIf=\"suffix\" class=\"sui-input-text-suffix-text\">{{ suffix }}</span>\n </div>\n </div>\n\n <!-- Helper Text / Error Message -->\n <div *ngIf=\"errorMessage || helperText\" \n [id]=\"label + '-description'\"\n class=\"sui-input-text-helper\"\n [class.sui-input-text-error]=\"validationState === 'invalid'\">\n {{ errorMessage || helperText }}\n </div>\n</div>\n", styles: [".sui-input-text-container{width:100%;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif}.sui-input-text-label{display:inline-block;font-size:.875rem;font-weight:600;color:var(--sui-gray-700, #374151);margin-bottom:.5rem;letter-spacing:.01em;transition:color .2s ease}.sui-input-text-label .sui-input-text-required{color:var(--sui-danger-500, #ef4444);margin-left:.125rem;font-weight:700}.sui-input-text-wrapper{position:relative;display:flex;align-items:center;width:100%}.sui-input-text{width:100%;border:2px solid var(--sui-gray-300, #d1d5db);border-radius:.5rem;padding:.625rem .875rem;font-size:.9375rem;font-weight:400;line-height:1.5;color:var(--sui-gray-900, #111827);background-color:var(--sui-white, #ffffff);transition:all .2s cubic-bezier(.4,0,.2,1);outline:none;box-shadow:0 1px 2px #00000008}.sui-input-text::placeholder{color:var(--sui-gray-400, #9ca3af);opacity:1;transition:opacity .2s ease}.sui-input-text:hover:not(:disabled):not(:read-only){border-color:var(--sui-gray-400, #9ca3af);box-shadow:0 1px 3px #00000014}.sui-input-text:focus{border-color:var(--sui-primary-500, #3b82f6);box-shadow:0 0 0 4px #3b82f61f,0 1px 3px #0000001a;background-color:var(--sui-white, #ffffff)}.sui-input-text:focus::placeholder{opacity:.6}.sui-input-text:disabled{background-color:var(--sui-gray-50, #f9fafb);border-color:var(--sui-gray-200, #e5e7eb);color:var(--sui-gray-500, #6b7280);cursor:not-allowed;box-shadow:none;opacity:.7}.sui-input-text:read-only{background-color:var(--sui-gray-50, #f9fafb);border-color:var(--sui-gray-200, #e5e7eb);cursor:default;box-shadow:none}.sui-input-text-sm{padding:.5rem .75rem;font-size:.8125rem;border-radius:.375rem;line-height:1.4}.sui-input-text-md{padding:.625rem .875rem;font-size:.9375rem;border-radius:.5rem;line-height:1.5}.sui-input-text-lg{padding:.875rem 1.125rem;font-size:1rem;border-radius:.625rem;line-height:1.6;font-weight:500}.sui-input-text-filled{background-color:var(--sui-gray-100, #f3f4f6);border-color:transparent;box-shadow:inset 0 1px 2px #0000000d}.sui-input-text-filled:hover:not(:disabled):not(:read-only){background-color:var(--sui-gray-200, #e5e7eb);border-color:transparent}.sui-input-text-filled:focus{background-color:var(--sui-white, #ffffff);border-color:var(--sui-primary-500, #3b82f6);box-shadow:0 0 0 4px #3b82f61f,inset 0 1px 2px #0000000d}.sui-input-text-outlined{background-color:transparent;border-width:2px;border-color:var(--sui-gray-300, #d1d5db)}.sui-input-text-outlined:focus{background-color:var(--sui-white, #ffffff)}.sui-input-text-valid{border-color:var(--sui-success-500, #10b981);background-color:#10b98105}.sui-input-text-valid:focus{border-color:var(--sui-success-600, #059669);box-shadow:0 0 0 4px #10b9811f,0 1px 3px #0000001a}.sui-input-text-valid:hover:not(:disabled):not(:read-only){border-color:var(--sui-success-600, #059669)}.sui-input-text-invalid{border-color:var(--sui-danger-500, #ef4444);background-color:#ef444405}.sui-input-text-invalid:focus{border-color:var(--sui-danger-600, #dc2626);box-shadow:0 0 0 4px #ef44441f,0 1px 3px #0000001a}.sui-input-text-invalid:hover:not(:disabled):not(:read-only){border-color:var(--sui-danger-600, #dc2626)}.sui-input-text-prefix,.sui-input-text-suffix{position:absolute;display:flex;align-items:center;gap:.375rem;pointer-events:none;z-index:1}.sui-input-text-prefix{left:.875rem;font-size:.9375rem;font-weight:500;color:var(--sui-gray-500, #6b7280)}.sui-input-text-prefix+.sui-input-text{padding-left:2.5rem}.sui-input-text-suffix{right:.875rem;pointer-events:auto}.sui-input-text-suffix-text{font-size:.9375rem;font-weight:500;color:var(--sui-gray-500, #6b7280)}.sui-input-text-clear,.sui-input-text-password-toggle{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;background:transparent;border:none;border-radius:.375rem;color:var(--sui-gray-500, #6b7280);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);pointer-events:auto}.sui-input-text-clear svg,.sui-input-text-password-toggle svg{width:1rem;height:1rem;stroke-width:2.5}.sui-input-text-clear:hover,.sui-input-text-password-toggle:hover{color:var(--sui-gray-700, #374151);background-color:var(--sui-gray-100, #f3f4f6);transform:scale(1.05)}.sui-input-text-clear:active,.sui-input-text-password-toggle:active{transform:scale(.95);background-color:var(--sui-gray-200, #e5e7eb)}.sui-input-text-clear:focus-visible,.sui-input-text-password-toggle:focus-visible{outline:2px solid var(--sui-primary-500, #3b82f6);outline-offset:2px}.sui-input-text-wrapper:has(.sui-input-text-clear) .sui-input-text,.sui-input-text-wrapper:has(.sui-input-text-password-toggle) .sui-input-text{padding-right:2.75rem}.sui-input-text-wrapper:has(.sui-input-text-suffix-text) .sui-input-text{padding-right:3rem}.sui-input-text-helper{display:block;margin-top:.375rem;font-size:.8125rem;line-height:1.4;color:var(--sui-gray-600, #4b5563);font-weight:400;transition:color .2s ease}.sui-input-text-helper.sui-input-text-error{color:var(--sui-danger-600, #dc2626);font-weight:500}.sui-input-text-disabled .sui-input-text-label{color:var(--sui-gray-500, #6b7280);opacity:.7}.sui-input-text-readonly .sui-input-text-label{color:var(--sui-gray-600, #4b5563)}.sui-input-text-wrapper:focus-within .sui-input-text-prefix,.sui-input-text-wrapper:focus-within .sui-input-text-suffix-text{color:var(--sui-primary-600, #2563eb)}@keyframes shake{0%,to{transform:translate(0)}25%{transform:translate(-4px)}75%{transform:translate(4px)}}.sui-input-text-invalid:focus{animation:shake .3s ease-in-out}\n"] }] }], propDecorators: { placeholder: [{ type: Input }], disabled: [{ type: Input }], readonly: [{ type: Input }], required: [{ type: Input }], size: [{ type: Input }], variant: [{ type: Input }], validationState: [{ type: Input }], errorMessage: [{ type: Input }], helperText: [{ type: Input }], label: [{ type: Input }], type: [{ type: Input }], maxlength: [{ type: Input }], minlength: [{ type: Input }], pattern: [{ type: Input }], autocomplete: [{ type: Input }], autofocus: [{ type: Input }], spellcheck: [{ type: Input }], prefix: [{ type: Input }], suffix: [{ type: Input }], clearable: [{ type: Input }], showPasswordToggle: [{ type: Input }], blur: [{ type: Output }], focus: [{ type: Output }], input: [{ type: Output }], clear: [{ type: Output }] } }); class Card { variant = 'default'; size = 'md'; clickable = false; disabled = false; header = ''; subheader = ''; showHeader = true; showFooter = false; loading = false; hoverable = false; borderless = false; click = new EventEmitter(); headerClick = new EventEmitter(); onCardClick(event) { if (this.disabled || this.loading || !this.clickable) { return; } this.click.emit(event); } onHeaderClick(event) { if (this.disabled || this.loading) { return; } this.headerClick.emit(event); } get cardClasses() { const baseClasses = 'sui-card'; const sizeClass = `sui-card-${this.size}`; const variantClass = `sui-card-${this.variant}`; const interactiveClass = this.clickable && !this.disabled ? 'sui-card-clickable' : ''; const hoverClass = this.hoverable && !this.disabled ? 'sui-card-hoverable' : ''; const disabledClass = this.disabled ? 'sui-card-disabled' : ''; const borderlessClass = this.borderless ? 'sui-card-borderless' : ''; return `${baseClasses} ${sizeClass} ${variantClass} ${interactiveClass} ${hoverClass} ${disabledClass} ${borderlessClass}`.trim(); } get headerClasses() { const baseClasses = 'font-semibold text-gray-900'; const sizeClasses = { sm: 'text-base', md: 'text-lg', lg: 'text-xl' }; const clickableClasses = this.clickable ? 'cursor-pointer hover:text-primary-600' : ''; return `${baseClasses} ${sizeClasses[this.size]} ${clickableClasses}`.trim(); } get subheaderClasses() { return 'text-sm text-gray-600 mt-1'; } get contentClasses() { const sizeClasses = { sm: 'mt-3', md: 'mt-4', lg: 'mt-6' }; return `${sizeClasses[this.size]}`; } get footerClasses() { const sizeClasses = { sm: 'mt-3 pt-3', md: 'mt-4 pt-4', lg: 'mt-6 pt-6' }; return `border-t border-gray-200 ${sizeClasses[this.size]}`; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: Card, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: Card, isStandalone: true, selector: "sui-card", inputs: { variant: "variant", size: "size", clickable: "clickable", disabled: "disabled", header: "header", subheader: "subheader", showHeader: "showHeader", showFooter: "showFooter", loading: "loading", hoverable: "hoverable", borderless: "borderless" }, outputs: { click: "click", headerClick: "headerClick" }, ngImport: i0, template: "<div [class]=\"cardClasses\" \n (click)=\"onCardClick($event)\"\n [attr.role]=\"clickable ? 'button' : null\"\n [attr.tabindex]=\"clickable && !disabled ? '0' : null\"\n [attr.aria-disabled]=\"disabled\"\n [attr.aria-busy]=\"loading\">\n\n <!-- Loading Overlay -->\n <div *ngIf=\"loading\" class=\"sui-card-loading-overlay\">\n <svg class=\"sui-card-loading-spinner\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n </div>\n\n <!-- Card Header -->\n <div *ngIf=\"showHeader && (header || subheader)\" \n (click)=\"onHeaderClick($event)\"\n class=\"mb-0\">\n <h3 *ngIf=\"header\" [class]=\"headerClasses\">\n {{ header }}\n </h3>\n <p *ngIf=\"subheader\" [class]=\"subheaderClasses\">\n {{ subheader }}\n </p>\n </div>\n\n <!-- Card Content -->\n <div [class]=\"contentClasses\">\n <ng-content></ng-content>\n </div>\n\n <!-- Card Footer -->\n <div *ngIf=\"showFooter\" [class]=\"footerClasses\">\n <ng-content select=\"[slot=footer]\"></ng-content>\n </div>\n</div>\n", styles: [".sui-card{position:relative;display:block;background-color:var(--sui-gray-50, #ffffff);border:1px solid var(--sui-gray-200, #e5e7eb);border-radius:.5rem;padding:1rem;transition:all .2s ease-in-out}.sui-card-default{background-color:var(--sui-gray-50, #ffffff);border:1px solid var(--sui-gray-200, #e5e7eb)}.sui-card-outlined{background-color:transparent;border:2px solid var(--sui-primary-200, #bfdbfe)}.sui-card-elevated{background-color:var(--sui-gray-50, #ffffff);border:1px solid var(--sui-gray-200, #e5e7eb);box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.sui-card-filled{background-color:var(--sui-primary-50, #eff6ff);border:1px solid var(--sui-primary-200, #bfdbfe)}.sui-card-sm{padding:.75rem}.sui-card-md{padding:1rem}.sui-card-lg{padding:1.5rem}.sui-card-clickable{cursor:pointer}.sui-card-clickable:hover,.sui-card-hoverable:hover{border-color:var(--sui-primary-300, #93c5fd);box-shadow:0 2px 4px -1px #0000001a}.sui-card-disabled{opacity:.6;cursor:not-allowed}.sui-card-borderless{border:none}.sui-card-loading-overlay{position:absolute;inset:0;background-color:#ffffffbf;display:flex;align-items:center;justify-content:center;border-radius:.5rem;z-index:10}.sui-card-loading-spinner{animation:spin 1s linear infinite;width:1.5rem;height:1.5rem;color:var(--sui-primary-600, #2563eb)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: Card, decorators: [{ type: Component, args: [{ selector: 'sui-card', standalone: true, imports: [CommonModule], template: "<div [class]=\"cardClasses\" \n (click)=\"onCardClick($event)\"\n [attr.role]=\"clickable ? 'button' : null\"\n [attr.tabindex]=\"clickable && !disabled ? '0' : null\"\n [attr.aria-disabled]=\"disabled\"\n [attr.aria-busy]=\"loading\">\n\n <!-- Loading Overlay -->\n <div *ngIf=\"loading\" class=\"sui-card-loading-overlay\">\n <svg class=\"sui-card-loading-spinner\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n </div>\n\n <!-- Card Header -->\n <div *ngIf=\"showHeader && (header || subheader)\" \n (click)=\"onHeaderClick($event)\"\n class=\"mb-0\">\n <h3 *ngIf=\"header\" [class]=\"headerClasses\">\n {{ header }}\n </h3>\n <p *ngIf=\"subheader\" [class]=\"subheaderClasses\">\n {{ subheader }}\n </p>\n </div>\n\n <!-- Card Content -->\n <div [class]=\"contentClasses\">\n <ng-content></ng-content>\n </div>\n\n <!-- Card Footer -->\n <div *ngIf=\"showFooter\" [class]=\"footerClasses\">\n <ng-content select=\"[slot=footer]\"></ng-content>\n </div>\n</div>\n", styles: [".sui-card{position:relative;display:block;background-color:var(--sui-gray-50, #ffffff);border:1px solid var(--sui-gray-200, #e5e7eb);border-radius:.5rem;padding:1rem;transition:all .2s ease-in-out}.sui-card-default{background-color:var(--sui-gray-50, #ffffff);border:1px solid var(--sui-gray-200, #e5e7eb)}.sui-card-outlined{background-color:transparent;border:2px solid var(--sui-primary-200, #bfdbfe)}.sui-card-elevated{background-color:var(--sui-gray-50, #ffffff);border:1px solid var(--sui-gray-200, #e5e7eb);box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.sui-card-filled{background-color:var(--sui-primary-50, #eff6ff);border:1px solid var(--sui-primary-200, #bfdbfe)}.sui-card-sm{padding:.75rem}.sui-card-md{padding:1rem}.sui-card-lg{padding:1.5rem}.sui-card-clickable{cursor:pointer}.sui-card-clickable:hover,.sui-card-hoverable:hover{border-color:var(--sui-primary-300, #93c5fd);box-shadow:0 2px 4px -1px #0000001a}.sui-card-disabled{opacity:.6;cursor:not-allowed}.sui-card-borderless{border:none}.sui-card-loading-overlay{position:absolute;inset:0;background-color:#ffffffbf;display:flex;align-items:center;justify-content:center;border-radius:.5rem;z-index:10}.sui-card-loading-spinner{animation:spin 1s linear infinite;width:1.5rem;height:1.5rem;color:var(--sui-primary-600, #2563eb)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }] }], propDecorators: { variant: [{ type: Input }], size: [{ type: Input }], clickable: [{ type: Input }], disabled: [{ type: Input }], header: [{ type: Input }], subheader: [{ type: Input }], showHeader: [{ type: Input }], showFooter: [{ type: Input }], loading: [{ type: Input }], hoverable: [{ type: Input }], borderless: [{ type: Input }], click: [{ type: Output }], headerClick: [{ type: Output }] } }); class AutoComplete { disabled = false; name = ''; inputId = ''; placeholder = ''; minLength = 1; options = []; change = new EventEmitter(); value = ''; term = ''; open = false; activeIndex = -1; onChange = () => { }; onTouched = () => { }; writeValue(obj) { this.value = obj ?? ''; this.term = this.displayValue(this.value); } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this.disabled = isDisabled; } onInput(event) { const input = event.target; this.term = input.value ?? ''; this.open = this.term.length >= this.minLength && this.filtered.length > 0; this.activeIndex = this.filtered.length ? 0 : -1; } onFocus() { this.open = this.term.length >= this.minLength && this.filtered.length > 0; } onBlur() { this.onTouched(); // Add a small delay to allow click events to be processed before closing setTimeout(() => { this.open = false; }, 150); } onKeyDown(event) { if (!this.open) return; if (event.key === 'ArrowDown') { event.preventDefault(); this.activeIndex = Math.min(this.activeIndex + 1, this.filtered.length - 1); } else if (event.key === 'ArrowUp') { event.preventDefault(); this.activeIndex = Math.max(this.activeIndex - 1, 0); } else if (event.key === 'Enter') { event.preventDefault(); if (this.activeIndex >= 0) this.select(this.filtered[this.activeIndex]); } else if (event.key === 'Escape') { this.open = false; } } select(item) { if (this.disabled) return; const val = this.resolveValue(item); this.value = val; this.term = this.displayValue(val); this.onChange(this.value); this.change.emit(this.value); this.open = false; } clear() { if (this.disabled) return; this.value = ''; this.term = ''; this.onChange(this.value); this.change.emit(this.value); } get filtered() { const t = (this.term || '').toLowerCase(); if (!t) return []; return this.options.filter(opt => this.displayItem(opt).toLowerCase().includes(t)); } displayItem(item) { return typeof item === 'string' ? item : item.label ?? ''; } resolveValue(item) { return typeof item === 'string' ? item : item.value; } displayValue(val) { if (typeof val === 'string') return val; const match = this.options.find(o => typeof o !== 'string' && o.value === val); return match?.label ?? ''; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AutoComplete, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.3", type: AutoComplete, isStandalone: true, selector: "sui-auto-complete", inputs: { disabled: "disabled", name: "name", inputId: "inputId", placeholder: "placeholder", minLength: "minLength", options: "options" }, outputs: { change: "change" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AutoComplete), multi: true } ], ngImport: i0, template: "<div class=\"sui-auto-complete\">\n\t<input\n\t\t[type]=\"'text'\"\n\t\t[id]=\"inputId\"\n\t\t[name]=\"name\"\n\t\t[disabled]=\"disabled\"\n\t\t[placeholder]=\"placeholder\"\n\t\t[value]=\"term\"\n\t\t(input)=\"onInput($event)\"\n\t\t(focus)=\"onFocus()\"\n\t\t(blur)=\"onBlur()\"\n\t\t(keydown)=\"onKeyDown($event)\"\n\t/>\n\t<button *ngIf=\"term && !disabled\" type=\"button\" (click)=\"clear()\" class=\"clear-button\">\u00D7</button>\n\t<ul *ngIf=\"open\" class=\"dropdown\">\n\t\t<li\n\t\t\t*ngFor=\"let item of filtered; let i = index\"\n\t\t\t(click)=\"select(item)\"\n\t\t\t(mousedown)=\"$event.preventDefault()\"\n\t\t\t[class.active]=\"i === activeIndex\"\n\t\t\tclass=\"dropdown-item\"\n\t\t>\n\t\t\t{{ displayItem(item) }}\n\t\t</li>\n\t</ul>\n</div>\n", styles: [".sui-auto-complete{position:relative;display:block;width:100%}.sui-auto-complete input{width:100%;padding:var(--sui-input-padding-y, .5rem) var(--sui-input-padding-x, .75rem);border:var(--sui-input-border-width, 1px) solid var(--sui-input-border-color, #d1d5db);border-radius:var(--sui-input-border-radius, .375rem);background-color:var(--sui-input-bg, #ffffff);color:var(--sui-input-text-color, #111827);font-size:var(--sui-input-font-size, .875rem);line-height:var(--sui-input-line-height, 1.25rem);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.sui-auto-complete input:focus{outline:none;border-color:var(--sui-input-focus-border-color, #3b82f6);box-shadow:0 0 0 3px var(--sui-input-focus-ring-color, rgba(59, 130, 246, .1))}.sui-auto-complete input:disabled{background-color:var(--sui-input-disabled-bg, #f9fafb);color:var(--sui-input-disabled-text-color, #9ca3af);cursor:not-allowed}.sui-auto-complete input::placeholder{color:var(--sui-input-placeholder-color, #9ca3af)}.sui-auto-complete .clear-button{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--sui-input-clear-button-color, #9ca3af);font-size:1.25rem;cursor:pointer;padding:.25rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out}.sui-auto-complete .clear-button:hover{color:var(--sui-input-clear-button-hover-color, #6b7280);background-color:var(--sui-input-clear-button-hover-bg, #f3f4f6)}.sui-auto-complete .clear-button:focus{outline:none;color:var(--s