osl-base-extended 1.1.21 → 1.1.23

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.
@@ -5,7 +5,7 @@ import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/d
5
5
  import { MatSnackBar } from '@angular/material/snack-bar';
6
6
  import { Router } from '@angular/router';
7
7
  import * as i1$2 from '@angular/common';
8
- import { NgTemplateOutlet, NgComponentOutlet, isPlatformBrowser, NgStyle } from '@angular/common';
8
+ import { NgTemplateOutlet, NgComponentOutlet, isPlatformBrowser, NgStyle, DatePipe } from '@angular/common';
9
9
  import * as i3 from '@angular/material/button';
10
10
  import { MatIconButton, MatButtonModule } from '@angular/material/button';
11
11
  import * as i2 from '@angular/material/icon';
@@ -989,8 +989,11 @@ class Oslinput {
989
989
  togglePassword() {
990
990
  this.showPassword = !this.showPassword;
991
991
  }
992
- onFocusIn() {
992
+ onFocusIn(event) {
993
993
  this.isFocused = true;
994
+ if (this.decimalPortion !== null) {
995
+ setTimeout(() => event.target.select(), 0);
996
+ }
994
997
  }
995
998
  onFocusOut() {
996
999
  this.isFocused = false;
@@ -1138,11 +1141,11 @@ class Oslinput {
1138
1141
  return result;
1139
1142
  }
1140
1143
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: Oslinput, deps: [], target: i0.ɵɵFactoryTarget.Component });
1141
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: Oslinput, isStandalone: false, selector: "osl-input", inputs: { label: "label", required: "required", disabled: "disabled", model: "model", type: "type", placeholder: "placeholder", mask: "mask", min: "min", max: "max", minLength: "minLength", maxLength: "maxLength", prefixIcon: "prefixIcon", suffixIcon: "suffixIcon", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme", onlyChars: "onlyChars", decimalPortion: "decimalPortion" }, outputs: { modelChange: "modelChange", changeEv: "changeEv" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"d-flex flex-column\">\r\n @if(label){\r\n <div [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <label class=\"label\" [class.txt-clr-red]=\"myField.touched && myField.invalid\">\r\n <span [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">{{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span></span>\r\n </label>\r\n </div>\r\n}\r\n\r\n <div class=\"input-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.plain]=\"!hasWrapper\" [class.error]=\"myField.touched && myField.invalid\" [class.input-disabled]=\"disabled\">\r\n @if(prefixIcon) {\r\n <mat-icon class=\"input-icon prefix-icon\">{{prefixIcon}}</mat-icon>\r\n }\r\n <input\r\n\r\n [type]=\"inputType\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (focus)=\"onFocusIn()\"\r\n (blur)=\"onFocusOut()\"\r\n (change)=\"onChange()\"\r\n [required]=\"required\"\r\n [disabled]=\"disabled\"\r\n [placeholder]=\"placeholder\"\r\n [attr.min]=\"min || null\"\r\n [attr.max]=\"max || null\"\r\n [attr.minlength]=\"minLength\"\r\n [attr.maxlength]=\"maxLength\"\r\n [email]=\"type === 'email'\"\r\n #myField=\"ngModel\"\r\n class=\"inner-input\"\r\n >\r\n @if(type === 'password') {\r\n <button type=\"button\" class=\"password-toggle\" (click)=\"togglePassword()\" tabindex=\"-1\">\r\n <mat-icon>{{showPassword ? 'visibility_off' : 'visibility'}}</mat-icon>\r\n </button>\r\n }\r\n @if(suffixIcon && type !== 'password') {\r\n <mat-icon class=\"input-icon suffix-icon\">{{suffixIcon}}</mat-icon>\r\n }\r\n </div>\r\n\r\n @if(myField.touched && myField.invalid) {\r\n @if(myField.errors?.['required']) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n } @else if(myField.errors?.['email']) {\r\n <mat-hint class=\"hint\">Please enter a valid email address.</mat-hint>\r\n } @else if(myField.errors?.['minlength']) {\r\n <mat-hint class=\"hint\">Minimum {{minLength}} characters required.</mat-hint>\r\n } @else if(myField.errors?.['maxlength']) {\r\n <mat-hint class=\"hint\">Maximum {{maxLength}} characters allowed.</mat-hint>\r\n } @else if(myField.errors?.['min']) {\r\n <mat-hint class=\"hint\">Value must be at least {{min}}.</mat-hint>\r\n } @else if(myField.errors?.['max']) {\r\n <mat-hint class=\"hint\">Value must be at most {{max}}.</mat-hint>\r\n }\r\n }\r\n</div>\r\n", styles: [".label{font-size:var(--osl-label-font-size);margin-bottom:5px}.input-wrapper{display:flex;align-items:center;height:var(--osl-control-height);width:100%;border-radius:var(--osl-border-radius);border:1px solid var(--osl-border-color);padding:0 8px;gap:6px;transition:border-color .5s}.input-wrapper:focus-within{border-color:var(--osl-focus-border-color)}.input-wrapper.error{border-color:var(--osl-error-color)}.input-wrapper.input-disabled{background:#f5f5f5;opacity:.7;cursor:not-allowed}.input-wrapper.plain{padding:0;border:none;height:auto;gap:0}.input-wrapper.plain .inner-input{border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);padding:5px;height:var(--osl-control-height)}.input-wrapper.plain .inner-input:focus{border-color:var(--osl-focus-border-color)}.input-wrapper.plain .inner-input.error{border-color:var(--osl-error-color)}.inner-input{flex:1;min-width:0;height:100%;border:none;outline:none;font-size:var(--osl-text-font-size);background:transparent;width:100%}.inner-input:disabled{cursor:not-allowed;background:transparent}.inner-input::placeholder{font-size:var(--osl-label-font-size);color:#aaa}.input-icon{font-size:18px;width:18px;height:18px;color:#888;flex-shrink:0;-webkit-user-select:none;user-select:none}.password-toggle{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:0;cursor:pointer;color:#888;flex-shrink:0}.password-toggle mat-icon{font-size:18px;width:18px;height:18px}.password-toggle:hover{color:#333}.hint{color:var(--osl-error-color);margin-top:2px;font-size:var(--osl-hint-font-size)}.txt-clr-red{color:var(--osl-error-color)}\n"], dependencies: [{ kind: "directive", type: i1$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: OslSkeletonDirective, selector: "[oslSkeleton]", inputs: ["oslSkeleton", "oslSkeletonType", "oslSkeletonAnimation", "oslSkeletonTheme", "oslSkeletonColor", "oslSkeletonHighlight", "oslSkeletonRadius", "oslSkeletonRows", "oslSkeletonRowGap", "oslSkeletonZIndex", "oslSkeletonDelay", "oslSkeletonDuration", "oslSkeletonMinHeight", "oslSkeletonForceReread", "oslSkeletonCircleSize", "oslSkeletonListItems", "oslSkeletonTableRows", "oslSkeletonTableCols", "oslSkeletonCardLines", "oslSkeletonBgColor"] }] });
1144
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: Oslinput, isStandalone: false, selector: "osl-input", inputs: { label: "label", required: "required", disabled: "disabled", model: "model", type: "type", placeholder: "placeholder", mask: "mask", min: "min", max: "max", minLength: "minLength", maxLength: "maxLength", prefixIcon: "prefixIcon", suffixIcon: "suffixIcon", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme", onlyChars: "onlyChars", decimalPortion: "decimalPortion" }, outputs: { modelChange: "modelChange", changeEv: "changeEv" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"d-flex flex-column\">\r\n @if(label){\r\n <div [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <label class=\"label\" [class.txt-clr-red]=\"myField.touched && myField.invalid\">\r\n <span [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">{{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span></span>\r\n </label>\r\n </div>\r\n}\r\n\r\n <div class=\"input-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.plain]=\"!hasWrapper\" [class.error]=\"myField.touched && myField.invalid\" [class.input-disabled]=\"disabled\">\r\n @if(prefixIcon) {\r\n <mat-icon class=\"input-icon prefix-icon\">{{prefixIcon}}</mat-icon>\r\n }\r\n <input\r\n\r\n [type]=\"inputType\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (focus)=\"onFocusIn($event)\"\r\n (blur)=\"onFocusOut()\"\r\n (change)=\"onChange()\"\r\n [required]=\"required\"\r\n [disabled]=\"disabled\"\r\n [placeholder]=\"placeholder\"\r\n [attr.min]=\"min || null\"\r\n [attr.max]=\"max || null\"\r\n [attr.minlength]=\"minLength\"\r\n [attr.maxlength]=\"maxLength\"\r\n [email]=\"type === 'email'\"\r\n #myField=\"ngModel\"\r\n class=\"inner-input\"\r\n >\r\n @if(type === 'password') {\r\n <button type=\"button\" class=\"password-toggle\" (click)=\"togglePassword()\" tabindex=\"-1\">\r\n <mat-icon>{{showPassword ? 'visibility_off' : 'visibility'}}</mat-icon>\r\n </button>\r\n }\r\n @if(suffixIcon && type !== 'password') {\r\n <mat-icon class=\"input-icon suffix-icon\">{{suffixIcon}}</mat-icon>\r\n }\r\n </div>\r\n\r\n @if(myField.touched && myField.invalid) {\r\n @if(myField.errors?.['required']) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n } @else if(myField.errors?.['email']) {\r\n <mat-hint class=\"hint\">Please enter a valid email address.</mat-hint>\r\n } @else if(myField.errors?.['minlength']) {\r\n <mat-hint class=\"hint\">Minimum {{minLength}} characters required.</mat-hint>\r\n } @else if(myField.errors?.['maxlength']) {\r\n <mat-hint class=\"hint\">Maximum {{maxLength}} characters allowed.</mat-hint>\r\n } @else if(myField.errors?.['min']) {\r\n <mat-hint class=\"hint\">Value must be at least {{min}}.</mat-hint>\r\n } @else if(myField.errors?.['max']) {\r\n <mat-hint class=\"hint\">Value must be at most {{max}}.</mat-hint>\r\n }\r\n }\r\n</div>\r\n", styles: [".label{font-size:var(--osl-label-font-size);margin-bottom:5px}.input-wrapper{display:flex;align-items:center;height:var(--osl-control-height);width:100%;border-radius:var(--osl-border-radius);border:1px solid var(--osl-border-color);padding:0 8px;gap:6px;transition:border-color .5s}.input-wrapper:focus-within{border-color:var(--osl-focus-border-color)}.input-wrapper.error{border-color:var(--osl-error-color)}.input-wrapper.input-disabled{background:#f5f5f5;opacity:.7;cursor:not-allowed}.input-wrapper.plain{padding:0;border:none;height:auto;gap:0}.input-wrapper.plain .inner-input{border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);padding:5px;height:var(--osl-control-height)}.input-wrapper.plain .inner-input:focus{border-color:var(--osl-focus-border-color)}.input-wrapper.plain .inner-input.error{border-color:var(--osl-error-color)}.inner-input{flex:1;min-width:0;height:100%;border:none;outline:none;font-size:var(--osl-text-font-size);background:transparent;width:100%}.inner-input:disabled{cursor:not-allowed;background:transparent}.inner-input::placeholder{font-size:var(--osl-label-font-size);color:#aaa}.input-icon{font-size:18px;width:18px;height:18px;color:#888;flex-shrink:0;-webkit-user-select:none;user-select:none}.password-toggle{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:0;cursor:pointer;color:#888;flex-shrink:0}.password-toggle mat-icon{font-size:18px;width:18px;height:18px}.password-toggle:hover{color:#333}.hint{color:var(--osl-error-color);margin-top:2px;font-size:var(--osl-hint-font-size)}.txt-clr-red{color:var(--osl-error-color)}\n"], dependencies: [{ kind: "directive", type: i1$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: OslSkeletonDirective, selector: "[oslSkeleton]", inputs: ["oslSkeleton", "oslSkeletonType", "oslSkeletonAnimation", "oslSkeletonTheme", "oslSkeletonColor", "oslSkeletonHighlight", "oslSkeletonRadius", "oslSkeletonRows", "oslSkeletonRowGap", "oslSkeletonZIndex", "oslSkeletonDelay", "oslSkeletonDuration", "oslSkeletonMinHeight", "oslSkeletonForceReread", "oslSkeletonCircleSize", "oslSkeletonListItems", "oslSkeletonTableRows", "oslSkeletonTableCols", "oslSkeletonCardLines", "oslSkeletonBgColor"] }] });
1142
1145
  }
1143
1146
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: Oslinput, decorators: [{
1144
1147
  type: Component,
1145
- args: [{ selector: 'osl-input', standalone: false, template: "<div class=\"d-flex flex-column\">\r\n @if(label){\r\n <div [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <label class=\"label\" [class.txt-clr-red]=\"myField.touched && myField.invalid\">\r\n <span [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">{{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span></span>\r\n </label>\r\n </div>\r\n}\r\n\r\n <div class=\"input-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.plain]=\"!hasWrapper\" [class.error]=\"myField.touched && myField.invalid\" [class.input-disabled]=\"disabled\">\r\n @if(prefixIcon) {\r\n <mat-icon class=\"input-icon prefix-icon\">{{prefixIcon}}</mat-icon>\r\n }\r\n <input\r\n\r\n [type]=\"inputType\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (focus)=\"onFocusIn()\"\r\n (blur)=\"onFocusOut()\"\r\n (change)=\"onChange()\"\r\n [required]=\"required\"\r\n [disabled]=\"disabled\"\r\n [placeholder]=\"placeholder\"\r\n [attr.min]=\"min || null\"\r\n [attr.max]=\"max || null\"\r\n [attr.minlength]=\"minLength\"\r\n [attr.maxlength]=\"maxLength\"\r\n [email]=\"type === 'email'\"\r\n #myField=\"ngModel\"\r\n class=\"inner-input\"\r\n >\r\n @if(type === 'password') {\r\n <button type=\"button\" class=\"password-toggle\" (click)=\"togglePassword()\" tabindex=\"-1\">\r\n <mat-icon>{{showPassword ? 'visibility_off' : 'visibility'}}</mat-icon>\r\n </button>\r\n }\r\n @if(suffixIcon && type !== 'password') {\r\n <mat-icon class=\"input-icon suffix-icon\">{{suffixIcon}}</mat-icon>\r\n }\r\n </div>\r\n\r\n @if(myField.touched && myField.invalid) {\r\n @if(myField.errors?.['required']) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n } @else if(myField.errors?.['email']) {\r\n <mat-hint class=\"hint\">Please enter a valid email address.</mat-hint>\r\n } @else if(myField.errors?.['minlength']) {\r\n <mat-hint class=\"hint\">Minimum {{minLength}} characters required.</mat-hint>\r\n } @else if(myField.errors?.['maxlength']) {\r\n <mat-hint class=\"hint\">Maximum {{maxLength}} characters allowed.</mat-hint>\r\n } @else if(myField.errors?.['min']) {\r\n <mat-hint class=\"hint\">Value must be at least {{min}}.</mat-hint>\r\n } @else if(myField.errors?.['max']) {\r\n <mat-hint class=\"hint\">Value must be at most {{max}}.</mat-hint>\r\n }\r\n }\r\n</div>\r\n", styles: [".label{font-size:var(--osl-label-font-size);margin-bottom:5px}.input-wrapper{display:flex;align-items:center;height:var(--osl-control-height);width:100%;border-radius:var(--osl-border-radius);border:1px solid var(--osl-border-color);padding:0 8px;gap:6px;transition:border-color .5s}.input-wrapper:focus-within{border-color:var(--osl-focus-border-color)}.input-wrapper.error{border-color:var(--osl-error-color)}.input-wrapper.input-disabled{background:#f5f5f5;opacity:.7;cursor:not-allowed}.input-wrapper.plain{padding:0;border:none;height:auto;gap:0}.input-wrapper.plain .inner-input{border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);padding:5px;height:var(--osl-control-height)}.input-wrapper.plain .inner-input:focus{border-color:var(--osl-focus-border-color)}.input-wrapper.plain .inner-input.error{border-color:var(--osl-error-color)}.inner-input{flex:1;min-width:0;height:100%;border:none;outline:none;font-size:var(--osl-text-font-size);background:transparent;width:100%}.inner-input:disabled{cursor:not-allowed;background:transparent}.inner-input::placeholder{font-size:var(--osl-label-font-size);color:#aaa}.input-icon{font-size:18px;width:18px;height:18px;color:#888;flex-shrink:0;-webkit-user-select:none;user-select:none}.password-toggle{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:0;cursor:pointer;color:#888;flex-shrink:0}.password-toggle mat-icon{font-size:18px;width:18px;height:18px}.password-toggle:hover{color:#333}.hint{color:var(--osl-error-color);margin-top:2px;font-size:var(--osl-hint-font-size)}.txt-clr-red{color:var(--osl-error-color)}\n"] }]
1148
+ args: [{ selector: 'osl-input', standalone: false, template: "<div class=\"d-flex flex-column\">\r\n @if(label){\r\n <div [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <label class=\"label\" [class.txt-clr-red]=\"myField.touched && myField.invalid\">\r\n <span [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">{{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span></span>\r\n </label>\r\n </div>\r\n}\r\n\r\n <div class=\"input-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.plain]=\"!hasWrapper\" [class.error]=\"myField.touched && myField.invalid\" [class.input-disabled]=\"disabled\">\r\n @if(prefixIcon) {\r\n <mat-icon class=\"input-icon prefix-icon\">{{prefixIcon}}</mat-icon>\r\n }\r\n <input\r\n\r\n [type]=\"inputType\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (focus)=\"onFocusIn($event)\"\r\n (blur)=\"onFocusOut()\"\r\n (change)=\"onChange()\"\r\n [required]=\"required\"\r\n [disabled]=\"disabled\"\r\n [placeholder]=\"placeholder\"\r\n [attr.min]=\"min || null\"\r\n [attr.max]=\"max || null\"\r\n [attr.minlength]=\"minLength\"\r\n [attr.maxlength]=\"maxLength\"\r\n [email]=\"type === 'email'\"\r\n #myField=\"ngModel\"\r\n class=\"inner-input\"\r\n >\r\n @if(type === 'password') {\r\n <button type=\"button\" class=\"password-toggle\" (click)=\"togglePassword()\" tabindex=\"-1\">\r\n <mat-icon>{{showPassword ? 'visibility_off' : 'visibility'}}</mat-icon>\r\n </button>\r\n }\r\n @if(suffixIcon && type !== 'password') {\r\n <mat-icon class=\"input-icon suffix-icon\">{{suffixIcon}}</mat-icon>\r\n }\r\n </div>\r\n\r\n @if(myField.touched && myField.invalid) {\r\n @if(myField.errors?.['required']) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n } @else if(myField.errors?.['email']) {\r\n <mat-hint class=\"hint\">Please enter a valid email address.</mat-hint>\r\n } @else if(myField.errors?.['minlength']) {\r\n <mat-hint class=\"hint\">Minimum {{minLength}} characters required.</mat-hint>\r\n } @else if(myField.errors?.['maxlength']) {\r\n <mat-hint class=\"hint\">Maximum {{maxLength}} characters allowed.</mat-hint>\r\n } @else if(myField.errors?.['min']) {\r\n <mat-hint class=\"hint\">Value must be at least {{min}}.</mat-hint>\r\n } @else if(myField.errors?.['max']) {\r\n <mat-hint class=\"hint\">Value must be at most {{max}}.</mat-hint>\r\n }\r\n }\r\n</div>\r\n", styles: [".label{font-size:var(--osl-label-font-size);margin-bottom:5px}.input-wrapper{display:flex;align-items:center;height:var(--osl-control-height);width:100%;border-radius:var(--osl-border-radius);border:1px solid var(--osl-border-color);padding:0 8px;gap:6px;transition:border-color .5s}.input-wrapper:focus-within{border-color:var(--osl-focus-border-color)}.input-wrapper.error{border-color:var(--osl-error-color)}.input-wrapper.input-disabled{background:#f5f5f5;opacity:.7;cursor:not-allowed}.input-wrapper.plain{padding:0;border:none;height:auto;gap:0}.input-wrapper.plain .inner-input{border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);padding:5px;height:var(--osl-control-height)}.input-wrapper.plain .inner-input:focus{border-color:var(--osl-focus-border-color)}.input-wrapper.plain .inner-input.error{border-color:var(--osl-error-color)}.inner-input{flex:1;min-width:0;height:100%;border:none;outline:none;font-size:var(--osl-text-font-size);background:transparent;width:100%}.inner-input:disabled{cursor:not-allowed;background:transparent}.inner-input::placeholder{font-size:var(--osl-label-font-size);color:#aaa}.input-icon{font-size:18px;width:18px;height:18px;color:#888;flex-shrink:0;-webkit-user-select:none;user-select:none}.password-toggle{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:0;cursor:pointer;color:#888;flex-shrink:0}.password-toggle mat-icon{font-size:18px;width:18px;height:18px}.password-toggle:hover{color:#333}.hint{color:var(--osl-error-color);margin-top:2px;font-size:var(--osl-hint-font-size)}.txt-clr-red{color:var(--osl-error-color)}\n"] }]
1146
1149
  }], propDecorators: { label: [{
1147
1150
  type: Input,
1148
1151
  args: ['label']
@@ -2177,11 +2180,11 @@ class DynamicForm {
2177
2180
  elem.change(this.model, undefined, selectedObj);
2178
2181
  }
2179
2182
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DynamicForm, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2180
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DynamicForm, isStandalone: false, selector: "osl-dynamic-form", inputs: { elements: "elements", model: "model", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme" }, outputs: { modelChange: "modelChange" }, usesOnChanges: true, ngImport: i0, template: "@if(elements && elements.length > 0) {\r\n <div class=\"row align-items-center w-100\">\r\n @for(elem of elements; track elem) {\r\n @if(!(elem.hideIf ? elem.hideIf(model) : elem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: elem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n}\r\n\r\n<ng-template #formField let-elem>\r\n @if(elem.hideIf ? !elem.hideIf(model) : true) {\r\n @switch (elem.elementType) {\r\n\r\n @case (\"textbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-input\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [type]=\"elem.inputType || 'text'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [mask]=\"elem.mask || ''\"\r\n [min]=\"elem.min ?? ''\"\r\n [max]=\"elem.max ?? ''\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [prefixIcon]=\"elem.prefixIcon || ''\"\r\n [suffixIcon]=\"elem.suffixIcon || ''\"\r\n [onlyChars]=\"!!elem.onlyChars\"\r\n [decimalPortion]=\"elem.decimalPortion ?? null\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-input>\r\n </div>\r\n }\r\n\r\n @case (\"textarea\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-textarea\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [rows]=\"elem.textareaRows || 3\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [characterCounter]=\"!!elem.characterCounter\"\r\n [resize]=\"elem.resize || 'none'\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-textarea>\r\n </div>\r\n }\r\n\r\n @case (\"select\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-select\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.selectPlaceholder || 'Select...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n [clearable]=\"!!elem.clearable\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-select>\r\n </div>\r\n }\r\n\r\n @case (\"radio\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-radio\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [inline]=\"!!elem.inline\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-radio>\r\n </div>\r\n }\r\n\r\n @case (\"slide-toggle\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-slide-toggle\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [labelPosition]=\"elem.labelPosition || 'after'\"\r\n [trueLabel]=\"elem.trueLabel || ''\"\r\n [falseLabel]=\"elem.falseLabel || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-slide-toggle>\r\n </div>\r\n }\r\n\r\n @case (\"autocomplete\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-autocomplete\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.autocompletePlaceholder || 'Type to search...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n [methodName]=\"elem.apiMethod\"\r\n [service]=\"elem.apiService\"\r\n [object]=\"model[elem.objectName]\"\r\n [searchType]=\"elem.searchType\"\r\n [configMethodName]=\"elem.apiConfigMethod\"\r\n [isLister]=\"elem.isListerAutocomplete\"\r\n \r\n \r\n ></osl-autocomplete>\r\n </div>\r\n }\r\n\r\n @case (\"file-uploader\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-file-upload\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [accept]=\"elem.accept || ''\"\r\n [multiple]=\"!!elem.multiple\"\r\n [maxSize]=\"elem.maxFileSize || 0\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-file-upload>\r\n </div>\r\n }\r\n\r\n @case (\"datepicker\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-datepicker\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [dateType]=\"elem.dateType || 'date'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [minDate]=\"elem.minDate || ''\"\r\n [maxDate]=\"elem.maxDate || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-datepicker>\r\n </div>\r\n }\r\n\r\n @case (\"checkbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-checkbox\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [indeterminate]=\"!!elem.indeterminate\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-checkbox>\r\n </div>\r\n }\r\n\r\n @case (\"button\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-button\r\n \r\n [label]=\"elem.label\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n variant=\"secondary\"\r\n (clickEv)=\"elem.change ? elem.change(model) : null\"\r\n ></osl-button>\r\n </div>\r\n }\r\n\r\n @case (\"fieldset\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <fieldset class=\"osl-fieldset\">\r\n @if(elem.label) {\r\n <legend class=\"osl-fieldset-legend\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <span class=\"osl-fieldset-legend__text\">{{ elem.label }}</span>\r\n </legend>\r\n }\r\n <div class=\"row w-100 osl-fieldset-body\">\r\n @for(innerElem of elem.rows; track innerElem) {\r\n @if(!(innerElem.hideIf ? innerElem.hideIf(model) : innerElem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: innerElem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </fieldset>\r\n </div>\r\n }\r\n\r\n @case (\"templateRef\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container>\r\n\r\n \r\n </div>\r\n }\r\n @case (\"spacer\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <!-- <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container> -->\r\n\r\n \r\n </div>\r\n }\r\n\r\n }\r\n }\r\n</ng-template>\r\n", styles: [".osl-fieldset{border:1.5px solid var(--osl-border-color, #e5e7eb);border-radius:10px;padding:0 16px 16px;margin:0;background:linear-gradient(135deg,#f9fafb,#fff);box-shadow:0 1px 4px #0000000d;position:relative;transition:box-shadow .2s}.osl-fieldset:focus-within{box-shadow:0 0 0 3px #6366f114,0 2px 8px #0000000f;border-color:var(--osl-primary, #6366f1)}.osl-fieldset-legend{padding:0 6px;margin-left:8px;line-height:1;float:none;width:auto}.osl-fieldset-legend__text{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:#fff;padding:2px 10px;border:1.5px solid var(--osl-border-color, #e5e7eb);box-shadow:0 1px 3px #6366f11a}.osl-fieldset-body{margin-top:4px}\n"], dependencies: [{ kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: OslSkeletonDirective, selector: "[oslSkeleton]", inputs: ["oslSkeleton", "oslSkeletonType", "oslSkeletonAnimation", "oslSkeletonTheme", "oslSkeletonColor", "oslSkeletonHighlight", "oslSkeletonRadius", "oslSkeletonRows", "oslSkeletonRowGap", "oslSkeletonZIndex", "oslSkeletonDelay", "oslSkeletonDuration", "oslSkeletonMinHeight", "oslSkeletonForceReread", "oslSkeletonCircleSize", "oslSkeletonListItems", "oslSkeletonTableRows", "oslSkeletonTableCols", "oslSkeletonCardLines", "oslSkeletonBgColor"] }, { kind: "component", type: Oslinput, selector: "osl-input", inputs: ["label", "required", "disabled", "model", "type", "placeholder", "mask", "min", "max", "minLength", "maxLength", "prefixIcon", "suffixIcon", "skeletonLoading", "skeletonTheme", "onlyChars", "decimalPortion"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: Osltextarea, selector: "osl-textarea", inputs: ["label", "rows", "required", "disabled", "model", "placeholder", "maxLength", "minLength", "characterCounter", "resize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSelect, selector: "osl-select", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "clearable", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslRadio, selector: "osl-radio", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "inline", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSlideToggle, selector: "osl-slide-toggle", inputs: ["label", "disabled", "model", "labelPosition", "trueLabel", "falseLabel", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslAutocomplete, selector: "osl-autocomplete", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "searchType", "methodName", "configMethodName", "service", "object", "skeletonLoading", "skeletonTheme", "isLister"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslFileUpload, selector: "osl-file-upload", inputs: ["label", "required", "disabled", "model", "accept", "multiple", "maxSize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslDatepicker, selector: "osl-datepicker", inputs: ["label", "required", "disabled", "model", "dateType", "placeholder", "minDate", "maxDate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslCheckbox, selector: "osl-checkbox", inputs: ["label", "disabled", "required", "model", "indeterminate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslButton, selector: "osl-button", inputs: ["label", "icon", "variant", "size", "disabled", "loading", "type", "fullWidth"], outputs: ["clickEv"] }] });
2183
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DynamicForm, isStandalone: false, selector: "osl-dynamic-form", inputs: { elements: "elements", model: "model", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme" }, outputs: { modelChange: "modelChange" }, usesOnChanges: true, ngImport: i0, template: "@if(elements && elements.length > 0) {\r\n <div class=\"row align-items-center w-100\">\r\n @for(elem of elements; track elem) {\r\n @if(!(elem.hideIf ? elem.hideIf(model) : elem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: elem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n}\r\n\r\n<ng-template #formField let-elem>\r\n @if(elem.hideIf ? !elem.hideIf(model) : true) {\r\n @switch (elem.elementType) {\r\n\r\n @case (\"textbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-input\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [type]=\"elem.inputType || 'text'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [mask]=\"elem.mask || ''\"\r\n [min]=\"elem.min ?? ''\"\r\n [max]=\"elem.max ?? ''\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [prefixIcon]=\"elem.prefixIcon || ''\"\r\n [suffixIcon]=\"elem.suffixIcon || ''\"\r\n [onlyChars]=\"!!elem.onlyChars\"\r\n [decimalPortion]=\"elem.decimalPortion ?? null\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-input>\r\n </div>\r\n }\r\n\r\n @case (\"textarea\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-textarea\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [rows]=\"elem.textareaRows || 3\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [characterCounter]=\"!!elem.characterCounter\"\r\n [resize]=\"elem.resize || 'none'\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-textarea>\r\n </div>\r\n }\r\n\r\n @case (\"select\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-select\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.selectPlaceholder || 'Select...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n [clearable]=\"!!elem.clearable\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-select>\r\n </div>\r\n }\r\n\r\n @case (\"radio\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-radio\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [inline]=\"!!elem.inline\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-radio>\r\n </div>\r\n }\r\n\r\n @case (\"slide-toggle\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-slide-toggle\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [labelPosition]=\"elem.labelPosition || 'after'\"\r\n [trueLabel]=\"elem.trueLabel || ''\"\r\n [falseLabel]=\"elem.falseLabel || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-slide-toggle>\r\n </div>\r\n }\r\n\r\n @case (\"autocomplete\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-autocomplete\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.autocompletePlaceholder || 'Type to search...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n [methodName]=\"elem.apiMethod\"\r\n [service]=\"elem.apiService\"\r\n [object]=\"model[elem.objectName]\"\r\n [searchType]=\"elem.searchType\"\r\n [configMethodName]=\"elem.apiConfigMethod\"\r\n [isLister]=\"elem.isListerAutocomplete\"\r\n \r\n \r\n ></osl-autocomplete>\r\n </div>\r\n }\r\n\r\n @case (\"file-uploader\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-file-upload\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [accept]=\"elem.accept || ''\"\r\n [multiple]=\"!!elem.multiple\"\r\n [maxSize]=\"elem.maxFileSize || 0\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-file-upload>\r\n </div>\r\n }\r\n\r\n @case (\"datepicker\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-datepicker\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [dateType]=\"elem.dateType || 'date'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [minDate]=\"elem.minDate || ''\"\r\n [maxDate]=\"elem.maxDate || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-datepicker>\r\n </div>\r\n }\r\n\r\n @case (\"checkbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-checkbox\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [indeterminate]=\"!!elem.indeterminate\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-checkbox>\r\n </div>\r\n }\r\n\r\n @case (\"button\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-button\r\n \r\n [label]=\"elem.label\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n variant=\"secondary\"\r\n (clickEv)=\"elem.change ? elem.change(model) : null\"\r\n ></osl-button>\r\n </div>\r\n }\r\n\r\n @case (\"fieldset\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <fieldset class=\"osl-fieldset\">\r\n @if(elem.label) {\r\n <legend class=\"osl-fieldset-legend\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <span class=\"osl-fieldset-legend__text\">{{ elem.label }}</span>\r\n </legend>\r\n }\r\n <div class=\"row w-100 osl-fieldset-body\">\r\n @for(innerElem of elem.rows; track innerElem) {\r\n @if(!(innerElem.hideIf ? innerElem.hideIf(model) : innerElem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: innerElem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </fieldset>\r\n </div>\r\n }\r\n\r\n @case (\"templateRef\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container>\r\n\r\n \r\n </div>\r\n }\r\n @case (\"spacer\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <!-- <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container> -->\r\n\r\n \r\n </div>\r\n }\r\n\r\n }\r\n }\r\n</ng-template>\r\n", styles: [".osl-fieldset{border:1.5px solid var(--osl-border-color, #e5e7eb);border-radius:10px;padding:0 16px 16px;margin:0;background:linear-gradient(135deg,#f9fafb,#fff);box-shadow:0 1px 4px #0000000d;position:relative;transition:box-shadow .2s}.osl-fieldset:focus-within{box-shadow:0 0 0 3px #6366f114,0 2px 8px #0000000f;border-color:var(--osl-primary, #6366f1)}.osl-fieldset-legend{padding:0 6px;margin-left:8px;line-height:1;float:none;width:auto}.osl-fieldset-legend__text{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:#fff;padding:2px 10px;border:1.5px solid var(--osl-border-color, #e5e7eb);box-shadow:0 1px 3px #6366f11a}.osl-fieldset-body{margin-top:4px}\n"], dependencies: [{ kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: OslSkeletonDirective, selector: "[oslSkeleton]", inputs: ["oslSkeleton", "oslSkeletonType", "oslSkeletonAnimation", "oslSkeletonTheme", "oslSkeletonColor", "oslSkeletonHighlight", "oslSkeletonRadius", "oslSkeletonRows", "oslSkeletonRowGap", "oslSkeletonZIndex", "oslSkeletonDelay", "oslSkeletonDuration", "oslSkeletonMinHeight", "oslSkeletonForceReread", "oslSkeletonCircleSize", "oslSkeletonListItems", "oslSkeletonTableRows", "oslSkeletonTableCols", "oslSkeletonCardLines", "oslSkeletonBgColor"] }, { kind: "component", type: Oslinput, selector: "osl-input", inputs: ["label", "required", "disabled", "model", "type", "placeholder", "mask", "min", "max", "minLength", "maxLength", "prefixIcon", "suffixIcon", "skeletonLoading", "skeletonTheme", "onlyChars", "decimalPortion"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: Osltextarea, selector: "osl-textarea", inputs: ["label", "rows", "required", "disabled", "model", "placeholder", "maxLength", "minLength", "characterCounter", "resize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSelect, selector: "osl-select", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "clearable", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslRadio, selector: "osl-radio", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "inline", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSlideToggle, selector: "osl-slide-toggle", inputs: ["label", "disabled", "model", "labelPosition", "trueLabel", "falseLabel", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslAutocomplete, selector: "osl-autocomplete", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "searchType", "methodName", "configMethodName", "service", "object", "skeletonLoading", "skeletonTheme", "isLister"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslFileUpload, selector: "osl-file-upload", inputs: ["label", "required", "disabled", "model", "accept", "multiple", "maxSize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslDatepicker, selector: "osl-datepicker", inputs: ["label", "required", "disabled", "model", "dateType", "placeholder", "minDate", "maxDate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslCheckbox, selector: "osl-checkbox", inputs: ["label", "disabled", "required", "model", "indeterminate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslButton, selector: "osl-button", inputs: ["label", "icon", "variant", "size", "disabled", "loading", "type", "fullWidth"], outputs: ["clickEv"] }] });
2181
2184
  }
2182
2185
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DynamicForm, decorators: [{
2183
2186
  type: Component,
2184
- args: [{ selector: 'osl-dynamic-form', standalone: false, template: "@if(elements && elements.length > 0) {\r\n <div class=\"row align-items-center w-100\">\r\n @for(elem of elements; track elem) {\r\n @if(!(elem.hideIf ? elem.hideIf(model) : elem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: elem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n}\r\n\r\n<ng-template #formField let-elem>\r\n @if(elem.hideIf ? !elem.hideIf(model) : true) {\r\n @switch (elem.elementType) {\r\n\r\n @case (\"textbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-input\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [type]=\"elem.inputType || 'text'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [mask]=\"elem.mask || ''\"\r\n [min]=\"elem.min ?? ''\"\r\n [max]=\"elem.max ?? ''\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [prefixIcon]=\"elem.prefixIcon || ''\"\r\n [suffixIcon]=\"elem.suffixIcon || ''\"\r\n [onlyChars]=\"!!elem.onlyChars\"\r\n [decimalPortion]=\"elem.decimalPortion ?? null\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-input>\r\n </div>\r\n }\r\n\r\n @case (\"textarea\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-textarea\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [rows]=\"elem.textareaRows || 3\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [characterCounter]=\"!!elem.characterCounter\"\r\n [resize]=\"elem.resize || 'none'\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-textarea>\r\n </div>\r\n }\r\n\r\n @case (\"select\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-select\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.selectPlaceholder || 'Select...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n [clearable]=\"!!elem.clearable\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-select>\r\n </div>\r\n }\r\n\r\n @case (\"radio\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-radio\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [inline]=\"!!elem.inline\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-radio>\r\n </div>\r\n }\r\n\r\n @case (\"slide-toggle\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-slide-toggle\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [labelPosition]=\"elem.labelPosition || 'after'\"\r\n [trueLabel]=\"elem.trueLabel || ''\"\r\n [falseLabel]=\"elem.falseLabel || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-slide-toggle>\r\n </div>\r\n }\r\n\r\n @case (\"autocomplete\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-autocomplete\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.autocompletePlaceholder || 'Type to search...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n [methodName]=\"elem.apiMethod\"\r\n [service]=\"elem.apiService\"\r\n [object]=\"model[elem.objectName]\"\r\n [searchType]=\"elem.searchType\"\r\n [configMethodName]=\"elem.apiConfigMethod\"\r\n [isLister]=\"elem.isListerAutocomplete\"\r\n \r\n \r\n ></osl-autocomplete>\r\n </div>\r\n }\r\n\r\n @case (\"file-uploader\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-file-upload\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [accept]=\"elem.accept || ''\"\r\n [multiple]=\"!!elem.multiple\"\r\n [maxSize]=\"elem.maxFileSize || 0\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-file-upload>\r\n </div>\r\n }\r\n\r\n @case (\"datepicker\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-datepicker\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [dateType]=\"elem.dateType || 'date'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [minDate]=\"elem.minDate || ''\"\r\n [maxDate]=\"elem.maxDate || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-datepicker>\r\n </div>\r\n }\r\n\r\n @case (\"checkbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-checkbox\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf() : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [indeterminate]=\"!!elem.indeterminate\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-checkbox>\r\n </div>\r\n }\r\n\r\n @case (\"button\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-button\r\n \r\n [label]=\"elem.label\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n variant=\"secondary\"\r\n (clickEv)=\"elem.change ? elem.change(model) : null\"\r\n ></osl-button>\r\n </div>\r\n }\r\n\r\n @case (\"fieldset\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <fieldset class=\"osl-fieldset\">\r\n @if(elem.label) {\r\n <legend class=\"osl-fieldset-legend\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <span class=\"osl-fieldset-legend__text\">{{ elem.label }}</span>\r\n </legend>\r\n }\r\n <div class=\"row w-100 osl-fieldset-body\">\r\n @for(innerElem of elem.rows; track innerElem) {\r\n @if(!(innerElem.hideIf ? innerElem.hideIf(model) : innerElem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: innerElem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </fieldset>\r\n </div>\r\n }\r\n\r\n @case (\"templateRef\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container>\r\n\r\n \r\n </div>\r\n }\r\n @case (\"spacer\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <!-- <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container> -->\r\n\r\n \r\n </div>\r\n }\r\n\r\n }\r\n }\r\n</ng-template>\r\n", styles: [".osl-fieldset{border:1.5px solid var(--osl-border-color, #e5e7eb);border-radius:10px;padding:0 16px 16px;margin:0;background:linear-gradient(135deg,#f9fafb,#fff);box-shadow:0 1px 4px #0000000d;position:relative;transition:box-shadow .2s}.osl-fieldset:focus-within{box-shadow:0 0 0 3px #6366f114,0 2px 8px #0000000f;border-color:var(--osl-primary, #6366f1)}.osl-fieldset-legend{padding:0 6px;margin-left:8px;line-height:1;float:none;width:auto}.osl-fieldset-legend__text{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:#fff;padding:2px 10px;border:1.5px solid var(--osl-border-color, #e5e7eb);box-shadow:0 1px 3px #6366f11a}.osl-fieldset-body{margin-top:4px}\n"] }]
2187
+ args: [{ selector: 'osl-dynamic-form', standalone: false, template: "@if(elements && elements.length > 0) {\r\n <div class=\"row align-items-center w-100\">\r\n @for(elem of elements; track elem) {\r\n @if(!(elem.hideIf ? elem.hideIf(model) : elem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: elem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n}\r\n\r\n<ng-template #formField let-elem>\r\n @if(elem.hideIf ? !elem.hideIf(model) : true) {\r\n @switch (elem.elementType) {\r\n\r\n @case (\"textbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-input\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [type]=\"elem.inputType || 'text'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [mask]=\"elem.mask || ''\"\r\n [min]=\"elem.min ?? ''\"\r\n [max]=\"elem.max ?? ''\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [prefixIcon]=\"elem.prefixIcon || ''\"\r\n [suffixIcon]=\"elem.suffixIcon || ''\"\r\n [onlyChars]=\"!!elem.onlyChars\"\r\n [decimalPortion]=\"elem.decimalPortion ?? null\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-input>\r\n </div>\r\n }\r\n\r\n @case (\"textarea\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-textarea\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [rows]=\"elem.textareaRows || 3\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [maxLength]=\"elem.maxLength ?? null\"\r\n [minLength]=\"elem.minLength ?? null\"\r\n [characterCounter]=\"!!elem.characterCounter\"\r\n [resize]=\"elem.resize || 'none'\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-textarea>\r\n </div>\r\n }\r\n\r\n @case (\"select\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-select\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.selectPlaceholder || 'Select...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n [clearable]=\"!!elem.clearable\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-select>\r\n </div>\r\n }\r\n\r\n @case (\"radio\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-radio\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [inline]=\"!!elem.inline\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-radio>\r\n </div>\r\n }\r\n\r\n @case (\"slide-toggle\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-slide-toggle\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [labelPosition]=\"elem.labelPosition || 'after'\"\r\n [trueLabel]=\"elem.trueLabel || ''\"\r\n [falseLabel]=\"elem.falseLabel || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-slide-toggle>\r\n </div>\r\n }\r\n\r\n @case (\"autocomplete\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-autocomplete\r\n [label]=\"elem.label\"\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [datasource]=\"elem.datasource || []\"\r\n [displayField]=\"elem.displayField || ''\"\r\n [valueField]=\"elem.valueField || ''\"\r\n [placeholder]=\"elem.autocompletePlaceholder || 'Type to search...'\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n (changeEv)=\"elem.change ? onSelectChange(elem, $event) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n [methodName]=\"elem.apiMethod\"\r\n [service]=\"elem.apiService\"\r\n [object]=\"model[elem.objectName]\"\r\n [searchType]=\"elem.searchType\"\r\n [configMethodName]=\"elem.apiConfigMethod\"\r\n [isLister]=\"elem.isListerAutocomplete\"\r\n \r\n \r\n ></osl-autocomplete>\r\n </div>\r\n }\r\n\r\n @case (\"file-uploader\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-file-upload\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [accept]=\"elem.accept || ''\"\r\n [multiple]=\"!!elem.multiple\"\r\n [maxSize]=\"elem.maxFileSize || 0\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-file-upload>\r\n </div>\r\n }\r\n\r\n @case (\"datepicker\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-datepicker\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [dateType]=\"elem.dateType || 'date'\"\r\n [placeholder]=\"elem.placeholder || ''\"\r\n [minDate]=\"elem.minDate || ''\"\r\n [maxDate]=\"elem.maxDate || ''\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-datepicker>\r\n </div>\r\n }\r\n\r\n @case (\"checkbox\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-checkbox\r\n [skeletonLoading]=\"skeletonLoading\"\r\n [skeletonTheme]=\"skeletonTheme\"\r\n\r\n [label]=\"elem.label\"\r\n [disabled]=\"elem.disabledIf ? elem.disabledIf(model) : !!elem.disabled\"\r\n [required]=\"elem.requiredIf ? elem.requiredIf(model) : !!elem.required\"\r\n [indeterminate]=\"!!elem.indeterminate\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-checkbox>\r\n </div>\r\n }\r\n\r\n @case (\"button\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-button\r\n \r\n [label]=\"elem.label\"\r\n [loading]=\"elem.loadingIf ? elem.loadingIf(model) : false\"\r\n variant=\"secondary\"\r\n (clickEv)=\"elem.change ? elem.change(model) : null\"\r\n ></osl-button>\r\n </div>\r\n }\r\n\r\n @case (\"fieldset\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <fieldset class=\"osl-fieldset\">\r\n @if(elem.label) {\r\n <legend class=\"osl-fieldset-legend\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n <span class=\"osl-fieldset-legend__text\">{{ elem.label }}</span>\r\n </legend>\r\n }\r\n <div class=\"row w-100 osl-fieldset-body\">\r\n @for(innerElem of elem.rows; track innerElem) {\r\n @if(!(innerElem.hideIf ? innerElem.hideIf(model) : innerElem.hide)) {\r\n <ng-container *ngTemplateOutlet=\"formField; context: { $implicit: innerElem }\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </fieldset>\r\n </div>\r\n }\r\n\r\n @case (\"templateRef\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container>\r\n\r\n \r\n </div>\r\n }\r\n @case (\"spacer\"){\r\n <div [class]=\"'col-md-'+elem.columns+' mt-3'\">\r\n <!-- <ng-container *ngTemplateOutlet=\"elem.templateRef; context: { $implicit: elem}\"></ng-container> -->\r\n\r\n \r\n </div>\r\n }\r\n\r\n }\r\n }\r\n</ng-template>\r\n", styles: [".osl-fieldset{border:1.5px solid var(--osl-border-color, #e5e7eb);border-radius:10px;padding:0 16px 16px;margin:0;background:linear-gradient(135deg,#f9fafb,#fff);box-shadow:0 1px 4px #0000000d;position:relative;transition:box-shadow .2s}.osl-fieldset:focus-within{box-shadow:0 0 0 3px #6366f114,0 2px 8px #0000000f;border-color:var(--osl-primary, #6366f1)}.osl-fieldset-legend{padding:0 6px;margin-left:8px;line-height:1;float:none;width:auto}.osl-fieldset-legend__text{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:#fff;padding:2px 10px;border:1.5px solid var(--osl-border-color, #e5e7eb);box-shadow:0 1px 3px #6366f11a}.osl-fieldset-body{margin-top:4px}\n"] }]
2185
2188
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { elements: [{
2186
2189
  type: Input,
2187
2190
  args: ['elements']
@@ -2366,11 +2369,11 @@ class OslGrid {
2366
2369
  return raw !== null && raw !== undefined && raw !== '' ? raw : '--';
2367
2370
  }
2368
2371
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
2369
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslGrid, isStandalone: false, selector: "osl-grid", inputs: { columns: "columns", datasource: "datasource", isPaginated: "isPaginated", pageSize: "pageSize", autoMode: "autoMode", totalRecords: "totalRecords", tableHeight: "tableHeight", loading: "loading", isSelectable: "isSelectable", moreMenuActions: "moreMenuActions", canEdit: "canEdit", canDelete: "canDelete" }, outputs: { datasourceChange: "datasourceChange", pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", editClick: "editClick", deleteClick: "deleteClick", onRowClick: "onRowClick" }, host: { listeners: { "document:click": "onDocumentClick()" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"osl-grid-wrapper\">\r\n\r\n <div class=\"osl-grid-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-grid-table\">\r\n <thead class=\"osl-grid-thead\">\r\n <tr>\r\n @if (loading && columns.length === 0) {\r\n @for (sk of skeletonColumns; track $index) {\r\n <th class=\"osl-grid-th osl-grid-th--skeleton\">\r\n <div class=\"osl-skeleton osl-skeleton--header\"></div>\r\n </th>\r\n }\r\n } @else {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <th\r\n class=\"osl-grid-th\"\r\n [class.osl-grid-th--last]=\"last\"\r\n [class.osl-grid-th--actions]=\"col.isActions\"\r\n (click)=\"sort(col.key, col.isActions)\"\r\n >\r\n @if (!col.isActions) {\r\n <span class=\"osl-grid-th-inner\">\r\n {{ col.label }}\r\n <span class=\"osl-grid-sort-icon\" [class.osl-grid-sort-icon--active]=\"sortKey === col.key\">\r\n @if (sortKey === col.key) {\r\n {{ sortAsc ? '\u2191' : '\u2193' }}\r\n } @else {\r\n <span class=\"osl-grid-sort-icon--idle\">\u21C5</span>\r\n }\r\n </span>\r\n </span>\r\n }\r\n </th>\r\n }\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-grid-row osl-grid-row--skeleton\">\r\n @if (columns.length > 0) {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\" [class.osl-grid-td--actions]=\"col.isActions\">\r\n @if (col.isActions) {\r\n <div class=\"osl-skeleton osl-skeleton--actions\"></div>\r\n } @else {\r\n <div class=\"osl-skeleton\"></div>\r\n }\r\n </td>\r\n }\r\n } @else {\r\n @for (sk2 of skeletonColumns; track $index; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">\r\n <div class=\"osl-skeleton\"></div>\r\n </td>\r\n }\r\n }\r\n </tr>\r\n }\r\n } @else {\r\n @if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length\" class=\"osl-grid-empty\">\r\n <div class=\"d-flex align-items-center justify-content-center floating-element\">\r\n <div class=\"mx-4\">\r\n <p class=\"f-s-20 f-w-600 text-start\">No Records match the <br> current filters.</p>\r\n <p class=\"text-start\">Expecting to see new Records? Try again in <br> a few seconds as the system catches up</p>\r\n </div>\r\n <i class=\"icon\"></i>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n @for (row of pagedData; track $index; let rowIdx = $index) {\r\n <tr class=\"osl-grid-row\" [class.pointer]=\"isSelectable\" (click)=\"onRowClick.emit(row)\">\r\n @for (col of columns; track col.key; let last = $last) {\r\n @if (col.isActions) {\r\n <td class=\"osl-grid-td osl-grid-td--actions\" [class.osl-grid-td--last]=\"last\">\r\n @if (moreMenuActions.length > 0 && hasVisibleActions(row)) {\r\n <div class=\"osl-menu-wrapper\">\r\n <button class=\"osl-grid-icon-btn\" (click)=\"toggleMenu(rowIdx, $event)\" title=\"More actions\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n @if (openMenuIndex === rowIdx) {\r\n <div class=\"osl-custom-menu\"\r\n [style.top.px]=\"menuPosition.top\"\r\n [style.left.px]=\"menuPosition.left\">\r\n <div class=\"osl-custom-menu-header\">Actions</div>\r\n @for (action of moreMenuActions; track $index) {\r\n @if (!action.hideIf || !action.hideIf(row)) {\r\n <button class=\"osl-custom-menu-item\" (click)=\"action.click(row); closeMenu(); $event.stopPropagation()\">\r\n <span class=\"osl-custom-menu-dot\"></span>\r\n {{ getActionLabel(action, row) }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if(canEdit){\r\n <button class=\"osl-grid-icon-btn\" (click)=\"$event.stopPropagation(); editClick.emit(row)\" title=\"Edit\">\r\n <mat-icon>mode_edit_outline</mat-icon>\r\n </button>\r\n }\r\n @if(canDelete){\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"$event.stopPropagation(); deleteClick.emit(row)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n } @else {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">{{ getCellValue(row, col) }}</td>\r\n }\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-grid-pagination\">\r\n\r\n <span class=\"osl-grid-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} records\r\n } @else {\r\n No records\r\n }\r\n </span>\r\n\r\n <div class=\"osl-grid-pagination__controls\">\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\" title=\"First page\">\r\n \u00AB\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\" title=\"Previous page\">\r\n \u2039 Prev\r\n </button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-grid-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-grid-page-btn osl-grid-page-btn--num\"\r\n [class.osl-grid-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\"\r\n >\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Next page\">\r\n Next \u203A\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Last page\">\r\n \u00BB\r\n </button>\r\n </div>\r\n\r\n <div class=\"osl-grid-pagination__size\">\r\n <select class=\"osl-grid-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-grid-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);overflow:hidden;background:#fff}.osl-grid-table-container{overflow-x:auto;overflow-y:auto;min-height:200px}.osl-grid-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-grid-thead{position:sticky;top:0;z-index:2}.osl-grid-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 14px;text-align:left;border-bottom:2px solid var(--osl-border-color);border-right:1px solid var(--osl-border-color);white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none}.osl-grid-th:hover{background:#e5e7eb}.osl-grid-th--last{border-right:none}.osl-grid-th-inner{display:inline-flex;align-items:center;gap:6px}.osl-grid-sort-icon{font-size:11px;color:#9ca3af}.osl-grid-sort-icon--active{color:var(--osl-primary)}.osl-grid-sort-icon--idle{opacity:.35}.osl-grid-row{border-bottom:1px solid #f3f4f6;transition:background .12s}.osl-grid-row:hover{background:#f9fafb}.osl-grid-row:last-child{border-bottom:none}.osl-grid-td{padding:10px 14px;color:#111827;font-size:var(--osl-text-font-size);vertical-align:middle;white-space:nowrap;border-right:1px solid #f3f4f6}.osl-grid-td--last{border-right:none}.osl-grid-empty{padding:48px 16px;text-align:center;color:#9ca3af;font-size:var(--osl-text-font-size)}.osl-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-grid-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-grid-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-grid-pagination__size{display:flex;align-items:center;min-width:120px;justify-content:flex-end}.osl-grid-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-grid-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-grid-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-grid-page-btn--nav{font-size:12px;color:#6b7280}.osl-grid-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-grid-page-btn--active{background:var(--osl-primary);border-color:var(--osl-primary);color:#fff;font-weight:600}.osl-grid-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover);border-color:var(--osl-primary-hover)}.osl-grid-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-grid-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-grid-page-size:focus{border-color:var(--osl-focus-border-color)}.osl-grid-th--actions{width:80px;min-width:80px;cursor:default;text-align:center}.osl-grid-th--actions:hover{background:#f3f4f6}.osl-grid-td--actions{width:80px;min-width:80px;text-align:center;padding:6px 8px;white-space:nowrap}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}.osl-menu-wrapper{position:relative;display:inline-flex}.osl-custom-menu{position:fixed;z-index:9999;min-width:190px;background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 8px 24px #0000001f,0 2px 8px #00000012;overflow:hidden;animation:osl-menu-appear .15s cubic-bezier(.16,1,.3,1)}@keyframes osl-menu-appear{0%{opacity:0;transform:translateY(-8px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.osl-custom-menu-header{padding:8px 14px 6px;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#9ca3af;border-bottom:1px solid #f3f4f6;-webkit-user-select:none;user-select:none}.osl-custom-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:10px 14px;background:transparent;border:none;border-left:3px solid transparent;border-bottom:1px solid #f9fafb;text-align:left;font-size:13px;font-weight:500;font-family:inherit;color:#374151;cursor:pointer;white-space:nowrap;transition:background .12s,color .12s,border-left-color .12s}.osl-custom-menu-item:last-child{border-bottom:none}.osl-custom-menu-item:hover{background:#f5f3ff;color:var(--osl-primary);border-left-color:var(--osl-primary)}.osl-custom-menu-item:hover .osl-custom-menu-dot{background:var(--osl-primary);box-shadow:0 0 0 3px #6366f12e}.osl-custom-menu-dot{flex-shrink:0;width:6px;height:6px;border-radius:50%;background:#d1d5db;transition:background .12s,box-shadow .12s}@keyframes osl-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-skeleton{height:14px;border-radius:4px;background:#e5e7eb;animation:osl-skeleton-pulse 1.4s ease-in-out infinite;width:80%}.osl-skeleton--actions{width:52px;margin:0 auto}.osl-skeleton--header{height:11px;width:65%;background:#d1d5db;border-radius:3px}.osl-grid-th--skeleton{cursor:default;pointer-events:none}.osl-grid-row--skeleton{pointer-events:none}.icon{background-repeat:no-repeat;background-position:center;display:inline-block!important;vertical-align:middle;width:18%;height:250px;background-image:url('data:image/svg+xml,<svg width=\"147\" height=\"134\" viewBox=\"0 0 147 134\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <g fill=\"none\" fill-rule=\"evenodd\">%0D%0A <path d=\"M2.143 94.537c-2.858-1.65-2.858-4.35 0-6l66.1-38.163c2.858-1.65 7.534-1.65 10.392 0l66.101 38.163c2.858 1.65 2.858 4.35 0 6l-66.1 38.163c-2.859 1.65-7.535 1.65-10.393 0l-66.1-38.162z\" fill=\"%23EAF0F6\" fill-opacity=\".75\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M82.974 42.77c-5.498 1.128-11.537 1.124-17.03-.013L46.688 88.68h.007c1.089-3.023 3.637-5.9 7.679-8.233 11.065-6.39 29.172-6.39 40.237 0 2.902 1.674 5.02 3.632 6.4 5.719L82.975 42.77z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114zM74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265\" fill=\"%23FFF\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748\" fill=\"%23FFF\"/>%0D%0A <path d=\"M101.012 86.166L82.974 42.77c-5.499 1.127-11.537 1.123-17.031-.014L46.687 88.679h.007\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M121.68 10.236l-11.902 4.361M115.666 23.734l-5.239-2.47M119 25.306l-.753-.356M106.763 7.402l-.803 1.704M109.781 1l-1.81 3.84\" stroke=\"%23CBD6E5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A </g>%0D%0A</svg>%0D%0A');background-size:100%;animation:moveUpDown 3s ease-in-out infinite}@keyframes moveUpDown{0%,to{transform:translateY(0)}50%{transform:translateY(-15px)}}.pointer{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
2372
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslGrid, isStandalone: false, selector: "osl-grid", inputs: { columns: "columns", datasource: "datasource", isPaginated: "isPaginated", pageSize: "pageSize", autoMode: "autoMode", totalRecords: "totalRecords", tableHeight: "tableHeight", loading: "loading", isSelectable: "isSelectable", moreMenuActions: "moreMenuActions", canEdit: "canEdit", canDelete: "canDelete" }, outputs: { datasourceChange: "datasourceChange", pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", editClick: "editClick", deleteClick: "deleteClick", onRowClick: "onRowClick" }, host: { listeners: { "document:click": "onDocumentClick()" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"osl-grid-wrapper\">\r\n\r\n <div class=\"osl-grid-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-grid-table\">\r\n <thead class=\"osl-grid-thead\">\r\n <tr>\r\n @if (loading && columns.length === 0) {\r\n @for (sk of skeletonColumns; track $index) {\r\n <th class=\"osl-grid-th osl-grid-th--skeleton\">\r\n <div class=\"osl-skeleton osl-skeleton--header\"></div>\r\n </th>\r\n }\r\n } @else {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <th\r\n class=\"osl-grid-th\"\r\n [class.osl-grid-th--last]=\"last\"\r\n [class.osl-grid-th--actions]=\"col.isActions\"\r\n (click)=\"sort(col.key, col.isActions)\"\r\n >\r\n @if (!col.isActions) {\r\n <span class=\"osl-grid-th-inner\">\r\n {{ col.label }}\r\n <span class=\"osl-grid-sort-icon\" [class.osl-grid-sort-icon--active]=\"sortKey === col.key\">\r\n @if (sortKey === col.key) {\r\n {{ sortAsc ? '\u2191' : '\u2193' }}\r\n } @else {\r\n <span class=\"osl-grid-sort-icon--idle\">\u21C5</span>\r\n }\r\n </span>\r\n </span>\r\n }\r\n </th>\r\n }\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-grid-row osl-grid-row--skeleton\">\r\n @if (columns.length > 0) {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\" [class.osl-grid-td--actions]=\"col.isActions\">\r\n @if (col.isActions) {\r\n <div class=\"osl-skeleton osl-skeleton--actions\"></div>\r\n } @else {\r\n <div class=\"osl-skeleton\"></div>\r\n }\r\n </td>\r\n }\r\n } @else {\r\n @for (sk2 of skeletonColumns; track $index; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">\r\n <div class=\"osl-skeleton\"></div>\r\n </td>\r\n }\r\n }\r\n </tr>\r\n }\r\n } @else {\r\n @if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length\" class=\"osl-grid-empty\">\r\n <div class=\"d-flex align-items-center justify-content-center floating-element\">\r\n <div class=\"mx-4\">\r\n <p class=\"f-s-20 f-w-600 text-start\">No Records match the <br> current filters.</p>\r\n <p class=\"text-start\">Expecting to see new Records? Try again in <br> a few seconds as the system catches up</p>\r\n </div>\r\n <i class=\"icon\"></i>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n @for (row of pagedData; track $index; let rowIdx = $index) {\r\n <tr class=\"osl-grid-row\" [class.pointer]=\"isSelectable\" (click)=\"onRowClick.emit(row)\">\r\n @for (col of columns; track col.key; let last = $last) {\r\n @if (col.isActions) {\r\n <td class=\"osl-grid-td osl-grid-td--actions\" [class.osl-grid-td--last]=\"last\">\r\n @if (moreMenuActions.length > 0 && hasVisibleActions(row)) {\r\n <div class=\"osl-menu-wrapper\">\r\n <button class=\"osl-grid-icon-btn\" (click)=\"toggleMenu(rowIdx, $event)\" title=\"More actions\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n @if (openMenuIndex === rowIdx) {\r\n <div class=\"osl-custom-menu\"\r\n [style.top.px]=\"menuPosition.top\"\r\n [style.left.px]=\"menuPosition.left\">\r\n <div class=\"osl-custom-menu-header\">Actions</div>\r\n @for (action of moreMenuActions; track $index) {\r\n @if (!action.hideIf || !action.hideIf(row)) {\r\n <button class=\"osl-custom-menu-item\" (click)=\"action.click(row); closeMenu(); $event.stopPropagation()\">\r\n <span class=\"osl-custom-menu-dot\"></span>\r\n {{ getActionLabel(action, row) }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if(canEdit){\r\n <button class=\"osl-grid-icon-btn\" (click)=\"$event.stopPropagation(); editClick.emit(row)\" title=\"Edit\">\r\n <mat-icon>mode_edit_outline</mat-icon>\r\n </button>\r\n }\r\n @if(canDelete){\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"$event.stopPropagation(); deleteClick.emit(row)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n } @else {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">\r\n @switch (col.displayType) {\r\n @case ('date') { {{ row[col.key] | date }} }\r\n @case ('datetime') { {{ row[col.key] | date:'medium' }} }\r\n @case ('time') { {{ row[col.key] | date:'shortTime' }} }\r\n @default { {{ getCellValue(row, col) }} }\r\n }\r\n </td>\r\n }\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-grid-pagination\">\r\n\r\n <span class=\"osl-grid-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} records\r\n } @else {\r\n No records\r\n }\r\n </span>\r\n\r\n <div class=\"osl-grid-pagination__controls\">\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\" title=\"First page\">\r\n \u00AB\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\" title=\"Previous page\">\r\n \u2039 Prev\r\n </button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-grid-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-grid-page-btn osl-grid-page-btn--num\"\r\n [class.osl-grid-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\"\r\n >\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Next page\">\r\n Next \u203A\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Last page\">\r\n \u00BB\r\n </button>\r\n </div>\r\n\r\n <div class=\"osl-grid-pagination__size\">\r\n <select class=\"osl-grid-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-grid-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);overflow:hidden;background:#fff}.osl-grid-table-container{overflow-x:auto;overflow-y:auto;min-height:200px}.osl-grid-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-grid-thead{position:sticky;top:0;z-index:2}.osl-grid-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 14px;text-align:left;border-bottom:2px solid var(--osl-border-color);border-right:1px solid var(--osl-border-color);white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none}.osl-grid-th:hover{background:#e5e7eb}.osl-grid-th--last{border-right:none}.osl-grid-th-inner{display:inline-flex;align-items:center;gap:6px}.osl-grid-sort-icon{font-size:11px;color:#9ca3af}.osl-grid-sort-icon--active{color:var(--osl-primary)}.osl-grid-sort-icon--idle{opacity:.35}.osl-grid-row{border-bottom:1px solid #f3f4f6;transition:background .12s}.osl-grid-row:hover{background:#f9fafb}.osl-grid-row:last-child{border-bottom:none}.osl-grid-td{padding:10px 14px;color:#111827;font-size:var(--osl-text-font-size);vertical-align:middle;white-space:nowrap;border-right:1px solid #f3f4f6}.osl-grid-td--last{border-right:none}.osl-grid-empty{padding:48px 16px;text-align:center;color:#9ca3af;font-size:var(--osl-text-font-size)}.osl-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-grid-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-grid-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-grid-pagination__size{display:flex;align-items:center;min-width:120px;justify-content:flex-end}.osl-grid-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-grid-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-grid-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-grid-page-btn--nav{font-size:12px;color:#6b7280}.osl-grid-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-grid-page-btn--active{background:var(--osl-primary);border-color:var(--osl-primary);color:#fff;font-weight:600}.osl-grid-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover);border-color:var(--osl-primary-hover)}.osl-grid-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-grid-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-grid-page-size:focus{border-color:var(--osl-focus-border-color)}.osl-grid-th--actions{width:80px;min-width:80px;cursor:default;text-align:center}.osl-grid-th--actions:hover{background:#f3f4f6}.osl-grid-td--actions{width:80px;min-width:80px;text-align:center;padding:6px 8px;white-space:nowrap}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}.osl-menu-wrapper{position:relative;display:inline-flex}.osl-custom-menu{position:fixed;z-index:9999;min-width:190px;background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 8px 24px #0000001f,0 2px 8px #00000012;overflow:hidden;animation:osl-menu-appear .15s cubic-bezier(.16,1,.3,1)}@keyframes osl-menu-appear{0%{opacity:0;transform:translateY(-8px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.osl-custom-menu-header{padding:8px 14px 6px;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#9ca3af;border-bottom:1px solid #f3f4f6;-webkit-user-select:none;user-select:none}.osl-custom-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:10px 14px;background:transparent;border:none;border-left:3px solid transparent;border-bottom:1px solid #f9fafb;text-align:left;font-size:13px;font-weight:500;font-family:inherit;color:#374151;cursor:pointer;white-space:nowrap;transition:background .12s,color .12s,border-left-color .12s}.osl-custom-menu-item:last-child{border-bottom:none}.osl-custom-menu-item:hover{background:#f5f3ff;color:var(--osl-primary);border-left-color:var(--osl-primary)}.osl-custom-menu-item:hover .osl-custom-menu-dot{background:var(--osl-primary);box-shadow:0 0 0 3px #6366f12e}.osl-custom-menu-dot{flex-shrink:0;width:6px;height:6px;border-radius:50%;background:#d1d5db;transition:background .12s,box-shadow .12s}@keyframes osl-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-skeleton{height:14px;border-radius:4px;background:#e5e7eb;animation:osl-skeleton-pulse 1.4s ease-in-out infinite;width:80%}.osl-skeleton--actions{width:52px;margin:0 auto}.osl-skeleton--header{height:11px;width:65%;background:#d1d5db;border-radius:3px}.osl-grid-th--skeleton{cursor:default;pointer-events:none}.osl-grid-row--skeleton{pointer-events:none}.icon{background-repeat:no-repeat;background-position:center;display:inline-block!important;vertical-align:middle;width:18%;height:250px;background-image:url('data:image/svg+xml,<svg width=\"147\" height=\"134\" viewBox=\"0 0 147 134\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <g fill=\"none\" fill-rule=\"evenodd\">%0D%0A <path d=\"M2.143 94.537c-2.858-1.65-2.858-4.35 0-6l66.1-38.163c2.858-1.65 7.534-1.65 10.392 0l66.101 38.163c2.858 1.65 2.858 4.35 0 6l-66.1 38.163c-2.859 1.65-7.535 1.65-10.393 0l-66.1-38.162z\" fill=\"%23EAF0F6\" fill-opacity=\".75\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M82.974 42.77c-5.498 1.128-11.537 1.124-17.03-.013L46.688 88.68h.007c1.089-3.023 3.637-5.9 7.679-8.233 11.065-6.39 29.172-6.39 40.237 0 2.902 1.674 5.02 3.632 6.4 5.719L82.975 42.77z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114zM74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265\" fill=\"%23FFF\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748\" fill=\"%23FFF\"/>%0D%0A <path d=\"M101.012 86.166L82.974 42.77c-5.499 1.127-11.537 1.123-17.031-.014L46.687 88.679h.007\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M121.68 10.236l-11.902 4.361M115.666 23.734l-5.239-2.47M119 25.306l-.753-.356M106.763 7.402l-.803 1.704M109.781 1l-1.81 3.84\" stroke=\"%23CBD6E5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A </g>%0D%0A</svg>%0D%0A');background-size:100%;animation:moveUpDown 3s ease-in-out infinite}@keyframes moveUpDown{0%,to{transform:translateY(0)}50%{transform:translateY(-15px)}}.pointer{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1$2.DatePipe, name: "date" }] });
2370
2373
  }
2371
2374
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslGrid, decorators: [{
2372
2375
  type: Component,
2373
- args: [{ selector: 'osl-grid', standalone: false, template: "<div class=\"osl-grid-wrapper\">\r\n\r\n <div class=\"osl-grid-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-grid-table\">\r\n <thead class=\"osl-grid-thead\">\r\n <tr>\r\n @if (loading && columns.length === 0) {\r\n @for (sk of skeletonColumns; track $index) {\r\n <th class=\"osl-grid-th osl-grid-th--skeleton\">\r\n <div class=\"osl-skeleton osl-skeleton--header\"></div>\r\n </th>\r\n }\r\n } @else {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <th\r\n class=\"osl-grid-th\"\r\n [class.osl-grid-th--last]=\"last\"\r\n [class.osl-grid-th--actions]=\"col.isActions\"\r\n (click)=\"sort(col.key, col.isActions)\"\r\n >\r\n @if (!col.isActions) {\r\n <span class=\"osl-grid-th-inner\">\r\n {{ col.label }}\r\n <span class=\"osl-grid-sort-icon\" [class.osl-grid-sort-icon--active]=\"sortKey === col.key\">\r\n @if (sortKey === col.key) {\r\n {{ sortAsc ? '\u2191' : '\u2193' }}\r\n } @else {\r\n <span class=\"osl-grid-sort-icon--idle\">\u21C5</span>\r\n }\r\n </span>\r\n </span>\r\n }\r\n </th>\r\n }\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-grid-row osl-grid-row--skeleton\">\r\n @if (columns.length > 0) {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\" [class.osl-grid-td--actions]=\"col.isActions\">\r\n @if (col.isActions) {\r\n <div class=\"osl-skeleton osl-skeleton--actions\"></div>\r\n } @else {\r\n <div class=\"osl-skeleton\"></div>\r\n }\r\n </td>\r\n }\r\n } @else {\r\n @for (sk2 of skeletonColumns; track $index; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">\r\n <div class=\"osl-skeleton\"></div>\r\n </td>\r\n }\r\n }\r\n </tr>\r\n }\r\n } @else {\r\n @if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length\" class=\"osl-grid-empty\">\r\n <div class=\"d-flex align-items-center justify-content-center floating-element\">\r\n <div class=\"mx-4\">\r\n <p class=\"f-s-20 f-w-600 text-start\">No Records match the <br> current filters.</p>\r\n <p class=\"text-start\">Expecting to see new Records? Try again in <br> a few seconds as the system catches up</p>\r\n </div>\r\n <i class=\"icon\"></i>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n @for (row of pagedData; track $index; let rowIdx = $index) {\r\n <tr class=\"osl-grid-row\" [class.pointer]=\"isSelectable\" (click)=\"onRowClick.emit(row)\">\r\n @for (col of columns; track col.key; let last = $last) {\r\n @if (col.isActions) {\r\n <td class=\"osl-grid-td osl-grid-td--actions\" [class.osl-grid-td--last]=\"last\">\r\n @if (moreMenuActions.length > 0 && hasVisibleActions(row)) {\r\n <div class=\"osl-menu-wrapper\">\r\n <button class=\"osl-grid-icon-btn\" (click)=\"toggleMenu(rowIdx, $event)\" title=\"More actions\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n @if (openMenuIndex === rowIdx) {\r\n <div class=\"osl-custom-menu\"\r\n [style.top.px]=\"menuPosition.top\"\r\n [style.left.px]=\"menuPosition.left\">\r\n <div class=\"osl-custom-menu-header\">Actions</div>\r\n @for (action of moreMenuActions; track $index) {\r\n @if (!action.hideIf || !action.hideIf(row)) {\r\n <button class=\"osl-custom-menu-item\" (click)=\"action.click(row); closeMenu(); $event.stopPropagation()\">\r\n <span class=\"osl-custom-menu-dot\"></span>\r\n {{ getActionLabel(action, row) }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if(canEdit){\r\n <button class=\"osl-grid-icon-btn\" (click)=\"$event.stopPropagation(); editClick.emit(row)\" title=\"Edit\">\r\n <mat-icon>mode_edit_outline</mat-icon>\r\n </button>\r\n }\r\n @if(canDelete){\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"$event.stopPropagation(); deleteClick.emit(row)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n } @else {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">{{ getCellValue(row, col) }}</td>\r\n }\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-grid-pagination\">\r\n\r\n <span class=\"osl-grid-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} records\r\n } @else {\r\n No records\r\n }\r\n </span>\r\n\r\n <div class=\"osl-grid-pagination__controls\">\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\" title=\"First page\">\r\n \u00AB\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\" title=\"Previous page\">\r\n \u2039 Prev\r\n </button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-grid-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-grid-page-btn osl-grid-page-btn--num\"\r\n [class.osl-grid-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\"\r\n >\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Next page\">\r\n Next \u203A\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Last page\">\r\n \u00BB\r\n </button>\r\n </div>\r\n\r\n <div class=\"osl-grid-pagination__size\">\r\n <select class=\"osl-grid-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-grid-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);overflow:hidden;background:#fff}.osl-grid-table-container{overflow-x:auto;overflow-y:auto;min-height:200px}.osl-grid-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-grid-thead{position:sticky;top:0;z-index:2}.osl-grid-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 14px;text-align:left;border-bottom:2px solid var(--osl-border-color);border-right:1px solid var(--osl-border-color);white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none}.osl-grid-th:hover{background:#e5e7eb}.osl-grid-th--last{border-right:none}.osl-grid-th-inner{display:inline-flex;align-items:center;gap:6px}.osl-grid-sort-icon{font-size:11px;color:#9ca3af}.osl-grid-sort-icon--active{color:var(--osl-primary)}.osl-grid-sort-icon--idle{opacity:.35}.osl-grid-row{border-bottom:1px solid #f3f4f6;transition:background .12s}.osl-grid-row:hover{background:#f9fafb}.osl-grid-row:last-child{border-bottom:none}.osl-grid-td{padding:10px 14px;color:#111827;font-size:var(--osl-text-font-size);vertical-align:middle;white-space:nowrap;border-right:1px solid #f3f4f6}.osl-grid-td--last{border-right:none}.osl-grid-empty{padding:48px 16px;text-align:center;color:#9ca3af;font-size:var(--osl-text-font-size)}.osl-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-grid-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-grid-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-grid-pagination__size{display:flex;align-items:center;min-width:120px;justify-content:flex-end}.osl-grid-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-grid-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-grid-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-grid-page-btn--nav{font-size:12px;color:#6b7280}.osl-grid-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-grid-page-btn--active{background:var(--osl-primary);border-color:var(--osl-primary);color:#fff;font-weight:600}.osl-grid-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover);border-color:var(--osl-primary-hover)}.osl-grid-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-grid-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-grid-page-size:focus{border-color:var(--osl-focus-border-color)}.osl-grid-th--actions{width:80px;min-width:80px;cursor:default;text-align:center}.osl-grid-th--actions:hover{background:#f3f4f6}.osl-grid-td--actions{width:80px;min-width:80px;text-align:center;padding:6px 8px;white-space:nowrap}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}.osl-menu-wrapper{position:relative;display:inline-flex}.osl-custom-menu{position:fixed;z-index:9999;min-width:190px;background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 8px 24px #0000001f,0 2px 8px #00000012;overflow:hidden;animation:osl-menu-appear .15s cubic-bezier(.16,1,.3,1)}@keyframes osl-menu-appear{0%{opacity:0;transform:translateY(-8px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.osl-custom-menu-header{padding:8px 14px 6px;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#9ca3af;border-bottom:1px solid #f3f4f6;-webkit-user-select:none;user-select:none}.osl-custom-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:10px 14px;background:transparent;border:none;border-left:3px solid transparent;border-bottom:1px solid #f9fafb;text-align:left;font-size:13px;font-weight:500;font-family:inherit;color:#374151;cursor:pointer;white-space:nowrap;transition:background .12s,color .12s,border-left-color .12s}.osl-custom-menu-item:last-child{border-bottom:none}.osl-custom-menu-item:hover{background:#f5f3ff;color:var(--osl-primary);border-left-color:var(--osl-primary)}.osl-custom-menu-item:hover .osl-custom-menu-dot{background:var(--osl-primary);box-shadow:0 0 0 3px #6366f12e}.osl-custom-menu-dot{flex-shrink:0;width:6px;height:6px;border-radius:50%;background:#d1d5db;transition:background .12s,box-shadow .12s}@keyframes osl-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-skeleton{height:14px;border-radius:4px;background:#e5e7eb;animation:osl-skeleton-pulse 1.4s ease-in-out infinite;width:80%}.osl-skeleton--actions{width:52px;margin:0 auto}.osl-skeleton--header{height:11px;width:65%;background:#d1d5db;border-radius:3px}.osl-grid-th--skeleton{cursor:default;pointer-events:none}.osl-grid-row--skeleton{pointer-events:none}.icon{background-repeat:no-repeat;background-position:center;display:inline-block!important;vertical-align:middle;width:18%;height:250px;background-image:url('data:image/svg+xml,<svg width=\"147\" height=\"134\" viewBox=\"0 0 147 134\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <g fill=\"none\" fill-rule=\"evenodd\">%0D%0A <path d=\"M2.143 94.537c-2.858-1.65-2.858-4.35 0-6l66.1-38.163c2.858-1.65 7.534-1.65 10.392 0l66.101 38.163c2.858 1.65 2.858 4.35 0 6l-66.1 38.163c-2.859 1.65-7.535 1.65-10.393 0l-66.1-38.162z\" fill=\"%23EAF0F6\" fill-opacity=\".75\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M82.974 42.77c-5.498 1.128-11.537 1.124-17.03-.013L46.688 88.68h.007c1.089-3.023 3.637-5.9 7.679-8.233 11.065-6.39 29.172-6.39 40.237 0 2.902 1.674 5.02 3.632 6.4 5.719L82.975 42.77z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114zM74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265\" fill=\"%23FFF\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748\" fill=\"%23FFF\"/>%0D%0A <path d=\"M101.012 86.166L82.974 42.77c-5.499 1.127-11.537 1.123-17.031-.014L46.687 88.679h.007\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M121.68 10.236l-11.902 4.361M115.666 23.734l-5.239-2.47M119 25.306l-.753-.356M106.763 7.402l-.803 1.704M109.781 1l-1.81 3.84\" stroke=\"%23CBD6E5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A </g>%0D%0A</svg>%0D%0A');background-size:100%;animation:moveUpDown 3s ease-in-out infinite}@keyframes moveUpDown{0%,to{transform:translateY(0)}50%{transform:translateY(-15px)}}.pointer{cursor:pointer}\n"] }]
2376
+ args: [{ selector: 'osl-grid', standalone: false, template: "<div class=\"osl-grid-wrapper\">\r\n\r\n <div class=\"osl-grid-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-grid-table\">\r\n <thead class=\"osl-grid-thead\">\r\n <tr>\r\n @if (loading && columns.length === 0) {\r\n @for (sk of skeletonColumns; track $index) {\r\n <th class=\"osl-grid-th osl-grid-th--skeleton\">\r\n <div class=\"osl-skeleton osl-skeleton--header\"></div>\r\n </th>\r\n }\r\n } @else {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <th\r\n class=\"osl-grid-th\"\r\n [class.osl-grid-th--last]=\"last\"\r\n [class.osl-grid-th--actions]=\"col.isActions\"\r\n (click)=\"sort(col.key, col.isActions)\"\r\n >\r\n @if (!col.isActions) {\r\n <span class=\"osl-grid-th-inner\">\r\n {{ col.label }}\r\n <span class=\"osl-grid-sort-icon\" [class.osl-grid-sort-icon--active]=\"sortKey === col.key\">\r\n @if (sortKey === col.key) {\r\n {{ sortAsc ? '\u2191' : '\u2193' }}\r\n } @else {\r\n <span class=\"osl-grid-sort-icon--idle\">\u21C5</span>\r\n }\r\n </span>\r\n </span>\r\n }\r\n </th>\r\n }\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-grid-row osl-grid-row--skeleton\">\r\n @if (columns.length > 0) {\r\n @for (col of columns; track col.key; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\" [class.osl-grid-td--actions]=\"col.isActions\">\r\n @if (col.isActions) {\r\n <div class=\"osl-skeleton osl-skeleton--actions\"></div>\r\n } @else {\r\n <div class=\"osl-skeleton\"></div>\r\n }\r\n </td>\r\n }\r\n } @else {\r\n @for (sk2 of skeletonColumns; track $index; let last = $last) {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">\r\n <div class=\"osl-skeleton\"></div>\r\n </td>\r\n }\r\n }\r\n </tr>\r\n }\r\n } @else {\r\n @if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length\" class=\"osl-grid-empty\">\r\n <div class=\"d-flex align-items-center justify-content-center floating-element\">\r\n <div class=\"mx-4\">\r\n <p class=\"f-s-20 f-w-600 text-start\">No Records match the <br> current filters.</p>\r\n <p class=\"text-start\">Expecting to see new Records? Try again in <br> a few seconds as the system catches up</p>\r\n </div>\r\n <i class=\"icon\"></i>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n @for (row of pagedData; track $index; let rowIdx = $index) {\r\n <tr class=\"osl-grid-row\" [class.pointer]=\"isSelectable\" (click)=\"onRowClick.emit(row)\">\r\n @for (col of columns; track col.key; let last = $last) {\r\n @if (col.isActions) {\r\n <td class=\"osl-grid-td osl-grid-td--actions\" [class.osl-grid-td--last]=\"last\">\r\n @if (moreMenuActions.length > 0 && hasVisibleActions(row)) {\r\n <div class=\"osl-menu-wrapper\">\r\n <button class=\"osl-grid-icon-btn\" (click)=\"toggleMenu(rowIdx, $event)\" title=\"More actions\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n @if (openMenuIndex === rowIdx) {\r\n <div class=\"osl-custom-menu\"\r\n [style.top.px]=\"menuPosition.top\"\r\n [style.left.px]=\"menuPosition.left\">\r\n <div class=\"osl-custom-menu-header\">Actions</div>\r\n @for (action of moreMenuActions; track $index) {\r\n @if (!action.hideIf || !action.hideIf(row)) {\r\n <button class=\"osl-custom-menu-item\" (click)=\"action.click(row); closeMenu(); $event.stopPropagation()\">\r\n <span class=\"osl-custom-menu-dot\"></span>\r\n {{ getActionLabel(action, row) }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if(canEdit){\r\n <button class=\"osl-grid-icon-btn\" (click)=\"$event.stopPropagation(); editClick.emit(row)\" title=\"Edit\">\r\n <mat-icon>mode_edit_outline</mat-icon>\r\n </button>\r\n }\r\n @if(canDelete){\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"$event.stopPropagation(); deleteClick.emit(row)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n } @else {\r\n <td class=\"osl-grid-td\" [class.osl-grid-td--last]=\"last\">\r\n @switch (col.displayType) {\r\n @case ('date') { {{ row[col.key] | date }} }\r\n @case ('datetime') { {{ row[col.key] | date:'medium' }} }\r\n @case ('time') { {{ row[col.key] | date:'shortTime' }} }\r\n @default { {{ getCellValue(row, col) }} }\r\n }\r\n </td>\r\n }\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-grid-pagination\">\r\n\r\n <span class=\"osl-grid-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} records\r\n } @else {\r\n No records\r\n }\r\n </span>\r\n\r\n <div class=\"osl-grid-pagination__controls\">\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\" title=\"First page\">\r\n \u00AB\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\" title=\"Previous page\">\r\n \u2039 Prev\r\n </button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-grid-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-grid-page-btn osl-grid-page-btn--num\"\r\n [class.osl-grid-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\"\r\n >\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Next page\">\r\n Next \u203A\r\n </button>\r\n <button class=\"osl-grid-page-btn osl-grid-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\" title=\"Last page\">\r\n \u00BB\r\n </button>\r\n </div>\r\n\r\n <div class=\"osl-grid-pagination__size\">\r\n <select class=\"osl-grid-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-grid-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);overflow:hidden;background:#fff}.osl-grid-table-container{overflow-x:auto;overflow-y:auto;min-height:200px}.osl-grid-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-grid-thead{position:sticky;top:0;z-index:2}.osl-grid-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 14px;text-align:left;border-bottom:2px solid var(--osl-border-color);border-right:1px solid var(--osl-border-color);white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none}.osl-grid-th:hover{background:#e5e7eb}.osl-grid-th--last{border-right:none}.osl-grid-th-inner{display:inline-flex;align-items:center;gap:6px}.osl-grid-sort-icon{font-size:11px;color:#9ca3af}.osl-grid-sort-icon--active{color:var(--osl-primary)}.osl-grid-sort-icon--idle{opacity:.35}.osl-grid-row{border-bottom:1px solid #f3f4f6;transition:background .12s}.osl-grid-row:hover{background:#f9fafb}.osl-grid-row:last-child{border-bottom:none}.osl-grid-td{padding:10px 14px;color:#111827;font-size:var(--osl-text-font-size);vertical-align:middle;white-space:nowrap;border-right:1px solid #f3f4f6}.osl-grid-td--last{border-right:none}.osl-grid-empty{padding:48px 16px;text-align:center;color:#9ca3af;font-size:var(--osl-text-font-size)}.osl-grid-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-grid-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-grid-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-grid-pagination__size{display:flex;align-items:center;min-width:120px;justify-content:flex-end}.osl-grid-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-grid-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-grid-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-grid-page-btn--nav{font-size:12px;color:#6b7280}.osl-grid-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-grid-page-btn--active{background:var(--osl-primary);border-color:var(--osl-primary);color:#fff;font-weight:600}.osl-grid-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover);border-color:var(--osl-primary-hover)}.osl-grid-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-grid-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-grid-page-size:focus{border-color:var(--osl-focus-border-color)}.osl-grid-th--actions{width:80px;min-width:80px;cursor:default;text-align:center}.osl-grid-th--actions:hover{background:#f3f4f6}.osl-grid-td--actions{width:80px;min-width:80px;text-align:center;padding:6px 8px;white-space:nowrap}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}.osl-menu-wrapper{position:relative;display:inline-flex}.osl-custom-menu{position:fixed;z-index:9999;min-width:190px;background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 8px 24px #0000001f,0 2px 8px #00000012;overflow:hidden;animation:osl-menu-appear .15s cubic-bezier(.16,1,.3,1)}@keyframes osl-menu-appear{0%{opacity:0;transform:translateY(-8px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.osl-custom-menu-header{padding:8px 14px 6px;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#9ca3af;border-bottom:1px solid #f3f4f6;-webkit-user-select:none;user-select:none}.osl-custom-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:10px 14px;background:transparent;border:none;border-left:3px solid transparent;border-bottom:1px solid #f9fafb;text-align:left;font-size:13px;font-weight:500;font-family:inherit;color:#374151;cursor:pointer;white-space:nowrap;transition:background .12s,color .12s,border-left-color .12s}.osl-custom-menu-item:last-child{border-bottom:none}.osl-custom-menu-item:hover{background:#f5f3ff;color:var(--osl-primary);border-left-color:var(--osl-primary)}.osl-custom-menu-item:hover .osl-custom-menu-dot{background:var(--osl-primary);box-shadow:0 0 0 3px #6366f12e}.osl-custom-menu-dot{flex-shrink:0;width:6px;height:6px;border-radius:50%;background:#d1d5db;transition:background .12s,box-shadow .12s}@keyframes osl-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-skeleton{height:14px;border-radius:4px;background:#e5e7eb;animation:osl-skeleton-pulse 1.4s ease-in-out infinite;width:80%}.osl-skeleton--actions{width:52px;margin:0 auto}.osl-skeleton--header{height:11px;width:65%;background:#d1d5db;border-radius:3px}.osl-grid-th--skeleton{cursor:default;pointer-events:none}.osl-grid-row--skeleton{pointer-events:none}.icon{background-repeat:no-repeat;background-position:center;display:inline-block!important;vertical-align:middle;width:18%;height:250px;background-image:url('data:image/svg+xml,<svg width=\"147\" height=\"134\" viewBox=\"0 0 147 134\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <g fill=\"none\" fill-rule=\"evenodd\">%0D%0A <path d=\"M2.143 94.537c-2.858-1.65-2.858-4.35 0-6l66.1-38.163c2.858-1.65 7.534-1.65 10.392 0l66.101 38.163c2.858 1.65 2.858 4.35 0 6l-66.1 38.163c-2.859 1.65-7.535 1.65-10.393 0l-66.1-38.162z\" fill=\"%23EAF0F6\" fill-opacity=\".75\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M82.974 42.77c-5.498 1.128-11.537 1.124-17.03-.013L46.688 88.68h.007c1.089-3.023 3.637-5.9 7.679-8.233 11.065-6.39 29.172-6.39 40.237 0 2.902 1.674 5.02 3.632 6.4 5.719L82.975 42.77z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114zM74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748z\" stroke=\"%23CBD6E5\" stroke-width=\"5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0\" fill=\"%23FFF\"/>%0D%0A <path d=\"M92.296 32.687c9.792-5.653 9.792-14.905 0-20.558-9.792-5.653-25.815-5.653-35.607 0-9.792 5.653-9.793 14.905 0 20.558 9.792 5.653 25.815 5.653 35.607 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M87.338 30.07c7.3-4.214 7.3-11.11 0-15.325s-19.244-4.215-26.544 0c-7.3 4.214-7.3 11.111 0 15.325 7.3 4.214 19.244 4.214 26.544 0z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M92.296 32.687c-9.792 5.653-25.815 5.653-35.607 0-4.896-2.827-7.344-6.553-7.344-10.28v6.703c0 3.726 2.448 7.452 7.344 10.279 9.792 5.653 25.815 5.653 35.607 0 4.896-2.827 7.344-6.553 7.344-10.28v-6.701c0 3.726-2.448 7.452-7.344 10.279z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" fill=\"%23FFF\"/>%0D%0A <path d=\"M100.274 42.398l3.987-6.33-7.217-4.818-.011-.008-.004-.002v.001c-.481-.273-1.14-.234-1.867.185-1.46.843-2.654 2.912-2.654 4.598 0 .801.275 1.368.715 1.661l-.003.006.056.038.018.011 6.98 4.658z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M119.293 42.398l-14.095-8.168c-.745-.432-1.772-.374-2.904.28-2.259 1.303-4.107 4.505-4.107 7.113 0 1.32.475 2.241 1.235 2.664l-.002.004 14.179 8.201\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114\" fill=\"%23F2F5F8\"/>%0D%0A <path d=\"M120.635 45.115c0-2.609-1.848-3.676-4.107-2.37-2.26 1.303-4.108 4.504-4.108 7.113 0 2.608 1.848 3.676 4.108 2.371 2.26-1.304 4.107-4.505 4.107-7.114z\" stroke=\"%23CBD6E5\"/>%0D%0A <path d=\"M74.333 12.076c-3.027 1.608-5.823 3.647-8.256 6.062-2.93 2.909-5.318 6.35-7.064 10.092.601.496 1.271.97 2.03 1.408 3.03 1.748 6.86 2.749 10.812 3.023 1.165-3.821 2.893-7.457 5.26-10.67 2.245-3.048 5.088-5.688 8.321-7.65-3.252-1.476-7.168-2.232-11.103-2.265\" fill=\"%23FFF\"/>%0D%0A <path d=\"M87.55 15.472c-3.979 1.873-7.243 5.108-9.606 8.83-1.669 2.63-2.918 5.49-3.927 8.443 1.232.002 2.462-.07 3.674-.208 1.76-3.001 3.973-6.521 5.967-8.772 1.998-2.255 4.375-4.226 7.071-5.545-.784-.996-1.852-1.922-3.179-2.748\" fill=\"%23FFF\"/>%0D%0A <path d=\"M101.012 86.166L82.974 42.77c-5.499 1.127-11.537 1.123-17.031-.014L46.687 88.679h.007\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M94.611 80.446c11.065 6.39 11.065 16.843 0 23.231-11.065 6.39-29.172 6.39-40.238 0-11.065-6.388-11.065-16.842 0-23.23 11.066-6.39 29.173-6.39 40.238 0z\" stroke=\"%23CBD6E5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-dasharray=\"2,3,0,0\"/>%0D%0A <path d=\"M121.68 10.236l-11.902 4.361M115.666 23.734l-5.239-2.47M119 25.306l-.753-.356M106.763 7.402l-.803 1.704M109.781 1l-1.81 3.84\" stroke=\"%23CBD6E5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>%0D%0A </g>%0D%0A</svg>%0D%0A');background-size:100%;animation:moveUpDown 3s ease-in-out infinite}@keyframes moveUpDown{0%,to{transform:translateY(0)}50%{transform:translateY(-15px)}}.pointer{cursor:pointer}\n"] }]
2374
2377
  }], propDecorators: { columns: [{
2375
2378
  type: Input,
2376
2379
  args: ['columns']
@@ -2775,8 +2778,8 @@ class OslFormGrid {
2775
2778
  this.pageSize = Number(size);
2776
2779
  this.currentPage = 1;
2777
2780
  }
2778
- isDisabled(elem) {
2779
- return elem.disabledIf ? elem.disabledIf() : !!elem.disabled;
2781
+ isDisabled(elem, row, index) {
2782
+ return elem.disabledIf ? elem.disabledIf(row, index) : !!elem.disabled;
2780
2783
  }
2781
2784
  isLoading(row, elem) {
2782
2785
  return elem.loadingIf ? elem.loadingIf(row) : false;
@@ -2803,11 +2806,11 @@ class OslFormGrid {
2803
2806
  elem.change(row, i, selectedObj);
2804
2807
  }
2805
2808
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslFormGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
2806
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslFormGrid, isStandalone: false, selector: "osl-form-grid", inputs: { columns: "columns", datasource: "datasource", isPaginated: "isPaginated", pageSize: "pageSize", canAdd: "canAdd", canDelete: "canDelete", loading: "loading", tableHeight: "tableHeight", footerColumns: "footerColumns" }, outputs: { datasourceChange: "datasourceChange", rowAdd: "rowAdd", rowDelete: "rowDelete" }, ngImport: i0, template: "<div class=\"osl-fg-wrapper\">\r\n\r\n <div class=\"osl-fg-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-fg-table\">\r\n\r\n <thead class=\"osl-fg-thead\">\r\n <tr>\r\n <!-- Actions column: + add button in header -->\r\n @if (hasActions) {\r\n <th class=\"osl-fg-th osl-fg-th--actions\">\r\n @if (canAdd) {\r\n <button class=\"osl-grid-icon-btn\" (click)=\"addRow()\" [disabled]=\"loading\" title=\"Add row\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n </th>\r\n }\r\n @for (col of columns; track col.key) {\r\n <th class=\"osl-fg-th\" [style.width]=\"col.width\">\r\n {{ col.displayName }}\r\n @if (colRequired(col)) {\r\n <span class=\"osl-fg-th-required\">*</span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-fg-row osl-fg-row--skeleton\">\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n <div class=\"osl-fg-skeleton osl-fg-skeleton--sm\"></div>\r\n </td>\r\n }\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\"><div class=\"osl-fg-skeleton\"></div></td>\r\n }\r\n </tr>\r\n }\r\n\r\n } @else if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length + (hasActions ? 1 : 0)\" class=\"osl-fg-empty\">\r\n <div class=\"osl-fg-empty-inner\">\r\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\r\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/>\r\n <line x1=\"9\" y1=\"9\" x2=\"9\" y2=\"21\"/>\r\n </svg>\r\n <p>No rows yet.{{ canAdd ? ' Use + to get started.' : '' }}</p>\r\n </div>\r\n </td>\r\n </tr>\r\n\r\n } @else {\r\n @for (row of pagedData; track $index; let i = $index) {\r\n <tr class=\"osl-fg-row\">\r\n\r\n <!-- Delete button first -->\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n @if (canDelete) {\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"deleteRow(i)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\" [style.width]=\"col.width\">\r\n @if (col.formElem) {\r\n <div class=\"osl-fg-cell-form\">\r\n @switch (col.formElem.elementType) {\r\n\r\n @case ('textbox') {\r\n <osl-input\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [type]=\"col.formElem.inputType || 'text'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [mask]=\"col.formElem.mask || ''\"\r\n [min]=\"col.formElem.min ?? ''\"\r\n [max]=\"col.formElem.max ?? ''\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [prefixIcon]=\"col.formElem.prefixIcon || ''\"\r\n [suffixIcon]=\"col.formElem.suffixIcon || ''\"\r\n [decimalPortion]=\"col.formElem.decimalPortion ?? null\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-input>\r\n }\r\n\r\n @case ('textarea') {\r\n <osl-textarea\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [rows]=\"col.formElem.textareaRows || 3\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [characterCounter]=\"!!col.formElem.characterCounter\"\r\n [resize]=\"col.formElem.resize || 'none'\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-textarea>\r\n }\r\n\r\n @case ('select') {\r\n <osl-select\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.selectPlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [clearable]=\"!!col.formElem.clearable\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <osl-autocomplete\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.autocompletePlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [searchType]=\"col.formElem.searchType ? col.formElem.searchType : 'Local'\"\r\n [methodName]=\"col.formElem.apiMethod || ''\"\r\n [configMethodName]=\"col.formElem.apiConfigMethod || ''\"\r\n [service]=\"col.formElem.apiService\"\r\n [object]=\"col.formElem.objectName ? row[col.formElem.objectName] : null\"\r\n [isLister]=\"!!col.formElem.isListerAutocomplete\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-autocomplete>\r\n }\r\n\r\n @case ('radio') {\r\n <osl-radio\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [inline]=\"!!col.formElem.inline\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-radio>\r\n }\r\n\r\n @case ('checkbox') {\r\n <osl-checkbox\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [indeterminate]=\"!!col.formElem.indeterminate\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-checkbox>\r\n }\r\n\r\n @case ('slide-toggle') {\r\n <osl-slide-toggle\r\n [label]=\"''\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [labelPosition]=\"col.formElem.labelPosition || 'after'\"\r\n [trueLabel]=\"col.formElem.trueLabel || ''\"\r\n [falseLabel]=\"col.formElem.falseLabel || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-slide-toggle>\r\n }\r\n\r\n @case ('datepicker') {\r\n <osl-datepicker\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [dateType]=\"col.formElem.dateType || 'date'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [minDate]=\"col.formElem.minDate || ''\"\r\n [maxDate]=\"col.formElem.maxDate || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-datepicker>\r\n }\r\n\r\n @case ('file-uploader') {\r\n <osl-file-upload\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [accept]=\"col.formElem.accept || ''\"\r\n [multiple]=\"!!col.formElem.multiple\"\r\n [maxSize]=\"col.formElem.maxFileSize || 0\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-file-upload>\r\n }\r\n\r\n }\r\n </div>\r\n } @else {\r\n <span class=\"osl-fg-cell-text\">{{ row[col.key] ?? '--' }}</span>\r\n }\r\n </td>\r\n }\r\n\r\n </tr>\r\n }\r\n }\r\n\r\n </tbody>\r\n\r\n @if (footerColumns && footerColumns.length > 0 && datasource && datasource.length > 0) {\r\n <tfoot class=\"osl-fg-tfoot\">\r\n <tr class=\"osl-fg-footer-row\">\r\n @for (fcol of footerColumns; track $index) {\r\n <td\r\n [class]=\"'osl-fg-footer-td ' + (fcol.class || '')\"\r\n [attr.colspan]=\"fcol.colspan || 1\">\r\n {{ fcol.displayFn ? fcol.displayFn(datasource) : (fcol.display || '') }}\r\n </td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-fg-pagination\">\r\n\r\n <span class=\"osl-fg-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} rows\r\n } @else {\r\n No rows\r\n }\r\n </span>\r\n\r\n <div class=\"osl-fg-pagination__controls\">\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\">\u00AB</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\">\u2039 Prev</button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-fg-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-fg-page-btn osl-fg-page-btn--num\"\r\n [class.osl-fg-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\">\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\">Next \u203A</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\">\u00BB</button>\r\n </div>\r\n\r\n <div class=\"osl-fg-pagination__size\">\r\n <select class=\"osl-fg-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-fg-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 8px);overflow:hidden;background:#fff}.osl-fg-table-container{overflow-x:auto;overflow-y:auto;min-height:120px}.osl-fg-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-fg-thead{position:sticky;top:0;z-index:2}.osl-fg-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-bottom:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-th:last-child{border-right:none}.osl-fg-th--actions{width:44px;min-width:44px;text-align:center;padding:6px}.osl-fg-th-required{color:#ef4444;margin-left:2px;font-size:14px;line-height:1;vertical-align:middle}.osl-fg-row{border-bottom:1px solid #f0f0f0;transition:background .1s}.osl-fg-row:nth-child(odd){background:#f8fafc}.osl-fg-row:nth-child(2n){background:#fff}.osl-fg-row:hover{background:#eef2ff!important}.osl-fg-row:last-child{border-bottom:none}.osl-fg-row--skeleton{pointer-events:none}.osl-fg-td{padding:4px 10px;vertical-align:middle;border-right:1px solid #f0f0f0}.osl-fg-td:last-child{border-right:none}.osl-fg-td--actions{width:44px;min-width:44px;text-align:center;padding:4px 6px}.osl-fg-cell-form{min-width:100px}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field,.osl-fg-cell-form ::ng-deep mat-form-field{width:100%}.osl-fg-cell-form ::ng-deep .mat-mdc-text-field-wrapper{padding-top:0}.osl-fg-cell-text{color:#111827;font-size:var(--osl-text-font-size)}.osl-fg-add-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;border-radius:6px;background:var(--osl-primary, #6366f1);color:#fff;cursor:pointer;padding:0;box-shadow:0 1px 4px #6366f159;transition:background .15s,box-shadow .15s,transform .1s}.osl-fg-add-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.osl-fg-add-btn:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);box-shadow:0 2px 8px #6366f173;transform:scale(1.05)}.osl-fg-add-btn:disabled{opacity:.4;cursor:not-allowed;transform:none}.osl-fg-delete-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid transparent;border-radius:6px;background:transparent;color:#d1d5db;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s}.osl-fg-delete-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-fg-delete-btn:hover{border-color:#fca5a5;color:#ef4444;background:#fef2f2}.osl-fg-empty{padding:40px 16px;text-align:center}.osl-fg-empty-inner{display:flex;flex-direction:column;align-items:center;gap:10px;color:#9ca3af}.osl-fg-empty-inner svg{opacity:.4}.osl-fg-empty-inner p{margin:0;font-size:13px}@keyframes osl-fg-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-fg-skeleton{height:36px;border-radius:6px;background:#e5e7eb;animation:osl-fg-pulse 1.4s ease-in-out infinite}.osl-fg-skeleton--sm{height:28px;width:28px;border-radius:4px;margin:0 auto}.osl-fg-tfoot{position:sticky;bottom:0;z-index:2}.osl-fg-footer-td{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-top:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-footer-td:last-child{border-right:none}.osl-fg-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color, #e5e7eb);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-fg-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-fg-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-fg-pagination__size{display:flex;align-items:center;justify-content:flex-end;min-width:120px}.osl-fg-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-fg-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-fg-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-fg-page-btn--nav{font-size:12px;color:#6b7280}.osl-fg-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-fg-page-btn--active{background:var(--osl-primary, #6366f1);border-color:var(--osl-primary, #6366f1);color:#fff;font-weight:600}.osl-fg-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);border-color:var(--osl-primary-hover, #4f46e5)}.osl-fg-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-fg-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-fg-page-size:focus{border-color:var(--osl-primary, #6366f1)}.osl-fg-page-size:disabled{opacity:.4;cursor:not-allowed}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"], dependencies: [{ kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: Oslinput, selector: "osl-input", inputs: ["label", "required", "disabled", "model", "type", "placeholder", "mask", "min", "max", "minLength", "maxLength", "prefixIcon", "suffixIcon", "skeletonLoading", "skeletonTheme", "onlyChars", "decimalPortion"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: Osltextarea, selector: "osl-textarea", inputs: ["label", "rows", "required", "disabled", "model", "placeholder", "maxLength", "minLength", "characterCounter", "resize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSelect, selector: "osl-select", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "clearable", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslRadio, selector: "osl-radio", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "inline", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSlideToggle, selector: "osl-slide-toggle", inputs: ["label", "disabled", "model", "labelPosition", "trueLabel", "falseLabel", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslAutocomplete, selector: "osl-autocomplete", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "searchType", "methodName", "configMethodName", "service", "object", "skeletonLoading", "skeletonTheme", "isLister"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslFileUpload, selector: "osl-file-upload", inputs: ["label", "required", "disabled", "model", "accept", "multiple", "maxSize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslDatepicker, selector: "osl-datepicker", inputs: ["label", "required", "disabled", "model", "dateType", "placeholder", "minDate", "maxDate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslCheckbox, selector: "osl-checkbox", inputs: ["label", "disabled", "required", "model", "indeterminate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }] });
2809
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslFormGrid, isStandalone: false, selector: "osl-form-grid", inputs: { columns: "columns", datasource: "datasource", isPaginated: "isPaginated", pageSize: "pageSize", canAdd: "canAdd", canDelete: "canDelete", loading: "loading", tableHeight: "tableHeight", footerColumns: "footerColumns" }, outputs: { datasourceChange: "datasourceChange", rowAdd: "rowAdd", rowDelete: "rowDelete" }, ngImport: i0, template: "<div class=\"osl-fg-wrapper\">\r\n\r\n <div class=\"osl-fg-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-fg-table\">\r\n\r\n <thead class=\"osl-fg-thead\">\r\n <tr>\r\n <!-- Actions column: + add button in header -->\r\n @if (hasActions) {\r\n <th class=\"osl-fg-th osl-fg-th--actions\">\r\n @if (canAdd) {\r\n <button class=\"osl-grid-icon-btn\" (click)=\"addRow()\" [disabled]=\"loading\" title=\"Add row\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n </th>\r\n }\r\n @for (col of columns; track col.key) {\r\n <th class=\"osl-fg-th\" [style.width]=\"col.width\">\r\n {{ col.displayName }}\r\n @if (colRequired(col)) {\r\n <span class=\"osl-fg-th-required\">*</span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-fg-row osl-fg-row--skeleton\">\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n <div class=\"osl-fg-skeleton osl-fg-skeleton--sm\"></div>\r\n </td>\r\n }\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\"><div class=\"osl-fg-skeleton\"></div></td>\r\n }\r\n </tr>\r\n }\r\n\r\n } @else if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length + (hasActions ? 1 : 0)\" class=\"osl-fg-empty\">\r\n <div class=\"osl-fg-empty-inner\">\r\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\r\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/>\r\n <line x1=\"9\" y1=\"9\" x2=\"9\" y2=\"21\"/>\r\n </svg>\r\n <p>No rows yet.{{ canAdd ? ' Use + to get started.' : '' }}</p>\r\n </div>\r\n </td>\r\n </tr>\r\n\r\n } @else {\r\n @for (row of pagedData; track $index; let i = $index) {\r\n <tr class=\"osl-fg-row\">\r\n\r\n <!-- Delete button first -->\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n @if (canDelete) {\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"deleteRow(i)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\" [style.width]=\"col.width\">\r\n @if (col.formElem) {\r\n <div class=\"osl-fg-cell-form\">\r\n @switch (col.formElem.elementType) {\r\n\r\n @case ('textbox') {\r\n <osl-input\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [type]=\"col.formElem.inputType || 'text'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [mask]=\"col.formElem.mask || ''\"\r\n [min]=\"col.formElem.min ?? ''\"\r\n [max]=\"col.formElem.max ?? ''\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [prefixIcon]=\"col.formElem.prefixIcon || ''\"\r\n [suffixIcon]=\"col.formElem.suffixIcon || ''\"\r\n [decimalPortion]=\"col.formElem.decimalPortion ?? null\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-input>\r\n }\r\n\r\n @case ('textarea') {\r\n <osl-textarea\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [rows]=\"col.formElem.textareaRows || 3\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [characterCounter]=\"!!col.formElem.characterCounter\"\r\n [resize]=\"col.formElem.resize || 'none'\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-textarea>\r\n }\r\n\r\n @case ('select') {\r\n <osl-select\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.selectPlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [clearable]=\"!!col.formElem.clearable\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <osl-autocomplete\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.autocompletePlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [searchType]=\"col.formElem.searchType ? col.formElem.searchType : 'Local'\"\r\n [methodName]=\"col.formElem.apiMethod || ''\"\r\n [configMethodName]=\"col.formElem.apiConfigMethod || ''\"\r\n [service]=\"col.formElem.apiService\"\r\n [object]=\"col.formElem.objectName ? row[col.formElem.objectName] : null\"\r\n [isLister]=\"!!col.formElem.isListerAutocomplete\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-autocomplete>\r\n }\r\n\r\n @case ('radio') {\r\n <osl-radio\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [inline]=\"!!col.formElem.inline\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-radio>\r\n }\r\n\r\n @case ('checkbox') {\r\n <osl-checkbox\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [indeterminate]=\"!!col.formElem.indeterminate\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-checkbox>\r\n }\r\n\r\n @case ('slide-toggle') {\r\n <osl-slide-toggle\r\n [label]=\"''\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [labelPosition]=\"col.formElem.labelPosition || 'after'\"\r\n [trueLabel]=\"col.formElem.trueLabel || ''\"\r\n [falseLabel]=\"col.formElem.falseLabel || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-slide-toggle>\r\n }\r\n\r\n @case ('datepicker') {\r\n <osl-datepicker\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [dateType]=\"col.formElem.dateType || 'date'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [minDate]=\"col.formElem.minDate || ''\"\r\n [maxDate]=\"col.formElem.maxDate || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-datepicker>\r\n }\r\n\r\n @case ('file-uploader') {\r\n <osl-file-upload\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [accept]=\"col.formElem.accept || ''\"\r\n [multiple]=\"!!col.formElem.multiple\"\r\n [maxSize]=\"col.formElem.maxFileSize || 0\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-file-upload>\r\n }\r\n\r\n }\r\n </div>\r\n } @else {\r\n <span class=\"osl-fg-cell-text\">{{ row[col.key] ?? '--' }}</span>\r\n }\r\n </td>\r\n }\r\n\r\n </tr>\r\n }\r\n }\r\n\r\n </tbody>\r\n\r\n @if (footerColumns && footerColumns.length > 0 && datasource && datasource.length > 0) {\r\n <tfoot class=\"osl-fg-tfoot\">\r\n <tr class=\"osl-fg-footer-row\">\r\n @for (fcol of footerColumns; track $index) {\r\n <td\r\n [class]=\"'osl-fg-footer-td ' + (fcol.class || '')\"\r\n [attr.colspan]=\"fcol.colspan || 1\">\r\n {{ fcol.displayFn ? fcol.displayFn(datasource) : (fcol.display || '') }}\r\n </td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-fg-pagination\">\r\n\r\n <span class=\"osl-fg-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} rows\r\n } @else {\r\n No rows\r\n }\r\n </span>\r\n\r\n <div class=\"osl-fg-pagination__controls\">\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\">\u00AB</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\">\u2039 Prev</button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-fg-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-fg-page-btn osl-fg-page-btn--num\"\r\n [class.osl-fg-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\">\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\">Next \u203A</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\">\u00BB</button>\r\n </div>\r\n\r\n <div class=\"osl-fg-pagination__size\">\r\n <select class=\"osl-fg-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-fg-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 8px);overflow:hidden;background:#fff}.osl-fg-table-container{overflow-x:auto;overflow-y:auto;min-height:120px}.osl-fg-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-fg-thead{position:sticky;top:0;z-index:2}.osl-fg-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-bottom:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-th:last-child{border-right:none}.osl-fg-th--actions{width:44px;min-width:44px;text-align:center;padding:6px}.osl-fg-th-required{color:#ef4444;margin-left:2px;font-size:14px;line-height:1;vertical-align:middle}.osl-fg-row{border-bottom:1px solid #f0f0f0;transition:background .1s}.osl-fg-row:nth-child(odd){background:#f8fafc}.osl-fg-row:nth-child(2n){background:#fff}.osl-fg-row:hover{background:#eef2ff!important}.osl-fg-row:last-child{border-bottom:none}.osl-fg-row--skeleton{pointer-events:none}.osl-fg-td{padding:4px 10px;vertical-align:middle;border-right:1px solid #f0f0f0}.osl-fg-td:last-child{border-right:none}.osl-fg-td--actions{width:44px;min-width:44px;text-align:center;padding:4px 6px}.osl-fg-cell-form{min-width:100px}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field,.osl-fg-cell-form ::ng-deep mat-form-field{width:100%}.osl-fg-cell-form ::ng-deep .mat-mdc-text-field-wrapper{padding-top:0}.osl-fg-cell-text{color:#111827;font-size:var(--osl-text-font-size)}.osl-fg-add-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;border-radius:6px;background:var(--osl-primary, #6366f1);color:#fff;cursor:pointer;padding:0;box-shadow:0 1px 4px #6366f159;transition:background .15s,box-shadow .15s,transform .1s}.osl-fg-add-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.osl-fg-add-btn:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);box-shadow:0 2px 8px #6366f173;transform:scale(1.05)}.osl-fg-add-btn:disabled{opacity:.4;cursor:not-allowed;transform:none}.osl-fg-delete-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid transparent;border-radius:6px;background:transparent;color:#d1d5db;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s}.osl-fg-delete-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-fg-delete-btn:hover{border-color:#fca5a5;color:#ef4444;background:#fef2f2}.osl-fg-empty{padding:40px 16px;text-align:center}.osl-fg-empty-inner{display:flex;flex-direction:column;align-items:center;gap:10px;color:#9ca3af}.osl-fg-empty-inner svg{opacity:.4}.osl-fg-empty-inner p{margin:0;font-size:13px}@keyframes osl-fg-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-fg-skeleton{height:36px;border-radius:6px;background:#e5e7eb;animation:osl-fg-pulse 1.4s ease-in-out infinite}.osl-fg-skeleton--sm{height:28px;width:28px;border-radius:4px;margin:0 auto}.osl-fg-tfoot{position:sticky;bottom:0;z-index:2}.osl-fg-footer-td{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-top:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-footer-td:last-child{border-right:none}.osl-fg-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color, #e5e7eb);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-fg-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-fg-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-fg-pagination__size{display:flex;align-items:center;justify-content:flex-end;min-width:120px}.osl-fg-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-fg-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-fg-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-fg-page-btn--nav{font-size:12px;color:#6b7280}.osl-fg-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-fg-page-btn--active{background:var(--osl-primary, #6366f1);border-color:var(--osl-primary, #6366f1);color:#fff;font-weight:600}.osl-fg-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);border-color:var(--osl-primary-hover, #4f46e5)}.osl-fg-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-fg-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-fg-page-size:focus{border-color:var(--osl-primary, #6366f1)}.osl-fg-page-size:disabled{opacity:.4;cursor:not-allowed}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"], dependencies: [{ kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: Oslinput, selector: "osl-input", inputs: ["label", "required", "disabled", "model", "type", "placeholder", "mask", "min", "max", "minLength", "maxLength", "prefixIcon", "suffixIcon", "skeletonLoading", "skeletonTheme", "onlyChars", "decimalPortion"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: Osltextarea, selector: "osl-textarea", inputs: ["label", "rows", "required", "disabled", "model", "placeholder", "maxLength", "minLength", "characterCounter", "resize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSelect, selector: "osl-select", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "clearable", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslRadio, selector: "osl-radio", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "inline", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslSlideToggle, selector: "osl-slide-toggle", inputs: ["label", "disabled", "model", "labelPosition", "trueLabel", "falseLabel", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslAutocomplete, selector: "osl-autocomplete", inputs: ["label", "required", "disabled", "model", "datasource", "displayField", "valueField", "placeholder", "loading", "searchType", "methodName", "configMethodName", "service", "object", "skeletonLoading", "skeletonTheme", "isLister"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslFileUpload, selector: "osl-file-upload", inputs: ["label", "required", "disabled", "model", "accept", "multiple", "maxSize", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslDatepicker, selector: "osl-datepicker", inputs: ["label", "required", "disabled", "model", "dateType", "placeholder", "minDate", "maxDate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslCheckbox, selector: "osl-checkbox", inputs: ["label", "disabled", "required", "model", "indeterminate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }] });
2807
2810
  }
2808
2811
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslFormGrid, decorators: [{
2809
2812
  type: Component,
2810
- args: [{ selector: 'osl-form-grid', standalone: false, template: "<div class=\"osl-fg-wrapper\">\r\n\r\n <div class=\"osl-fg-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-fg-table\">\r\n\r\n <thead class=\"osl-fg-thead\">\r\n <tr>\r\n <!-- Actions column: + add button in header -->\r\n @if (hasActions) {\r\n <th class=\"osl-fg-th osl-fg-th--actions\">\r\n @if (canAdd) {\r\n <button class=\"osl-grid-icon-btn\" (click)=\"addRow()\" [disabled]=\"loading\" title=\"Add row\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n </th>\r\n }\r\n @for (col of columns; track col.key) {\r\n <th class=\"osl-fg-th\" [style.width]=\"col.width\">\r\n {{ col.displayName }}\r\n @if (colRequired(col)) {\r\n <span class=\"osl-fg-th-required\">*</span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-fg-row osl-fg-row--skeleton\">\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n <div class=\"osl-fg-skeleton osl-fg-skeleton--sm\"></div>\r\n </td>\r\n }\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\"><div class=\"osl-fg-skeleton\"></div></td>\r\n }\r\n </tr>\r\n }\r\n\r\n } @else if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length + (hasActions ? 1 : 0)\" class=\"osl-fg-empty\">\r\n <div class=\"osl-fg-empty-inner\">\r\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\r\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/>\r\n <line x1=\"9\" y1=\"9\" x2=\"9\" y2=\"21\"/>\r\n </svg>\r\n <p>No rows yet.{{ canAdd ? ' Use + to get started.' : '' }}</p>\r\n </div>\r\n </td>\r\n </tr>\r\n\r\n } @else {\r\n @for (row of pagedData; track $index; let i = $index) {\r\n <tr class=\"osl-fg-row\">\r\n\r\n <!-- Delete button first -->\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n @if (canDelete) {\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"deleteRow(i)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\" [style.width]=\"col.width\">\r\n @if (col.formElem) {\r\n <div class=\"osl-fg-cell-form\">\r\n @switch (col.formElem.elementType) {\r\n\r\n @case ('textbox') {\r\n <osl-input\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [type]=\"col.formElem.inputType || 'text'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [mask]=\"col.formElem.mask || ''\"\r\n [min]=\"col.formElem.min ?? ''\"\r\n [max]=\"col.formElem.max ?? ''\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [prefixIcon]=\"col.formElem.prefixIcon || ''\"\r\n [suffixIcon]=\"col.formElem.suffixIcon || ''\"\r\n [decimalPortion]=\"col.formElem.decimalPortion ?? null\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-input>\r\n }\r\n\r\n @case ('textarea') {\r\n <osl-textarea\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [rows]=\"col.formElem.textareaRows || 3\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [characterCounter]=\"!!col.formElem.characterCounter\"\r\n [resize]=\"col.formElem.resize || 'none'\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-textarea>\r\n }\r\n\r\n @case ('select') {\r\n <osl-select\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.selectPlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [clearable]=\"!!col.formElem.clearable\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <osl-autocomplete\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.autocompletePlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [searchType]=\"col.formElem.searchType ? col.formElem.searchType : 'Local'\"\r\n [methodName]=\"col.formElem.apiMethod || ''\"\r\n [configMethodName]=\"col.formElem.apiConfigMethod || ''\"\r\n [service]=\"col.formElem.apiService\"\r\n [object]=\"col.formElem.objectName ? row[col.formElem.objectName] : null\"\r\n [isLister]=\"!!col.formElem.isListerAutocomplete\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-autocomplete>\r\n }\r\n\r\n @case ('radio') {\r\n <osl-radio\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [inline]=\"!!col.formElem.inline\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-radio>\r\n }\r\n\r\n @case ('checkbox') {\r\n <osl-checkbox\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [indeterminate]=\"!!col.formElem.indeterminate\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-checkbox>\r\n }\r\n\r\n @case ('slide-toggle') {\r\n <osl-slide-toggle\r\n [label]=\"''\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [labelPosition]=\"col.formElem.labelPosition || 'after'\"\r\n [trueLabel]=\"col.formElem.trueLabel || ''\"\r\n [falseLabel]=\"col.formElem.falseLabel || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-slide-toggle>\r\n }\r\n\r\n @case ('datepicker') {\r\n <osl-datepicker\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [dateType]=\"col.formElem.dateType || 'date'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [minDate]=\"col.formElem.minDate || ''\"\r\n [maxDate]=\"col.formElem.maxDate || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-datepicker>\r\n }\r\n\r\n @case ('file-uploader') {\r\n <osl-file-upload\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem)\"\r\n [accept]=\"col.formElem.accept || ''\"\r\n [multiple]=\"!!col.formElem.multiple\"\r\n [maxSize]=\"col.formElem.maxFileSize || 0\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-file-upload>\r\n }\r\n\r\n }\r\n </div>\r\n } @else {\r\n <span class=\"osl-fg-cell-text\">{{ row[col.key] ?? '--' }}</span>\r\n }\r\n </td>\r\n }\r\n\r\n </tr>\r\n }\r\n }\r\n\r\n </tbody>\r\n\r\n @if (footerColumns && footerColumns.length > 0 && datasource && datasource.length > 0) {\r\n <tfoot class=\"osl-fg-tfoot\">\r\n <tr class=\"osl-fg-footer-row\">\r\n @for (fcol of footerColumns; track $index) {\r\n <td\r\n [class]=\"'osl-fg-footer-td ' + (fcol.class || '')\"\r\n [attr.colspan]=\"fcol.colspan || 1\">\r\n {{ fcol.displayFn ? fcol.displayFn(datasource) : (fcol.display || '') }}\r\n </td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-fg-pagination\">\r\n\r\n <span class=\"osl-fg-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} rows\r\n } @else {\r\n No rows\r\n }\r\n </span>\r\n\r\n <div class=\"osl-fg-pagination__controls\">\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\">\u00AB</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\">\u2039 Prev</button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-fg-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-fg-page-btn osl-fg-page-btn--num\"\r\n [class.osl-fg-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\">\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\">Next \u203A</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\">\u00BB</button>\r\n </div>\r\n\r\n <div class=\"osl-fg-pagination__size\">\r\n <select class=\"osl-fg-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-fg-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 8px);overflow:hidden;background:#fff}.osl-fg-table-container{overflow-x:auto;overflow-y:auto;min-height:120px}.osl-fg-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-fg-thead{position:sticky;top:0;z-index:2}.osl-fg-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-bottom:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-th:last-child{border-right:none}.osl-fg-th--actions{width:44px;min-width:44px;text-align:center;padding:6px}.osl-fg-th-required{color:#ef4444;margin-left:2px;font-size:14px;line-height:1;vertical-align:middle}.osl-fg-row{border-bottom:1px solid #f0f0f0;transition:background .1s}.osl-fg-row:nth-child(odd){background:#f8fafc}.osl-fg-row:nth-child(2n){background:#fff}.osl-fg-row:hover{background:#eef2ff!important}.osl-fg-row:last-child{border-bottom:none}.osl-fg-row--skeleton{pointer-events:none}.osl-fg-td{padding:4px 10px;vertical-align:middle;border-right:1px solid #f0f0f0}.osl-fg-td:last-child{border-right:none}.osl-fg-td--actions{width:44px;min-width:44px;text-align:center;padding:4px 6px}.osl-fg-cell-form{min-width:100px}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field,.osl-fg-cell-form ::ng-deep mat-form-field{width:100%}.osl-fg-cell-form ::ng-deep .mat-mdc-text-field-wrapper{padding-top:0}.osl-fg-cell-text{color:#111827;font-size:var(--osl-text-font-size)}.osl-fg-add-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;border-radius:6px;background:var(--osl-primary, #6366f1);color:#fff;cursor:pointer;padding:0;box-shadow:0 1px 4px #6366f159;transition:background .15s,box-shadow .15s,transform .1s}.osl-fg-add-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.osl-fg-add-btn:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);box-shadow:0 2px 8px #6366f173;transform:scale(1.05)}.osl-fg-add-btn:disabled{opacity:.4;cursor:not-allowed;transform:none}.osl-fg-delete-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid transparent;border-radius:6px;background:transparent;color:#d1d5db;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s}.osl-fg-delete-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-fg-delete-btn:hover{border-color:#fca5a5;color:#ef4444;background:#fef2f2}.osl-fg-empty{padding:40px 16px;text-align:center}.osl-fg-empty-inner{display:flex;flex-direction:column;align-items:center;gap:10px;color:#9ca3af}.osl-fg-empty-inner svg{opacity:.4}.osl-fg-empty-inner p{margin:0;font-size:13px}@keyframes osl-fg-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-fg-skeleton{height:36px;border-radius:6px;background:#e5e7eb;animation:osl-fg-pulse 1.4s ease-in-out infinite}.osl-fg-skeleton--sm{height:28px;width:28px;border-radius:4px;margin:0 auto}.osl-fg-tfoot{position:sticky;bottom:0;z-index:2}.osl-fg-footer-td{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-top:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-footer-td:last-child{border-right:none}.osl-fg-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color, #e5e7eb);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-fg-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-fg-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-fg-pagination__size{display:flex;align-items:center;justify-content:flex-end;min-width:120px}.osl-fg-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-fg-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-fg-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-fg-page-btn--nav{font-size:12px;color:#6b7280}.osl-fg-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-fg-page-btn--active{background:var(--osl-primary, #6366f1);border-color:var(--osl-primary, #6366f1);color:#fff;font-weight:600}.osl-fg-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);border-color:var(--osl-primary-hover, #4f46e5)}.osl-fg-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-fg-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-fg-page-size:focus{border-color:var(--osl-primary, #6366f1)}.osl-fg-page-size:disabled{opacity:.4;cursor:not-allowed}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"] }]
2813
+ args: [{ selector: 'osl-form-grid', standalone: false, template: "<div class=\"osl-fg-wrapper\">\r\n\r\n <div class=\"osl-fg-table-container\" [style.height]=\"tableHeight\">\r\n <table class=\"osl-fg-table\">\r\n\r\n <thead class=\"osl-fg-thead\">\r\n <tr>\r\n <!-- Actions column: + add button in header -->\r\n @if (hasActions) {\r\n <th class=\"osl-fg-th osl-fg-th--actions\">\r\n @if (canAdd) {\r\n <button class=\"osl-grid-icon-btn\" (click)=\"addRow()\" [disabled]=\"loading\" title=\"Add row\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n </th>\r\n }\r\n @for (col of columns; track col.key) {\r\n <th class=\"osl-fg-th\" [style.width]=\"col.width\">\r\n {{ col.displayName }}\r\n @if (colRequired(col)) {\r\n <span class=\"osl-fg-th-required\">*</span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n\r\n @if (loading) {\r\n @for (sk of skeletonRows; track $index) {\r\n <tr class=\"osl-fg-row osl-fg-row--skeleton\">\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n <div class=\"osl-fg-skeleton osl-fg-skeleton--sm\"></div>\r\n </td>\r\n }\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\"><div class=\"osl-fg-skeleton\"></div></td>\r\n }\r\n </tr>\r\n }\r\n\r\n } @else if (pagedData.length === 0) {\r\n <tr>\r\n <td [attr.colspan]=\"columns.length + (hasActions ? 1 : 0)\" class=\"osl-fg-empty\">\r\n <div class=\"osl-fg-empty-inner\">\r\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\r\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/>\r\n <line x1=\"9\" y1=\"9\" x2=\"9\" y2=\"21\"/>\r\n </svg>\r\n <p>No rows yet.{{ canAdd ? ' Use + to get started.' : '' }}</p>\r\n </div>\r\n </td>\r\n </tr>\r\n\r\n } @else {\r\n @for (row of pagedData; track $index; let i = $index) {\r\n <tr class=\"osl-fg-row\">\r\n\r\n <!-- Delete button first -->\r\n @if (hasActions) {\r\n <td class=\"osl-fg-td osl-fg-td--actions\">\r\n @if (canDelete) {\r\n <button class=\"osl-grid-icon-btn osl-grid-icon-btn--danger\" (click)=\"deleteRow(i)\" title=\"Delete\">\r\n <mat-icon>delete_outline</mat-icon>\r\n </button>\r\n }\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key) {\r\n <td class=\"osl-fg-td\" [style.width]=\"col.width\">\r\n @if (col.formElem) {\r\n <div class=\"osl-fg-cell-form\">\r\n @switch (col.formElem.elementType) {\r\n\r\n @case ('textbox') {\r\n <osl-input\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [type]=\"col.formElem.inputType || 'text'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [mask]=\"col.formElem.mask || ''\"\r\n [min]=\"col.formElem.min ?? ''\"\r\n [max]=\"col.formElem.max ?? ''\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [prefixIcon]=\"col.formElem.prefixIcon || ''\"\r\n [suffixIcon]=\"col.formElem.suffixIcon || ''\"\r\n [decimalPortion]=\"col.formElem.decimalPortion ?? null\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-input>\r\n }\r\n\r\n @case ('textarea') {\r\n <osl-textarea\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [rows]=\"col.formElem.textareaRows || 3\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [maxLength]=\"col.formElem.maxLength ?? null\"\r\n [minLength]=\"col.formElem.minLength ?? null\"\r\n [characterCounter]=\"!!col.formElem.characterCounter\"\r\n [resize]=\"col.formElem.resize || 'none'\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-textarea>\r\n }\r\n\r\n @case ('select') {\r\n <osl-select\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.selectPlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [clearable]=\"!!col.formElem.clearable\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <osl-autocomplete\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [placeholder]=\"col.formElem.autocompletePlaceholder || col.displayName\"\r\n [loading]=\"isLoading(row, col.formElem)\"\r\n [searchType]=\"col.formElem.searchType ? col.formElem.searchType : 'Local'\"\r\n [methodName]=\"col.formElem.apiMethod || ''\"\r\n [configMethodName]=\"col.formElem.apiConfigMethod || ''\"\r\n [service]=\"col.formElem.apiService\"\r\n [object]=\"col.formElem.objectName ? row[col.formElem.objectName] : null\"\r\n [isLister]=\"!!col.formElem.isListerAutocomplete\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? onSelectChange(col, row, i, $event) : null\">\r\n </osl-autocomplete>\r\n }\r\n\r\n @case ('radio') {\r\n <osl-radio\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [datasource]=\"col.formElem.datasource || []\"\r\n [displayField]=\"col.formElem.displayField || ''\"\r\n [valueField]=\"col.formElem.valueField || ''\"\r\n [inline]=\"!!col.formElem.inline\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-radio>\r\n }\r\n\r\n @case ('checkbox') {\r\n <osl-checkbox\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [indeterminate]=\"!!col.formElem.indeterminate\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-checkbox>\r\n }\r\n\r\n @case ('slide-toggle') {\r\n <osl-slide-toggle\r\n [label]=\"''\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [labelPosition]=\"col.formElem.labelPosition || 'after'\"\r\n [trueLabel]=\"col.formElem.trueLabel || ''\"\r\n [falseLabel]=\"col.formElem.falseLabel || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-slide-toggle>\r\n }\r\n\r\n @case ('datepicker') {\r\n <osl-datepicker\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [dateType]=\"col.formElem.dateType || 'date'\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [minDate]=\"col.formElem.minDate || ''\"\r\n [maxDate]=\"col.formElem.maxDate || ''\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-datepicker>\r\n }\r\n\r\n @case ('file-uploader') {\r\n <osl-file-upload\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [accept]=\"col.formElem.accept || ''\"\r\n [multiple]=\"!!col.formElem.multiple\"\r\n [maxSize]=\"col.formElem.maxFileSize || 0\"\r\n [model]=\"row[col.key]\"\r\n (modelChange)=\"onCellChange(row, col, $event)\"\r\n (changeEv)=\"col.formElem.change ? col.formElem.change(row,i) : null\">\r\n </osl-file-upload>\r\n }\r\n\r\n }\r\n </div>\r\n } @else {\r\n <span class=\"osl-fg-cell-text\">{{ row[col.key] ?? '--' }}</span>\r\n }\r\n </td>\r\n }\r\n\r\n </tr>\r\n }\r\n }\r\n\r\n </tbody>\r\n\r\n @if (footerColumns && footerColumns.length > 0 && datasource && datasource.length > 0) {\r\n <tfoot class=\"osl-fg-tfoot\">\r\n <tr class=\"osl-fg-footer-row\">\r\n @for (fcol of footerColumns; track $index) {\r\n <td\r\n [class]=\"'osl-fg-footer-td ' + (fcol.class || '')\"\r\n [attr.colspan]=\"fcol.colspan || 1\">\r\n {{ fcol.displayFn ? fcol.displayFn(datasource) : (fcol.display || '') }}\r\n </td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n\r\n </table>\r\n </div>\r\n\r\n @if (isPaginated) {\r\n <div class=\"osl-fg-pagination\">\r\n\r\n <span class=\"osl-fg-pagination__info\">\r\n @if (loading) {\r\n Loading...\r\n } @else if (_total > 0) {\r\n {{ startRecord }}\u2013{{ endRecord }} of {{ _total }} rows\r\n } @else {\r\n No rows\r\n }\r\n </span>\r\n\r\n <div class=\"osl-fg-pagination__controls\">\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(1)\" [disabled]=\"currentPage === 1 || loading\">\u00AB</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage - 1)\" [disabled]=\"currentPage === 1 || loading\">\u2039 Prev</button>\r\n\r\n @for (page of pageNumbers; track $index) {\r\n @if (page === -1) {\r\n <span class=\"osl-fg-page-ellipsis\">\u2026</span>\r\n } @else {\r\n <button\r\n class=\"osl-fg-page-btn osl-fg-page-btn--num\"\r\n [class.osl-fg-page-btn--active]=\"page === currentPage\"\r\n [disabled]=\"loading\"\r\n (click)=\"goToPage(page)\">\r\n {{ page }}\r\n </button>\r\n }\r\n }\r\n\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(currentPage + 1)\" [disabled]=\"currentPage === totalPages || loading\">Next \u203A</button>\r\n <button class=\"osl-fg-page-btn osl-fg-page-btn--nav\" (click)=\"goToPage(totalPages)\" [disabled]=\"currentPage === totalPages || loading\">\u00BB</button>\r\n </div>\r\n\r\n <div class=\"osl-fg-pagination__size\">\r\n <select class=\"osl-fg-page-size\" [ngModel]=\"pageSize\" (ngModelChange)=\"onPageSizeChange($event)\" [disabled]=\"loading\">\r\n @for (opt of pageSizeOptions; track opt) {\r\n <option [value]=\"opt\">{{ opt }} per page</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n </div>\r\n }\r\n\r\n</div>\r\n", styles: [".osl-fg-wrapper{display:flex;flex-direction:column;width:100%;font-size:var(--osl-text-font-size);font-family:inherit;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 8px);overflow:hidden;background:#fff}.osl-fg-table-container{overflow-x:auto;overflow-y:auto;min-height:120px}.osl-fg-table{width:100%;border-collapse:collapse;table-layout:auto}.osl-fg-thead{position:sticky;top:0;z-index:2}.osl-fg-th{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-bottom:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-th:last-child{border-right:none}.osl-fg-th--actions{width:44px;min-width:44px;text-align:center;padding:6px}.osl-fg-th-required{color:#ef4444;margin-left:2px;font-size:14px;line-height:1;vertical-align:middle}.osl-fg-row{border-bottom:1px solid #f0f0f0;transition:background .1s}.osl-fg-row:nth-child(odd){background:#f8fafc}.osl-fg-row:nth-child(2n){background:#fff}.osl-fg-row:hover{background:#eef2ff!important}.osl-fg-row:last-child{border-bottom:none}.osl-fg-row--skeleton{pointer-events:none}.osl-fg-td{padding:4px 10px;vertical-align:middle;border-right:1px solid #f0f0f0}.osl-fg-td:last-child{border-right:none}.osl-fg-td--actions{width:44px;min-width:44px;text-align:center;padding:4px 6px}.osl-fg-cell-form{min-width:100px}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.osl-fg-cell-form ::ng-deep .mat-mdc-form-field,.osl-fg-cell-form ::ng-deep mat-form-field{width:100%}.osl-fg-cell-form ::ng-deep .mat-mdc-text-field-wrapper{padding-top:0}.osl-fg-cell-text{color:#111827;font-size:var(--osl-text-font-size)}.osl-fg-add-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;border-radius:6px;background:var(--osl-primary, #6366f1);color:#fff;cursor:pointer;padding:0;box-shadow:0 1px 4px #6366f159;transition:background .15s,box-shadow .15s,transform .1s}.osl-fg-add-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.osl-fg-add-btn:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);box-shadow:0 2px 8px #6366f173;transform:scale(1.05)}.osl-fg-add-btn:disabled{opacity:.4;cursor:not-allowed;transform:none}.osl-fg-delete-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid transparent;border-radius:6px;background:transparent;color:#d1d5db;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s}.osl-fg-delete-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-fg-delete-btn:hover{border-color:#fca5a5;color:#ef4444;background:#fef2f2}.osl-fg-empty{padding:40px 16px;text-align:center}.osl-fg-empty-inner{display:flex;flex-direction:column;align-items:center;gap:10px;color:#9ca3af}.osl-fg-empty-inner svg{opacity:.4}.osl-fg-empty-inner p{margin:0;font-size:13px}@keyframes osl-fg-pulse{0%,to{opacity:1}50%{opacity:.4}}.osl-fg-skeleton{height:36px;border-radius:6px;background:#e5e7eb;animation:osl-fg-pulse 1.4s ease-in-out infinite}.osl-fg-skeleton--sm{height:28px;width:28px;border-radius:4px;margin:0 auto}.osl-fg-tfoot{position:sticky;bottom:0;z-index:2}.osl-fg-footer-td{background:#f3f4f6;color:#4b5563;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;text-align:left;border-top:2px solid var(--osl-border-color, #e5e7eb);border-right:1px solid var(--osl-border-color, #e5e7eb);white-space:nowrap;vertical-align:middle}.osl-fg-footer-td:last-child{border-right:none}.osl-fg-pagination{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--osl-border-color, #e5e7eb);background:#f9fafb;flex-shrink:0;flex-wrap:wrap}.osl-fg-pagination__info{font-size:12px;color:#6b7280;white-space:nowrap;min-width:120px}.osl-fg-pagination__controls{display:flex;align-items:center;gap:3px;flex-wrap:nowrap}.osl-fg-pagination__size{display:flex;align-items:center;justify-content:flex-end;min-width:120px}.osl-fg-page-btn{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:13px;font-family:inherit;cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.osl-fg-page-btn:hover:not(:disabled){background:#f3f4f6;border-color:#9ca3af}.osl-fg-page-btn:disabled{opacity:.35;cursor:not-allowed}.osl-fg-page-btn--nav{font-size:12px;color:#6b7280}.osl-fg-page-btn--num{min-width:30px;padding:0;font-size:13px}.osl-fg-page-btn--active{background:var(--osl-primary, #6366f1);border-color:var(--osl-primary, #6366f1);color:#fff;font-weight:600}.osl-fg-page-btn--active:hover:not(:disabled){background:var(--osl-primary-hover, #4f46e5);border-color:var(--osl-primary-hover, #4f46e5)}.osl-fg-page-ellipsis{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;color:#9ca3af;font-size:13px;pointer-events:none}.osl-fg-page-size{height:30px;padding:0 8px;border:1px solid var(--osl-border-color, #e5e7eb);border-radius:var(--osl-border-radius, 6px);background:#fff;color:#374151;font-size:12px;font-family:inherit;cursor:pointer;outline:none}.osl-fg-page-size:focus{border-color:var(--osl-primary, #6366f1)}.osl-fg-page-size:disabled{opacity:.4;cursor:not-allowed}.osl-grid-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1.5px solid var(--osl-border-color);border-radius:var(--osl-border-radius);background:transparent;color:#6b7280;cursor:pointer;padding:0;transition:border-color .15s,color .15s,background .15s;margin:0 2px}.osl-grid-icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.osl-grid-icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.osl-grid-icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"] }]
2811
2814
  }], propDecorators: { columns: [{
2812
2815
  type: Input,
2813
2816
  args: ['columns']
@@ -2938,6 +2941,7 @@ class FormStructureModule {
2938
2941
  OslFormGrid,
2939
2942
  OslAutocompleteLister], imports: [NgTemplateOutlet,
2940
2943
  NgStyle,
2944
+ DatePipe,
2941
2945
  FormsModule,
2942
2946
  ReactiveFormsModule,
2943
2947
  MatFormFieldModule,
@@ -2997,6 +3001,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2997
3001
  imports: [
2998
3002
  NgTemplateOutlet,
2999
3003
  NgStyle,
3004
+ DatePipe,
3000
3005
  FormsModule,
3001
3006
  ReactiveFormsModule,
3002
3007
  MatFormFieldModule,