fn-input 0.0.8 → 0.0.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.
package/fesm2022/fn-input.mjs
CHANGED
|
@@ -902,6 +902,16 @@ class FNInput {
|
|
|
902
902
|
}
|
|
903
903
|
});
|
|
904
904
|
}
|
|
905
|
+
prefixClick(e) {
|
|
906
|
+
if (this.field.prefix?.onClick) {
|
|
907
|
+
this.field.prefix.onClick(e);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
suffixClick(e) {
|
|
911
|
+
if (this.field.suffix?.onClick) {
|
|
912
|
+
this.field.suffix.onClick(e);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
905
915
|
/**
|
|
906
916
|
* Set up visibility condition listener
|
|
907
917
|
* Watches the dependent field and shows/hides this field based on conditions
|
|
@@ -1040,13 +1050,24 @@ class FNInput {
|
|
|
1040
1050
|
loadIconToContainer(container, name, variant, sizeName, color, disabled) {
|
|
1041
1051
|
const size = this.sizeMap[sizeName];
|
|
1042
1052
|
// 1. Check if raw SVG string is provided
|
|
1043
|
-
|
|
1044
|
-
|
|
1053
|
+
const trimmedName = name.trim();
|
|
1054
|
+
if (trimmedName.startsWith('<svg')) {
|
|
1055
|
+
this.renderSvgToContainer(container, trimmedName, color, size, 'custom', disabled);
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
// 1b. Check if it's just raw SVG inner content (like `<path ...>`)
|
|
1059
|
+
if (trimmedName.startsWith('<path') ||
|
|
1060
|
+
trimmedName.startsWith('<g') ||
|
|
1061
|
+
trimmedName.startsWith('<circle') ||
|
|
1062
|
+
trimmedName.startsWith('<rect') ||
|
|
1063
|
+
trimmedName.startsWith('<polygon')) {
|
|
1064
|
+
const wrappedSvg = `<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">${trimmedName}</svg>`;
|
|
1065
|
+
this.renderSvgToContainer(container, wrappedSvg, color, size, 'custom', disabled);
|
|
1045
1066
|
return;
|
|
1046
1067
|
}
|
|
1047
1068
|
// 2. Check built-in icons registry
|
|
1048
1069
|
// Strip possible --size suffix if it was passed by mistake from old logic
|
|
1049
|
-
const baseName =
|
|
1070
|
+
const baseName = trimmedName.split('--')[0].trim();
|
|
1050
1071
|
if (CORE_ICONS[baseName]) {
|
|
1051
1072
|
this.renderSvgToContainer(container, CORE_ICONS[baseName], color, size, baseName, disabled);
|
|
1052
1073
|
return;
|
|
@@ -1149,11 +1170,11 @@ class FNInput {
|
|
|
1149
1170
|
return !!(this.control?.valid && this.control?.touched);
|
|
1150
1171
|
}
|
|
1151
1172
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FNInput, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1152
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FNInput, isStandalone: true, selector: "fn-input", inputs: { field: "field", helperHandle: "helperHandle", toastService: "toastService", currencyMeta: "currencyMeta", defaultLocale: "defaultLocale", form: "form" }, outputs: { valueChange: "valueChange", fieldBlur: "fieldBlur" }, viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["fnTextarea"], descendants: true }, { propertyName: "iconContainers", predicate: ["iconContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (field.name && isVisible() && !field.hidden) {\r\n <div class=\"fn-input-container\">\r\n @if (field.type! !== 'hidden') {\r\n <label\r\n [for]=\"uniqueId\"\r\n class=\"fn-label\"\r\n [ngStyle]=\"{\r\n color: field.color || '#03182b',\r\n 'font-size': field.labelSize || '',\r\n }\"\r\n >\r\n {{ getTranslatedLabel(field.label) }}\r\n @if (!field.required && !field.hideOptional) {\r\n <span> (Optional)</span>\r\n }\r\n </label>\r\n }\r\n\r\n <ng-container>\r\n @switch (field.type) {\r\n <!-- Textarea Field -->\r\n @case ('textarea') {\r\n <textarea\r\n #fnTextarea\r\n style=\"resize: none\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [rows]=\"field.rows || 1\"\r\n [readonly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"handleTextArea($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n ></textarea>\r\n }\r\n\r\n <!-- Password Field -->\r\n @case ('password') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon) {\r\n <div class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n </div>\r\n }\r\n <input\r\n [type]=\"showPassword ? 'text' : 'password'\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [disabled]=\"field.disabled || false\"\r\n [formControl]=\"control\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [readonly]=\"field.readOnly || false\"\r\n (input)=\"isAlphanumeric ? handleAlphanumericInput($event) : handleInput($event)\"\r\n (focus)=\"onPasswordFocus()\"\r\n (blur)=\"handlePasswordBlur($event)\"\r\n class=\"fn-input-field overflow-hidden text-ellipsis\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid,\r\n 'pl-10': field.prefix?.icon,\r\n 'pr-12':\r\n (field.toggleMask && !field.isCopyText) ||\r\n (!field.toggleMask && field.isCopyText),\r\n 'pr-24': field.toggleMask && field.isCopyText && !field.hasGenerateKey,\r\n 'pr-32': field.toggleMask && field.isCopyText && field.hasGenerateKey,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.toggleMask && !field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n } @else if (field.isCopyText && !field.toggleMask) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n } @else if (field.toggleMask && field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n [ngClass]=\"{ 'opacity-50 cursor-not-allowed': !control.value }\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (field.feedback && isPasswordFocused) {\r\n <div class=\"mt-2 space-y-1\">\r\n <div class=\"flex items-center justify-between text-xs\">\r\n <span class=\"font-medium\" [ngClass]=\"strengthClass\">\r\n {{ passwordStrengthLabel | translate }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"\r\n passwordStrengthPercent > 50 ? 'check-circle' : 'info-circle'\r\n \"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"extrasmall\"\r\n [attr.data-icon-color]=\"\r\n passwordStrengthPercent <= 25\r\n ? '#ef3e42'\r\n : passwordStrengthPercent <= 75\r\n ? '#ff9f00'\r\n : '#6cc24a'\r\n \"\r\n ></div>\r\n </div>\r\n </div>\r\n <div class=\"h-1.5 w-full bg-[#eef0f2] rounded-full overflow-hidden\">\r\n <div\r\n class=\"h-full transition-all duration-300 rounded-full\"\r\n [ngClass]=\"{\r\n 'bg-[#ef3e42]': passwordStrengthPercent <= 25,\r\n 'bg-[#ff9f00]': passwordStrengthPercent > 25 && passwordStrengthPercent <= 75,\r\n 'bg-[#6cc24a]': passwordStrengthPercent > 75,\r\n }\"\r\n [style.width.%]=\"passwordStrengthPercent\"\r\n ></div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Number Field -->\r\n @case ('number') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon) {\r\n <div class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type === 'number' && field.isCurrency ? 'text' : 'number'\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"isDisabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n [min]=\"field.type === 'number' && !field.isCurrency ? 0 : null\"\r\n [max]=\"field.type === 'number' && !field.isCurrency ? field.max : null\"\r\n [step]=\"field.type === 'number' && !field.isCurrency ? field.step || 1 : null\"\r\n (input)=\"handleNumberInput($event, field.minFractionDigits || 2)\"\r\n (paste)=\"handleNumberPaste($event, field.minFractionDigits || 2)\"\r\n (blur)=\"handleBlur($event, field.minFractionDigits || 2)\"\r\n (keydown)=\"handleNumberKeydown($event, field.isCurrency || false)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon,\r\n 'text-[24px] font-bold': field.isCurrency,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Default Input Field (text, email, etc.) -->\r\n @default {\r\n <div class=\"relative z-0\">\r\n @if (field.prefix?.icon) {\r\n <div class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"\r\n isEmailField\r\n ? handleEmailInput($event)\r\n : field.type === 'text' && isAlphanumeric\r\n ? handleAlphanumericInput($event)\r\n : handleInput($event)\r\n \"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon,\r\n 'pr-10': (field.icon || field.suffix?.icon) && !field.isCopyText,\r\n 'pr-20':\r\n field.isCopyText && !field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-30':\r\n field.isCopyText && field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-32':\r\n field.isCopyText && field.hasGenerateKey && (field.icon || field.suffix?.icon),\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n\r\n @if (field.icon || field.suffix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.suffix?.icon || field.icon!.name\"\r\n [attr.data-icon-variant]=\"field.icon?.variant || 'Line'\"\r\n [attr.data-icon-size]=\"field.icon ? getIconSizeName(field.icon.size) : 'medium'\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-container>\r\n\r\n @if (showFormFieldMessage(control, helperText)) {\r\n <div class=\"fn-field-message-container\">\r\n <span\r\n class=\"fn-field-message-text\"\r\n [ngClass]=\"{\r\n error: isError,\r\n success: isSuccess,\r\n }\"\r\n >\r\n {{ getFieldMessage() | translate }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Integrated Toast Notifications -->\r\n <div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\" [class.toast-enter]=\"toast.isVisible\">\r\n <span class=\"toast-icon\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"getToastIconName(toast)\"\r\n data-icon-variant=\"Colour\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"\r\n toast.type === 'success'\r\n ? '#6cc24a'\r\n : toast.type === 'warn'\r\n ? '#ff9f00'\r\n : toast.type === 'error'\r\n ? '#ef3e42'\r\n : '#03182b'\r\n \"\r\n ></div>\r\n </span>\r\n <div class=\"toast-content\">\r\n <span class=\"toast-message\">\r\n {{ getTranslatedMessage(toast.message) | translate }}\r\n </span>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"removeToast(toast.id)\" aria-label=\"Close\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"cross\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n data-icon-color=\"#ffffff\"\r\n ></div>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".fn-input-container{display:flex;flex-direction:column;width:100%}.fn-label{font-family:Outfit,sans-serif;font-weight:500;margin-bottom:8px;display:flex;align-items:center}.fn-label span{color:#c4cdd2;font-size:14px;font-weight:400}.fn-input-field{width:100%;height:48px;padding:0 16px;background-color:#f7f8f9;border-bottom:1.5px solid #c4cdd2;font-family:Outfit,sans-serif;font-size:16px;color:#03182b;transition:all .2s ease;border-radius:4px 4px 0 0}.fn-input-field::placeholder{color:#c4cdd2}.fn-input-field:focus{outline:none;background-color:#fff;border-bottom-color:#03182b}.fn-input-field.error{border-bottom-color:#ef3e42}.fn-input-field.success{border-bottom-color:#6cc24a}.fn-input-field.disabled{background-color:#eef0f2;color:#c4cdd2;cursor:not-allowed}.fn-input-field.pl-10{padding-left:40px!important}.fn-input-field.pr-10{padding-right:40px!important}.fn-input-field.pr-12{padding-right:44px!important}.fn-input-field.pr-20{padding-right:72px!important}.fn-input-field.pr-24{padding-right:88px!important}.fn-input-field.pr-30{padding-right:104px!important}.fn-input-field.pr-32{padding-right:120px!important}.fn-field-message-container{margin-top:4px}.fn-field-message-text{font-family:Outfit,sans-serif;font-size:12px;color:#c4cdd2}.fn-field-message-text.error{color:#ef3e42}.fn-field-message-text.success{color:#6cc24a}.icon-container{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}.relative{position:relative}.absolute{position:absolute}.right-0{right:0}.left-0{left:0}.top-1\\/2{top:50%}.-translate-y-1\\/2{transform:translateY(-50%)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.mt-2{margin-top:.5rem}.space-y-1>:not([hidden])~:not([hidden]){margin-top:.25rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.h-1\\.5{height:.375rem}.w-full{width:100%}.bg-\\[\\#eef0f2\\]{background-color:#eef0f2}.rounded-full{border-radius:9999px}.overflow-hidden{overflow:hidden}.transition-all{transition-property:all}.duration-300{transition-duration:.3s}.cursor-pointer{cursor:pointer}.opacity-50{opacity:.5}.cursor-not-allowed{cursor:not-allowed}.text-ellipsis{text-overflow:ellipsis}.toast-container{position:fixed;top:24px;left:50%;transform:translate(-50%);z-index:9999;width:100%;max-width:336px;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{display:flex;align-items:center;background:#25333f;border-radius:8px;padding:12px;width:336px;max-width:100%;opacity:0;transform:translateY(-20px);transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.toast.toast-enter{opacity:1;transform:translateY(0)}.toast.toast-success{border-left:4px solid #6cc24a}.toast.toast-warn{border-left:4px solid #ff9f00}.toast.toast-error{border-left:4px solid #ef3e42}.toast.toast-info{border-left:4px solid #3b82f6}.toast .toast-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;margin-right:8px;flex-shrink:0}.toast .toast-content{flex:1;min-width:0}.toast .toast-message{font-size:14px;line-height:20px;color:#fff;display:block}.toast .toast-close{background:none;border:none;font-size:20px;color:#fff;opacity:.7;cursor:pointer;padding:0;margin-left:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:opacity .2s;pointer-events:auto}.toast .toast-close:hover{opacity:1}\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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1173
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FNInput, isStandalone: true, selector: "fn-input", inputs: { field: "field", helperHandle: "helperHandle", toastService: "toastService", currencyMeta: "currencyMeta", defaultLocale: "defaultLocale", form: "form" }, outputs: { valueChange: "valueChange", fieldBlur: "fieldBlur" }, viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["fnTextarea"], descendants: true }, { propertyName: "iconContainers", predicate: ["iconContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (field.name && isVisible() && !field.hidden) {\r\n <div class=\"fn-input-container\">\r\n @if (field.type! !== 'hidden') {\r\n <label\r\n [for]=\"uniqueId\"\r\n class=\"fn-label\"\r\n [ngStyle]=\"{\r\n color: field.color || '#03182b',\r\n 'font-size': field.labelSize || '',\r\n }\"\r\n >\r\n {{ getTranslatedLabel(field.label) }}\r\n @if (!field.required && !field.hideOptional) {\r\n <span> (Optional)</span>\r\n }\r\n </label>\r\n }\r\n\r\n <ng-container>\r\n @switch (field.type) {\r\n <!-- Textarea Field -->\r\n @case ('textarea') {\r\n <textarea\r\n #fnTextarea\r\n style=\"resize: none\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [rows]=\"field.rows || 1\"\r\n [readonly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"handleTextArea($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n ></textarea>\r\n }\r\n\r\n <!-- Password Field -->\r\n @case ('password') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"showPassword ? 'text' : 'password'\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [disabled]=\"field.disabled || false\"\r\n [formControl]=\"control\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [readonly]=\"field.readOnly || false\"\r\n (input)=\"isAlphanumeric ? handleAlphanumericInput($event) : handleInput($event)\"\r\n (focus)=\"onPasswordFocus()\"\r\n (blur)=\"handlePasswordBlur($event)\"\r\n class=\"fn-input-field overflow-hidden text-ellipsis\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-12':\r\n (field.toggleMask && !field.isCopyText) ||\r\n (!field.toggleMask && field.isCopyText),\r\n 'pr-24': field.toggleMask && field.isCopyText && !field.hasGenerateKey,\r\n 'pr-32': field.toggleMask && field.isCopyText && field.hasGenerateKey,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.toggleMask && !field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n } @else if (field.isCopyText && !field.toggleMask) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n } @else if (field.toggleMask && field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n [ngClass]=\"{ 'opacity-50 cursor-not-allowed': !control.value }\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (field.feedback && isPasswordFocused) {\r\n <div class=\"mt-2 space-y-1\">\r\n <div class=\"flex items-center justify-between text-xs\">\r\n <span class=\"font-medium\" [ngClass]=\"strengthClass\">\r\n {{ passwordStrengthLabel | translate }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"\r\n passwordStrengthPercent > 50 ? 'check-circle' : 'info-circle'\r\n \"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"extrasmall\"\r\n [attr.data-icon-color]=\"\r\n passwordStrengthPercent <= 25\r\n ? '#ef3e42'\r\n : passwordStrengthPercent <= 75\r\n ? '#ff9f00'\r\n : '#6cc24a'\r\n \"\r\n ></div>\r\n </div>\r\n </div>\r\n <div class=\"h-1.5 w-full bg-[#eef0f2] rounded-full overflow-hidden\">\r\n <div\r\n class=\"h-full transition-all duration-300 rounded-full\"\r\n [ngClass]=\"{\r\n 'bg-[#ef3e42]': passwordStrengthPercent <= 25,\r\n 'bg-[#ff9f00]': passwordStrengthPercent > 25 && passwordStrengthPercent <= 75,\r\n 'bg-[#6cc24a]': passwordStrengthPercent > 75,\r\n }\"\r\n [style.width.%]=\"passwordStrengthPercent\"\r\n ></div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Number Field -->\r\n @case ('number') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type === 'number' && field.isCurrency ? 'text' : 'number'\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"isDisabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n [min]=\"field.type === 'number' && !field.isCurrency ? 0 : null\"\r\n [max]=\"field.type === 'number' && !field.isCurrency ? field.max : null\"\r\n [step]=\"field.type === 'number' && !field.isCurrency ? field.step || 1 : null\"\r\n (input)=\"handleNumberInput($event, field.minFractionDigits || 2)\"\r\n (paste)=\"handleNumberPaste($event, field.minFractionDigits || 2)\"\r\n (blur)=\"handleBlur($event, field.minFractionDigits || 2)\"\r\n (keydown)=\"handleNumberKeydown($event, field.isCurrency || false)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10': field.suffix?.icon && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'text-[24px] font-bold': field.isCurrency,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Default Input Field (text, email, etc.) -->\r\n @default {\r\n <div class=\"relative z-0\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"\r\n isEmailField\r\n ? handleEmailInput($event)\r\n : field.type === 'text' && isAlphanumeric\r\n ? handleAlphanumericInput($event)\r\n : handleInput($event)\r\n \"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10':\r\n (field.icon || field.suffix?.icon) && !field.isCopyText && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'pr-20':\r\n field.isCopyText && !field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-30':\r\n field.isCopyText && field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-32':\r\n field.isCopyText && field.hasGenerateKey && (field.icon || field.suffix?.icon),\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n\r\n @if (field.icon || field.suffix?.icon || field.suffix?.text) {\r\n @if (field.suffix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"suffixClick($event)\"\r\n (keydown.enter)=\"suffixClick($event)\"\r\n [attr.tabindex]=\"field.suffix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.suffix?.onClick\"\r\n >{{ field.suffix!.text }}</span\r\n >\r\n }\r\n @if (field.icon || field.suffix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.suffix?.icon || field.icon!.name\"\r\n [attr.data-icon-variant]=\"field.icon?.variant || 'Line'\"\r\n [attr.data-icon-size]=\"field.icon ? getIconSizeName(field.icon.size) : 'medium'\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-container>\r\n\r\n @if (showFormFieldMessage(control, helperText)) {\r\n <div class=\"fn-field-message-container\">\r\n <span\r\n class=\"fn-field-message-text\"\r\n [ngClass]=\"{\r\n error: isError,\r\n success: isSuccess,\r\n }\"\r\n >\r\n {{ getFieldMessage() | translate }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Integrated Toast Notifications -->\r\n <div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\" [class.toast-enter]=\"toast.isVisible\">\r\n <span class=\"toast-icon\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"getToastIconName(toast)\"\r\n data-icon-variant=\"Colour\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"\r\n toast.type === 'success'\r\n ? '#6cc24a'\r\n : toast.type === 'warn'\r\n ? '#ff9f00'\r\n : toast.type === 'error'\r\n ? '#ef3e42'\r\n : '#03182b'\r\n \"\r\n ></div>\r\n </span>\r\n <div class=\"toast-content\">\r\n <span class=\"toast-message\">\r\n {{ getTranslatedMessage(toast.message) | translate }}\r\n </span>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"removeToast(toast.id)\" aria-label=\"Close\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"cross\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n data-icon-color=\"#ffffff\"\r\n ></div>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".fn-input-container{display:flex;flex-direction:column;width:100%}.fn-label{font-family:Outfit,sans-serif;font-weight:500;margin-bottom:8px;display:flex;align-items:center}.fn-label span{color:#c4cdd2;font-size:14px;font-weight:400}.fn-input-field{width:100%;height:48px;padding:0 16px;background-color:#f7f8f9;border-bottom:1.5px solid #c4cdd2;font-family:Outfit,sans-serif;font-size:16px;color:#03182b;transition:all .2s ease;border-radius:4px 4px 0 0}.fn-input-field::placeholder{color:#c4cdd2}.fn-input-field:focus{outline:none;background-color:#fff;border-bottom-color:#03182b}.fn-input-field.error{border-bottom-color:#ef3e42}.fn-input-field.success{border-bottom-color:#6cc24a}.fn-input-field.disabled{background-color:#eef0f2;color:#c4cdd2;cursor:not-allowed}.fn-input-field.pl-10{padding-left:40px!important}.fn-input-field.has-prefix-text{padding-left:100px!important}.fn-input-field.pr-10{padding-right:40px!important}.fn-input-field.has-suffix-text{padding-right:120px!important}.fn-input-field.pr-12{padding-right:44px!important}.fn-input-field.pr-20{padding-right:72px!important}.fn-input-field.pr-24{padding-right:88px!important}.fn-input-field.pr-30{padding-right:104px!important}.fn-input-field.pr-32{padding-right:120px!important}.fn-field-message-container{margin-top:4px}.fn-field-message-text{font-family:Outfit,sans-serif;font-size:12px;color:#c4cdd2}.fn-field-message-text.error{color:#ef3e42}.fn-field-message-text.success{color:#6cc24a}.icon-container{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}.relative{position:relative}.absolute{position:absolute}.right-0{right:0}.left-0{left:0}.top-1\\/2{top:50%}.-translate-y-1\\/2{transform:translateY(-50%)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.mt-2{margin-top:.5rem}.space-y-1>:not([hidden])~:not([hidden]){margin-top:.25rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.h-1\\.5{height:.375rem}.w-full{width:100%}.bg-\\[\\#eef0f2\\]{background-color:#eef0f2}.rounded-full{border-radius:9999px}.overflow-hidden{overflow:hidden}.transition-all{transition-property:all}.duration-300{transition-duration:.3s}.cursor-pointer{cursor:pointer}.opacity-50{opacity:.5}.cursor-not-allowed{cursor:not-allowed}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.toast-container{position:fixed;top:24px;left:50%;transform:translate(-50%);z-index:9999;width:100%;max-width:336px;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{display:flex;align-items:center;background:#25333f;border-radius:8px;padding:12px;width:336px;max-width:100%;opacity:0;transform:translateY(-20px);transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.toast.toast-enter{opacity:1;transform:translateY(0)}.toast.toast-success{border-left:4px solid #6cc24a}.toast.toast-warn{border-left:4px solid #ff9f00}.toast.toast-error{border-left:4px solid #ef3e42}.toast.toast-info{border-left:4px solid #3b82f6}.toast .toast-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;margin-right:8px;flex-shrink:0}.toast .toast-content{flex:1;min-width:0}.toast .toast-message{font-size:14px;line-height:20px;color:#fff;display:block}.toast .toast-close{background:none;border:none;font-size:20px;color:#fff;opacity:.7;cursor:pointer;padding:0;margin-left:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:opacity .2s;pointer-events:auto}.toast .toast-close:hover{opacity:1}\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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1153
1174
|
}
|
|
1154
1175
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FNInput, decorators: [{
|
|
1155
1176
|
type: Component,
|
|
1156
|
-
args: [{ selector: 'fn-input', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule, TranslateModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (field.name && isVisible() && !field.hidden) {\r\n <div class=\"fn-input-container\">\r\n @if (field.type! !== 'hidden') {\r\n <label\r\n [for]=\"uniqueId\"\r\n class=\"fn-label\"\r\n [ngStyle]=\"{\r\n color: field.color || '#03182b',\r\n 'font-size': field.labelSize || '',\r\n }\"\r\n >\r\n {{ getTranslatedLabel(field.label) }}\r\n @if (!field.required && !field.hideOptional) {\r\n <span> (Optional)</span>\r\n }\r\n </label>\r\n }\r\n\r\n <ng-container>\r\n @switch (field.type) {\r\n <!-- Textarea Field -->\r\n @case ('textarea') {\r\n <textarea\r\n #fnTextarea\r\n style=\"resize: none\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [rows]=\"field.rows || 1\"\r\n [readonly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"handleTextArea($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n ></textarea>\r\n }\r\n\r\n <!-- Password Field -->\r\n @case ('password') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon) {\r\n <div class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n </div>\r\n }\r\n <input\r\n [type]=\"showPassword ? 'text' : 'password'\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [disabled]=\"field.disabled || false\"\r\n [formControl]=\"control\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [readonly]=\"field.readOnly || false\"\r\n (input)=\"isAlphanumeric ? handleAlphanumericInput($event) : handleInput($event)\"\r\n (focus)=\"onPasswordFocus()\"\r\n (blur)=\"handlePasswordBlur($event)\"\r\n class=\"fn-input-field overflow-hidden text-ellipsis\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid,\r\n 'pl-10': field.prefix?.icon,\r\n 'pr-12':\r\n (field.toggleMask && !field.isCopyText) ||\r\n (!field.toggleMask && field.isCopyText),\r\n 'pr-24': field.toggleMask && field.isCopyText && !field.hasGenerateKey,\r\n 'pr-32': field.toggleMask && field.isCopyText && field.hasGenerateKey,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.toggleMask && !field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n } @else if (field.isCopyText && !field.toggleMask) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n } @else if (field.toggleMask && field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n [ngClass]=\"{ 'opacity-50 cursor-not-allowed': !control.value }\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (field.feedback && isPasswordFocused) {\r\n <div class=\"mt-2 space-y-1\">\r\n <div class=\"flex items-center justify-between text-xs\">\r\n <span class=\"font-medium\" [ngClass]=\"strengthClass\">\r\n {{ passwordStrengthLabel | translate }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"\r\n passwordStrengthPercent > 50 ? 'check-circle' : 'info-circle'\r\n \"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"extrasmall\"\r\n [attr.data-icon-color]=\"\r\n passwordStrengthPercent <= 25\r\n ? '#ef3e42'\r\n : passwordStrengthPercent <= 75\r\n ? '#ff9f00'\r\n : '#6cc24a'\r\n \"\r\n ></div>\r\n </div>\r\n </div>\r\n <div class=\"h-1.5 w-full bg-[#eef0f2] rounded-full overflow-hidden\">\r\n <div\r\n class=\"h-full transition-all duration-300 rounded-full\"\r\n [ngClass]=\"{\r\n 'bg-[#ef3e42]': passwordStrengthPercent <= 25,\r\n 'bg-[#ff9f00]': passwordStrengthPercent > 25 && passwordStrengthPercent <= 75,\r\n 'bg-[#6cc24a]': passwordStrengthPercent > 75,\r\n }\"\r\n [style.width.%]=\"passwordStrengthPercent\"\r\n ></div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Number Field -->\r\n @case ('number') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon) {\r\n <div class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type === 'number' && field.isCurrency ? 'text' : 'number'\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"isDisabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n [min]=\"field.type === 'number' && !field.isCurrency ? 0 : null\"\r\n [max]=\"field.type === 'number' && !field.isCurrency ? field.max : null\"\r\n [step]=\"field.type === 'number' && !field.isCurrency ? field.step || 1 : null\"\r\n (input)=\"handleNumberInput($event, field.minFractionDigits || 2)\"\r\n (paste)=\"handleNumberPaste($event, field.minFractionDigits || 2)\"\r\n (blur)=\"handleBlur($event, field.minFractionDigits || 2)\"\r\n (keydown)=\"handleNumberKeydown($event, field.isCurrency || false)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon,\r\n 'text-[24px] font-bold': field.isCurrency,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Default Input Field (text, email, etc.) -->\r\n @default {\r\n <div class=\"relative z-0\">\r\n @if (field.prefix?.icon) {\r\n <div class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"\r\n isEmailField\r\n ? handleEmailInput($event)\r\n : field.type === 'text' && isAlphanumeric\r\n ? handleAlphanumericInput($event)\r\n : handleInput($event)\r\n \"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon,\r\n 'pr-10': (field.icon || field.suffix?.icon) && !field.isCopyText,\r\n 'pr-20':\r\n field.isCopyText && !field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-30':\r\n field.isCopyText && field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-32':\r\n field.isCopyText && field.hasGenerateKey && (field.icon || field.suffix?.icon),\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n\r\n @if (field.icon || field.suffix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.suffix?.icon || field.icon!.name\"\r\n [attr.data-icon-variant]=\"field.icon?.variant || 'Line'\"\r\n [attr.data-icon-size]=\"field.icon ? getIconSizeName(field.icon.size) : 'medium'\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-container>\r\n\r\n @if (showFormFieldMessage(control, helperText)) {\r\n <div class=\"fn-field-message-container\">\r\n <span\r\n class=\"fn-field-message-text\"\r\n [ngClass]=\"{\r\n error: isError,\r\n success: isSuccess,\r\n }\"\r\n >\r\n {{ getFieldMessage() | translate }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Integrated Toast Notifications -->\r\n <div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\" [class.toast-enter]=\"toast.isVisible\">\r\n <span class=\"toast-icon\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"getToastIconName(toast)\"\r\n data-icon-variant=\"Colour\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"\r\n toast.type === 'success'\r\n ? '#6cc24a'\r\n : toast.type === 'warn'\r\n ? '#ff9f00'\r\n : toast.type === 'error'\r\n ? '#ef3e42'\r\n : '#03182b'\r\n \"\r\n ></div>\r\n </span>\r\n <div class=\"toast-content\">\r\n <span class=\"toast-message\">\r\n {{ getTranslatedMessage(toast.message) | translate }}\r\n </span>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"removeToast(toast.id)\" aria-label=\"Close\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"cross\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n data-icon-color=\"#ffffff\"\r\n ></div>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".fn-input-container{display:flex;flex-direction:column;width:100%}.fn-label{font-family:Outfit,sans-serif;font-weight:500;margin-bottom:8px;display:flex;align-items:center}.fn-label span{color:#c4cdd2;font-size:14px;font-weight:400}.fn-input-field{width:100%;height:48px;padding:0 16px;background-color:#f7f8f9;border-bottom:1.5px solid #c4cdd2;font-family:Outfit,sans-serif;font-size:16px;color:#03182b;transition:all .2s ease;border-radius:4px 4px 0 0}.fn-input-field::placeholder{color:#c4cdd2}.fn-input-field:focus{outline:none;background-color:#fff;border-bottom-color:#03182b}.fn-input-field.error{border-bottom-color:#ef3e42}.fn-input-field.success{border-bottom-color:#6cc24a}.fn-input-field.disabled{background-color:#eef0f2;color:#c4cdd2;cursor:not-allowed}.fn-input-field.pl-10{padding-left:40px!important}.fn-input-field.pr-10{padding-right:40px!important}.fn-input-field.pr-12{padding-right:44px!important}.fn-input-field.pr-20{padding-right:72px!important}.fn-input-field.pr-24{padding-right:88px!important}.fn-input-field.pr-30{padding-right:104px!important}.fn-input-field.pr-32{padding-right:120px!important}.fn-field-message-container{margin-top:4px}.fn-field-message-text{font-family:Outfit,sans-serif;font-size:12px;color:#c4cdd2}.fn-field-message-text.error{color:#ef3e42}.fn-field-message-text.success{color:#6cc24a}.icon-container{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}.relative{position:relative}.absolute{position:absolute}.right-0{right:0}.left-0{left:0}.top-1\\/2{top:50%}.-translate-y-1\\/2{transform:translateY(-50%)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.mt-2{margin-top:.5rem}.space-y-1>:not([hidden])~:not([hidden]){margin-top:.25rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.h-1\\.5{height:.375rem}.w-full{width:100%}.bg-\\[\\#eef0f2\\]{background-color:#eef0f2}.rounded-full{border-radius:9999px}.overflow-hidden{overflow:hidden}.transition-all{transition-property:all}.duration-300{transition-duration:.3s}.cursor-pointer{cursor:pointer}.opacity-50{opacity:.5}.cursor-not-allowed{cursor:not-allowed}.text-ellipsis{text-overflow:ellipsis}.toast-container{position:fixed;top:24px;left:50%;transform:translate(-50%);z-index:9999;width:100%;max-width:336px;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{display:flex;align-items:center;background:#25333f;border-radius:8px;padding:12px;width:336px;max-width:100%;opacity:0;transform:translateY(-20px);transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.toast.toast-enter{opacity:1;transform:translateY(0)}.toast.toast-success{border-left:4px solid #6cc24a}.toast.toast-warn{border-left:4px solid #ff9f00}.toast.toast-error{border-left:4px solid #ef3e42}.toast.toast-info{border-left:4px solid #3b82f6}.toast .toast-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;margin-right:8px;flex-shrink:0}.toast .toast-content{flex:1;min-width:0}.toast .toast-message{font-size:14px;line-height:20px;color:#fff;display:block}.toast .toast-close{background:none;border:none;font-size:20px;color:#fff;opacity:.7;cursor:pointer;padding:0;margin-left:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:opacity .2s;pointer-events:auto}.toast .toast-close:hover{opacity:1}\n"] }]
|
|
1177
|
+
args: [{ selector: 'fn-input', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule, TranslateModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (field.name && isVisible() && !field.hidden) {\r\n <div class=\"fn-input-container\">\r\n @if (field.type! !== 'hidden') {\r\n <label\r\n [for]=\"uniqueId\"\r\n class=\"fn-label\"\r\n [ngStyle]=\"{\r\n color: field.color || '#03182b',\r\n 'font-size': field.labelSize || '',\r\n }\"\r\n >\r\n {{ getTranslatedLabel(field.label) }}\r\n @if (!field.required && !field.hideOptional) {\r\n <span> (Optional)</span>\r\n }\r\n </label>\r\n }\r\n\r\n <ng-container>\r\n @switch (field.type) {\r\n <!-- Textarea Field -->\r\n @case ('textarea') {\r\n <textarea\r\n #fnTextarea\r\n style=\"resize: none\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [rows]=\"field.rows || 1\"\r\n [readonly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"handleTextArea($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n ></textarea>\r\n }\r\n\r\n <!-- Password Field -->\r\n @case ('password') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"showPassword ? 'text' : 'password'\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [disabled]=\"field.disabled || false\"\r\n [formControl]=\"control\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [readonly]=\"field.readOnly || false\"\r\n (input)=\"isAlphanumeric ? handleAlphanumericInput($event) : handleInput($event)\"\r\n (focus)=\"onPasswordFocus()\"\r\n (blur)=\"handlePasswordBlur($event)\"\r\n class=\"fn-input-field overflow-hidden text-ellipsis\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-12':\r\n (field.toggleMask && !field.isCopyText) ||\r\n (!field.toggleMask && field.isCopyText),\r\n 'pr-24': field.toggleMask && field.isCopyText && !field.hasGenerateKey,\r\n 'pr-32': field.toggleMask && field.isCopyText && field.hasGenerateKey,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.toggleMask && !field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n } @else if (field.isCopyText && !field.toggleMask) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n } @else if (field.toggleMask && field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n [ngClass]=\"{ 'opacity-50 cursor-not-allowed': !control.value }\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (field.feedback && isPasswordFocused) {\r\n <div class=\"mt-2 space-y-1\">\r\n <div class=\"flex items-center justify-between text-xs\">\r\n <span class=\"font-medium\" [ngClass]=\"strengthClass\">\r\n {{ passwordStrengthLabel | translate }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"\r\n passwordStrengthPercent > 50 ? 'check-circle' : 'info-circle'\r\n \"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"extrasmall\"\r\n [attr.data-icon-color]=\"\r\n passwordStrengthPercent <= 25\r\n ? '#ef3e42'\r\n : passwordStrengthPercent <= 75\r\n ? '#ff9f00'\r\n : '#6cc24a'\r\n \"\r\n ></div>\r\n </div>\r\n </div>\r\n <div class=\"h-1.5 w-full bg-[#eef0f2] rounded-full overflow-hidden\">\r\n <div\r\n class=\"h-full transition-all duration-300 rounded-full\"\r\n [ngClass]=\"{\r\n 'bg-[#ef3e42]': passwordStrengthPercent <= 25,\r\n 'bg-[#ff9f00]': passwordStrengthPercent > 25 && passwordStrengthPercent <= 75,\r\n 'bg-[#6cc24a]': passwordStrengthPercent > 75,\r\n }\"\r\n [style.width.%]=\"passwordStrengthPercent\"\r\n ></div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Number Field -->\r\n @case ('number') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type === 'number' && field.isCurrency ? 'text' : 'number'\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"isDisabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n [min]=\"field.type === 'number' && !field.isCurrency ? 0 : null\"\r\n [max]=\"field.type === 'number' && !field.isCurrency ? field.max : null\"\r\n [step]=\"field.type === 'number' && !field.isCurrency ? field.step || 1 : null\"\r\n (input)=\"handleNumberInput($event, field.minFractionDigits || 2)\"\r\n (paste)=\"handleNumberPaste($event, field.minFractionDigits || 2)\"\r\n (blur)=\"handleBlur($event, field.minFractionDigits || 2)\"\r\n (keydown)=\"handleNumberKeydown($event, field.isCurrency || false)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10': field.suffix?.icon && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'text-[24px] font-bold': field.isCurrency,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Default Input Field (text, email, etc.) -->\r\n @default {\r\n <div class=\"relative z-0\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"\r\n isEmailField\r\n ? handleEmailInput($event)\r\n : field.type === 'text' && isAlphanumeric\r\n ? handleAlphanumericInput($event)\r\n : handleInput($event)\r\n \"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10':\r\n (field.icon || field.suffix?.icon) && !field.isCopyText && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'pr-20':\r\n field.isCopyText && !field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-30':\r\n field.isCopyText && field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-32':\r\n field.isCopyText && field.hasGenerateKey && (field.icon || field.suffix?.icon),\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n\r\n @if (field.icon || field.suffix?.icon || field.suffix?.text) {\r\n @if (field.suffix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"suffixClick($event)\"\r\n (keydown.enter)=\"suffixClick($event)\"\r\n [attr.tabindex]=\"field.suffix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.suffix?.onClick\"\r\n >{{ field.suffix!.text }}</span\r\n >\r\n }\r\n @if (field.icon || field.suffix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.suffix?.icon || field.icon!.name\"\r\n [attr.data-icon-variant]=\"field.icon?.variant || 'Line'\"\r\n [attr.data-icon-size]=\"field.icon ? getIconSizeName(field.icon.size) : 'medium'\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-container>\r\n\r\n @if (showFormFieldMessage(control, helperText)) {\r\n <div class=\"fn-field-message-container\">\r\n <span\r\n class=\"fn-field-message-text\"\r\n [ngClass]=\"{\r\n error: isError,\r\n success: isSuccess,\r\n }\"\r\n >\r\n {{ getFieldMessage() | translate }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Integrated Toast Notifications -->\r\n <div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\" [class.toast-enter]=\"toast.isVisible\">\r\n <span class=\"toast-icon\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"getToastIconName(toast)\"\r\n data-icon-variant=\"Colour\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"\r\n toast.type === 'success'\r\n ? '#6cc24a'\r\n : toast.type === 'warn'\r\n ? '#ff9f00'\r\n : toast.type === 'error'\r\n ? '#ef3e42'\r\n : '#03182b'\r\n \"\r\n ></div>\r\n </span>\r\n <div class=\"toast-content\">\r\n <span class=\"toast-message\">\r\n {{ getTranslatedMessage(toast.message) | translate }}\r\n </span>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"removeToast(toast.id)\" aria-label=\"Close\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"cross\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n data-icon-color=\"#ffffff\"\r\n ></div>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".fn-input-container{display:flex;flex-direction:column;width:100%}.fn-label{font-family:Outfit,sans-serif;font-weight:500;margin-bottom:8px;display:flex;align-items:center}.fn-label span{color:#c4cdd2;font-size:14px;font-weight:400}.fn-input-field{width:100%;height:48px;padding:0 16px;background-color:#f7f8f9;border-bottom:1.5px solid #c4cdd2;font-family:Outfit,sans-serif;font-size:16px;color:#03182b;transition:all .2s ease;border-radius:4px 4px 0 0}.fn-input-field::placeholder{color:#c4cdd2}.fn-input-field:focus{outline:none;background-color:#fff;border-bottom-color:#03182b}.fn-input-field.error{border-bottom-color:#ef3e42}.fn-input-field.success{border-bottom-color:#6cc24a}.fn-input-field.disabled{background-color:#eef0f2;color:#c4cdd2;cursor:not-allowed}.fn-input-field.pl-10{padding-left:40px!important}.fn-input-field.has-prefix-text{padding-left:100px!important}.fn-input-field.pr-10{padding-right:40px!important}.fn-input-field.has-suffix-text{padding-right:120px!important}.fn-input-field.pr-12{padding-right:44px!important}.fn-input-field.pr-20{padding-right:72px!important}.fn-input-field.pr-24{padding-right:88px!important}.fn-input-field.pr-30{padding-right:104px!important}.fn-input-field.pr-32{padding-right:120px!important}.fn-field-message-container{margin-top:4px}.fn-field-message-text{font-family:Outfit,sans-serif;font-size:12px;color:#c4cdd2}.fn-field-message-text.error{color:#ef3e42}.fn-field-message-text.success{color:#6cc24a}.icon-container{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}.relative{position:relative}.absolute{position:absolute}.right-0{right:0}.left-0{left:0}.top-1\\/2{top:50%}.-translate-y-1\\/2{transform:translateY(-50%)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.mt-2{margin-top:.5rem}.space-y-1>:not([hidden])~:not([hidden]){margin-top:.25rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.h-1\\.5{height:.375rem}.w-full{width:100%}.bg-\\[\\#eef0f2\\]{background-color:#eef0f2}.rounded-full{border-radius:9999px}.overflow-hidden{overflow:hidden}.transition-all{transition-property:all}.duration-300{transition-duration:.3s}.cursor-pointer{cursor:pointer}.opacity-50{opacity:.5}.cursor-not-allowed{cursor:not-allowed}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.toast-container{position:fixed;top:24px;left:50%;transform:translate(-50%);z-index:9999;width:100%;max-width:336px;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{display:flex;align-items:center;background:#25333f;border-radius:8px;padding:12px;width:336px;max-width:100%;opacity:0;transform:translateY(-20px);transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.toast.toast-enter{opacity:1;transform:translateY(0)}.toast.toast-success{border-left:4px solid #6cc24a}.toast.toast-warn{border-left:4px solid #ff9f00}.toast.toast-error{border-left:4px solid #ef3e42}.toast.toast-info{border-left:4px solid #3b82f6}.toast .toast-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;margin-right:8px;flex-shrink:0}.toast .toast-content{flex:1;min-width:0}.toast .toast-message{font-size:14px;line-height:20px;color:#fff;display:block}.toast .toast-close{background:none;border:none;font-size:20px;color:#fff;opacity:.7;cursor:pointer;padding:0;margin-left:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:opacity .2s;pointer-events:auto}.toast .toast-close:hover{opacity:1}\n"] }]
|
|
1157
1178
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { field: [{
|
|
1158
1179
|
type: Input
|
|
1159
1180
|
}], helperHandle: [{
|