osl-base-extended 2.0.2 → 2.0.4

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.
@@ -18,12 +18,15 @@ import * as i2$1 from '@angular/material/form-field';
18
18
  import { MatFormFieldModule, MatHint } from '@angular/material/form-field';
19
19
  import * as i5 from '@angular/material/datepicker';
20
20
  import { MatDatepickerModule } from '@angular/material/datepicker';
21
+ import * as i4 from '@ngxmc/datetime-picker';
22
+ import { NgxMatDatetimepicker, NgxMatDatepickerInput, NgxMatDatepickerToggle } from '@ngxmc/datetime-picker';
21
23
  import { MatInputModule } from '@angular/material/input';
22
24
  import { debounceTime as debounceTime$1, distinctUntilChanged as distinctUntilChanged$1 } from 'rxjs/operators';
23
25
  import { MatMenuModule } from '@angular/material/menu';
24
26
  import { ScrollingModule } from '@angular/cdk/scrolling';
25
27
  import * as i3$1 from '@angular/cdk/drag-drop';
26
28
  import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
29
+ import { NativeDateAdapter, DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
27
30
 
28
31
  class OslBaseExtended {
29
32
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslBaseExtended, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -280,10 +283,10 @@ class Httpbase {
280
283
  };
281
284
  }
282
285
  handleError(error) {
283
- if (error.status === 401) {
284
- // localStorage.clear();
285
- window.location.href = '/login';
286
- }
286
+ // if (error.status === 401) {
287
+ // // localStorage.clear();
288
+ // window.location.href = '/login';
289
+ // }
287
290
  return {
288
291
  isSuccessful: false,
289
292
  error: this.mapError(error),
@@ -2089,251 +2092,631 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2089
2092
  type: Output
2090
2093
  }] } });
2091
2094
 
2092
- class OslCheckbox {
2093
- checkboxEl;
2094
- label = '';
2095
- disabled = false;
2096
- required = false;
2097
- model = false;
2098
- indeterminate = false;
2099
- skeletonLoading = false;
2100
- skeletonTheme = 'light';
2101
- modelChange = new EventEmitter();
2102
- changeEv = new EventEmitter();
2103
- touched = false;
2104
- get isInvalid() {
2105
- return this.touched && this.required && !this.model;
2106
- }
2107
- ngOnChanges(changes) {
2108
- if (changes['indeterminate'] && this.checkboxEl) {
2109
- this.checkboxEl.nativeElement.indeterminate = this.indeterminate;
2110
- }
2111
- }
2112
- ngAfterViewInit() {
2113
- if (this.checkboxEl) {
2114
- this.checkboxEl.nativeElement.indeterminate = this.indeterminate;
2115
- }
2116
- }
2117
- onModelChange(event) {
2118
- this.touched = true;
2119
- this.model = event;
2120
- this.modelChange.emit(this.model);
2121
- this.changeEv.emit(this.model);
2122
- }
2123
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
2124
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslCheckbox, isStandalone: false, selector: "osl-checkbox", inputs: { label: "label", disabled: "disabled", required: "required", model: "model", indeterminate: "indeterminate", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme" }, outputs: { modelChange: "modelChange", changeEv: "changeEv" }, viewQueries: [{ propertyName: "checkboxEl", first: true, predicate: ["checkboxEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"d-flex flex-column\">\r\n\r\n <label class=\"checkbox-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.checkbox-disabled]=\"disabled\" [class.checkbox-invalid]=\"isInvalid\">\r\n <input\r\n #checkboxEl\r\n type=\"checkbox\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n [disabled]=\"disabled\"\r\n >\r\n <span class=\"checkbox-label\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n {{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span>\r\n </span>\r\n </label>\r\n @if(isInvalid) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n }\r\n</div>\r\n", styles: [".checkbox-wrapper{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:var(--osl-label-font-size);width:fit-content}.checkbox-wrapper input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:#333;flex-shrink:0}.checkbox-wrapper .checkbox-label{-webkit-user-select:none;user-select:none}.checkbox-wrapper.checkbox-disabled{opacity:.6;cursor:not-allowed}.checkbox-wrapper.checkbox-disabled input[type=checkbox]{cursor:not-allowed}.checkbox-wrapper.checkbox-invalid{color:var(--osl-error-color)}.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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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: "directive", type: i2$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { 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"] }] });
2095
+ // ─── Date Utilities ───────────────────────────────────────────────────────────
2096
+ const MONTH_NAMES_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
2097
+ const MONTH_NAMES_FULL = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
2098
+ const DAY_NAMES_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
2099
+ const DAY_NAMES_FULL = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
2100
+ function pad(n) {
2101
+ return String(n).padStart(2, '0');
2125
2102
  }
2126
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslCheckbox, decorators: [{
2127
- type: Component,
2128
- args: [{ selector: 'osl-checkbox', standalone: false, template: "<div class=\"d-flex flex-column\">\r\n\r\n <label class=\"checkbox-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.checkbox-disabled]=\"disabled\" [class.checkbox-invalid]=\"isInvalid\">\r\n <input\r\n #checkboxEl\r\n type=\"checkbox\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n [disabled]=\"disabled\"\r\n >\r\n <span class=\"checkbox-label\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n {{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span>\r\n </span>\r\n </label>\r\n @if(isInvalid) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n }\r\n</div>\r\n", styles: [".checkbox-wrapper{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:var(--osl-label-font-size);width:fit-content}.checkbox-wrapper input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:#333;flex-shrink:0}.checkbox-wrapper .checkbox-label{-webkit-user-select:none;user-select:none}.checkbox-wrapper.checkbox-disabled{opacity:.6;cursor:not-allowed}.checkbox-wrapper.checkbox-disabled input[type=checkbox]{cursor:not-allowed}.checkbox-wrapper.checkbox-invalid{color:var(--osl-error-color)}.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"] }]
2129
- }], propDecorators: { checkboxEl: [{
2130
- type: ViewChild,
2131
- args: ['checkboxEl']
2132
- }], label: [{
2133
- type: Input,
2134
- args: ['label']
2135
- }], disabled: [{
2136
- type: Input,
2137
- args: ['disabled']
2138
- }], required: [{
2139
- type: Input,
2140
- args: ['required']
2141
- }], model: [{
2142
- type: Input,
2143
- args: ['model']
2144
- }], indeterminate: [{
2145
- type: Input,
2146
- args: ['indeterminate']
2147
- }], skeletonLoading: [{
2148
- type: Input,
2149
- args: ['skeletonLoading']
2150
- }], skeletonTheme: [{
2151
- type: Input,
2152
- args: ['skeletonTheme']
2153
- }], modelChange: [{
2154
- type: Output
2155
- }], changeEv: [{
2156
- type: Output
2157
- }] } });
2158
-
2159
- class OslButton {
2160
- label = 'Button';
2161
- icon = '';
2162
- variant = 'primary';
2163
- size = 'md';
2164
- disabled = false;
2165
- loading = false;
2166
- type = 'button';
2167
- fullWidth = false;
2168
- clickEv = new EventEmitter();
2169
- get classes() {
2170
- return [
2171
- 'osl-btn',
2172
- `osl-btn--${this.variant}`,
2173
- `osl-btn--${this.size}`,
2174
- this.fullWidth ? 'osl-btn--full' : '',
2175
- ]
2176
- .filter(Boolean)
2177
- .join(' ');
2178
- }
2179
- onClick() {
2180
- if (!this.disabled && !this.loading) {
2181
- this.clickEv.emit();
2182
- }
2183
- }
2184
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2185
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslButton, isStandalone: false, selector: "osl-button", inputs: { label: "label", icon: "icon", variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type", fullWidth: "fullWidth" }, outputs: { clickEv: "clickEv" }, ngImport: i0, template: "@if (variant == 'icon' && icon) {\r\n <button class=\"icon-btn\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n } @else {\r\n <mat-icon>{{ icon }}</mat-icon>\r\n }\r\n </button>\r\n} @else {\r\n <button [class]=\"classes\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n }\r\n <span class=\"osl-btn__label\">{{ label }}</span>\r\n @if (icon) {\r\n <span class=\"osl-btn__label-icon\"\r\n ><mat-icon>{{ icon }}</mat-icon></span\r\n >\r\n }\r\n </button>\r\n}\r\n", styles: ["@charset \"UTF-8\";.osl-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border:none;border-radius:var(--osl-border-radius);cursor:pointer;font-size:var(--osl-label-font-size);font-weight:500;line-height:1;transition:background-color .2s ease,border-color .2s ease,opacity .2s ease;white-space:nowrap;outline:none}.osl-btn--sm{height:28px;padding:0 var(--osl-hint-font-size);font-size:var(--osl-hint-font-size)}.osl-btn--sm mat-icon{font-size:var(--osl-hint-font-size)}.osl-btn--md{height:36px;padding:0 18px;font-size:var(--osl-label-font-size)}.osl-btn--lg{height:44px;padding:0 24px;font-size:16px}.osl-btn--full{width:100%}.osl-btn:disabled{opacity:var(--osl-disabled-opacity);cursor:not-allowed}.osl-btn--primary{background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--primary:hover:not(:disabled){background-color:var(--osl-primary-hover)}.osl-btn--secondary{background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--secondary:hover:not(:disabled){background-color:var(--osl-secondary-hover)}.osl-btn--success{background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--success:hover:not(:disabled){background-color:var(--osl-success-hover)}.osl-btn--danger{background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--danger:hover:not(:disabled){background-color:var(--osl-danger-hover)}.osl-btn--warning{background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--warning:hover:not(:disabled){background-color:var(--osl-warning-hover)}.osl-btn--info{background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn--info:hover:not(:disabled){background-color:var(--osl-info-hover)}.osl-btn--outline-primary{background-color:transparent;border:1.5px solid var(--osl-primary);color:var(--osl-primary)}.osl-btn--outline-primary:hover:not(:disabled){background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--outline-secondary{background-color:transparent;border:1.5px solid var(--osl-secondary);color:var(--osl-secondary)}.osl-btn--outline-secondary:hover:not(:disabled){background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--outline-success{background-color:transparent;border:1.5px solid var(--osl-success);color:var(--osl-success)}.osl-btn--outline-success:hover:not(:disabled){background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--outline-danger{background-color:transparent;border:1.5px solid var(--osl-danger);color:var(--osl-danger)}.osl-btn--outline-danger:hover:not(:disabled){background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--outline-warning{background-color:transparent;border:1.5px solid var(--osl-warning);color:var(--osl-warning)}.osl-btn--outline-warning:hover:not(:disabled){background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--outline-info{background-color:transparent;border:1.5px solid var(--osl-info);color:var(--osl-info)}.osl-btn--outline-info:hover:not(:disabled){background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn__spinner{display:inline-block;width:var(--osl-label-font-size);height:var(--osl-label-font-size);border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:osl-spin .7s linear infinite}@keyframes osl-spin{to{transform:rotate(360deg)}}.osl-btn__label-icon{color:var(--color-white)}.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}.icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"], dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
2103
+ /** Returns the current date and time. */
2104
+ function now() {
2105
+ return new Date();
2186
2106
  }
2187
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslButton, decorators: [{
2188
- type: Component,
2189
- args: [{ selector: 'osl-button', standalone: false, template: "@if (variant == 'icon' && icon) {\r\n <button class=\"icon-btn\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n } @else {\r\n <mat-icon>{{ icon }}</mat-icon>\r\n }\r\n </button>\r\n} @else {\r\n <button [class]=\"classes\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n }\r\n <span class=\"osl-btn__label\">{{ label }}</span>\r\n @if (icon) {\r\n <span class=\"osl-btn__label-icon\"\r\n ><mat-icon>{{ icon }}</mat-icon></span\r\n >\r\n }\r\n </button>\r\n}\r\n", styles: ["@charset \"UTF-8\";.osl-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border:none;border-radius:var(--osl-border-radius);cursor:pointer;font-size:var(--osl-label-font-size);font-weight:500;line-height:1;transition:background-color .2s ease,border-color .2s ease,opacity .2s ease;white-space:nowrap;outline:none}.osl-btn--sm{height:28px;padding:0 var(--osl-hint-font-size);font-size:var(--osl-hint-font-size)}.osl-btn--sm mat-icon{font-size:var(--osl-hint-font-size)}.osl-btn--md{height:36px;padding:0 18px;font-size:var(--osl-label-font-size)}.osl-btn--lg{height:44px;padding:0 24px;font-size:16px}.osl-btn--full{width:100%}.osl-btn:disabled{opacity:var(--osl-disabled-opacity);cursor:not-allowed}.osl-btn--primary{background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--primary:hover:not(:disabled){background-color:var(--osl-primary-hover)}.osl-btn--secondary{background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--secondary:hover:not(:disabled){background-color:var(--osl-secondary-hover)}.osl-btn--success{background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--success:hover:not(:disabled){background-color:var(--osl-success-hover)}.osl-btn--danger{background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--danger:hover:not(:disabled){background-color:var(--osl-danger-hover)}.osl-btn--warning{background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--warning:hover:not(:disabled){background-color:var(--osl-warning-hover)}.osl-btn--info{background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn--info:hover:not(:disabled){background-color:var(--osl-info-hover)}.osl-btn--outline-primary{background-color:transparent;border:1.5px solid var(--osl-primary);color:var(--osl-primary)}.osl-btn--outline-primary:hover:not(:disabled){background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--outline-secondary{background-color:transparent;border:1.5px solid var(--osl-secondary);color:var(--osl-secondary)}.osl-btn--outline-secondary:hover:not(:disabled){background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--outline-success{background-color:transparent;border:1.5px solid var(--osl-success);color:var(--osl-success)}.osl-btn--outline-success:hover:not(:disabled){background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--outline-danger{background-color:transparent;border:1.5px solid var(--osl-danger);color:var(--osl-danger)}.osl-btn--outline-danger:hover:not(:disabled){background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--outline-warning{background-color:transparent;border:1.5px solid var(--osl-warning);color:var(--osl-warning)}.osl-btn--outline-warning:hover:not(:disabled){background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--outline-info{background-color:transparent;border:1.5px solid var(--osl-info);color:var(--osl-info)}.osl-btn--outline-info:hover:not(:disabled){background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn__spinner{display:inline-block;width:var(--osl-label-font-size);height:var(--osl-label-font-size);border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:osl-spin .7s linear infinite}@keyframes osl-spin{to{transform:rotate(360deg)}}.osl-btn__label-icon{color:var(--color-white)}.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}.icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"] }]
2190
- }], propDecorators: { label: [{
2191
- type: Input,
2192
- args: ['label']
2193
- }], icon: [{
2194
- type: Input,
2195
- args: ['icon']
2196
- }], variant: [{
2197
- type: Input,
2198
- args: ['variant']
2199
- }], size: [{
2200
- type: Input,
2201
- args: ['size']
2202
- }], disabled: [{
2203
- type: Input,
2204
- args: ['disabled']
2205
- }], loading: [{
2206
- type: Input,
2207
- args: ['loading']
2208
- }], type: [{
2209
- type: Input,
2210
- args: ['type']
2211
- }], fullWidth: [{
2212
- type: Input,
2213
- args: ['fullWidth']
2214
- }], clickEv: [{
2215
- type: Output
2216
- }] } });
2217
-
2218
- class DynamicForm {
2219
- cdr;
2220
- elements = [];
2221
- _model;
2222
- set model(val) {
2223
- this._model = val;
2224
- }
2225
- get model() {
2226
- return this._model;
2227
- }
2228
- skeletonLoading = false;
2229
- skeletonTheme = 'light';
2230
- modelChange = new EventEmitter();
2231
- datasourceCache = inject(DatasourceCacheService);
2232
- constructor(cdr) {
2233
- this.cdr = cdr;
2234
- }
2235
- ngOnInit() {
2236
- this.loadApiDatasources();
2237
- }
2238
- ngOnChanges(changes) {
2239
- if (changes['elements']) {
2240
- this.loadApiDatasources();
2241
- }
2242
- }
2243
- loadApiDatasources() {
2244
- this._loadForList(this.elements);
2245
- }
2246
- async _loadForList(list) {
2247
- for (const elem of list) {
2248
- if (elem.elementType === 'fieldset' && elem.rows?.length) {
2249
- this._loadForList(elem.rows);
2250
- }
2251
- else if (elem.apiService && elem.apiMethod && (!elem.searchType || elem.searchType == 'Local')) {
2252
- elem.loadingIf = () => true;
2253
- const data = await this.datasourceCache.load(elem.apiService, elem.apiMethod, elem.apiBody ? elem.apiBody(this.model) : null);
2254
- elem.loadingIf = () => false;
2255
- this.cdr.markForCheck();
2256
- if (data && data.length > 0) {
2257
- elem.datasource = data;
2258
- }
2259
- }
2260
- }
2261
- }
2262
- onModelChange(event, key) {
2263
- this.model[key] = event;
2264
- this.modelChange.emit(this.model);
2265
- }
2266
- onSelectChange(elem, value) {
2267
- if (!elem.change)
2268
- return;
2269
- let selectedObj = undefined;
2270
- if (elem.datasource) {
2271
- if (Array.isArray(value)) {
2272
- selectedObj = value.map(v => elem.datasource.find(item => (elem.valueField ? item[elem.valueField] : item) === v) ?? null);
2273
- }
2274
- else if (value !== null && value !== undefined) {
2275
- selectedObj = elem.datasource.find(item => (elem.valueField ? item[elem.valueField] : item) === (isNaN(Number(value)) ? value : Number(value))) ?? null;
2276
- }
2277
- else {
2278
- selectedObj = null;
2279
- }
2280
- }
2281
- elem.change(this.model, undefined, selectedObj);
2282
- }
2283
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DynamicForm, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2284
- 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 [isCapitalize]=\"elem.isCapitalize\"\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.minDateIf ? elem.minDateIf(model): elem.minDate ? elem.minDate : ''\"\r\n [maxDate]=\"elem.maxDateIf ? elem.maxDateIf(model): elem.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", "isCapitalize", "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: ["datasourceChange", "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"] }] });
2107
+ /** Returns today's date with time set to midnight. */
2108
+ function today() {
2109
+ return startOfDay(new Date());
2285
2110
  }
2286
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DynamicForm, decorators: [{
2287
- type: Component,
2288
- 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 [isCapitalize]=\"elem.isCapitalize\"\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.minDateIf ? elem.minDateIf(model): elem.minDate ? elem.minDate : ''\"\r\n [maxDate]=\"elem.maxDateIf ? elem.maxDateIf(model): elem.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"] }]
2289
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { elements: [{
2290
- type: Input,
2291
- args: ['elements']
2292
- }], model: [{
2293
- type: Input,
2294
- args: ['model']
2295
- }], skeletonLoading: [{
2296
- type: Input,
2297
- args: ['skeletonLoading']
2298
- }], skeletonTheme: [{
2299
- type: Input,
2300
- args: ['skeletonTheme']
2301
- }], modelChange: [{
2302
- type: Output
2303
- }] } });
2304
-
2305
- class OslSetupStateService {
2306
- _map = new Map();
2307
- save(key, state) {
2308
- this._map.set(key, state);
2309
- }
2310
- consume(key) {
2311
- const state = this._map.get(key);
2312
- if (state)
2313
- this._map.delete(key);
2314
- return state;
2315
- }
2316
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslSetupStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2317
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslSetupStateService, providedIn: 'root' });
2111
+ /** Returns true if the value is a valid Date object. */
2112
+ function isValidDate$1(value) {
2113
+ return value instanceof Date && !isNaN(value.getTime());
2318
2114
  }
2319
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslSetupStateService, decorators: [{
2320
- type: Injectable,
2321
- args: [{ providedIn: 'root' }]
2322
- }] });
2323
-
2324
- class OslSearchbar {
2325
- label = "Type to Search...";
2326
- onSearch = new EventEmitter();
2327
- searchQuery = "";
2328
- searchControl = new FormControl('');
2329
- onKeyChange() {
2330
- if (!this.searchQuery) {
2331
- this.onSearch.emit(this.searchQuery);
2332
- }
2333
- }
2334
- ngOnInit() {
2335
- this.searchControl.valueChanges.pipe(debounceTime$1(300), distinctUntilChanged$1()).subscribe(value => {
2336
- if (value) {
2115
+ /**
2116
+ * Formats a Date using a pattern string.
2117
+ * Tokens: YYYY, YY, MM, M, DD, D, HH, H, mm, m, ss, s,
2118
+ * MMM (short month), MMMM (full month),
2119
+ * ddd (short day), dddd (full day).
2120
+ */
2121
+ function formatDate(date, pattern) {
2122
+ const d = new Date(date);
2123
+ if (!isValidDate$1(d))
2124
+ return '';
2125
+ const year = d.getFullYear();
2126
+ const month = d.getMonth();
2127
+ const day = d.getDate();
2128
+ const hours = d.getHours();
2129
+ const mins = d.getMinutes();
2130
+ const secs = d.getSeconds();
2131
+ const dayOfWeek = d.getDay();
2132
+ return pattern
2133
+ .replace('YYYY', String(year))
2134
+ .replace('YY', String(year).slice(-2))
2135
+ .replace('MMMM', MONTH_NAMES_FULL[month])
2136
+ .replace('MMM', MONTH_NAMES_SHORT[month])
2137
+ .replace('MM', pad(month + 1))
2138
+ .replace('M', String(month + 1))
2139
+ .replace('dddd', DAY_NAMES_FULL[dayOfWeek])
2140
+ .replace('ddd', DAY_NAMES_SHORT[dayOfWeek])
2141
+ .replace('DD', pad(day))
2142
+ .replace('D', String(day))
2143
+ .replace('HH', pad(hours))
2144
+ .replace('H', String(hours))
2145
+ .replace('mm', pad(mins))
2146
+ .replace('m', String(mins))
2147
+ .replace('ss', pad(secs))
2148
+ .replace('s', String(secs));
2149
+ }
2150
+ /** Returns date as `YYYY-MM-DD`. */
2151
+ function toDateOnly(date) {
2152
+ return formatDate(date, 'YYYY-MM-DD');
2153
+ }
2154
+ /** Returns the ISO 8601 string for a date. */
2155
+ function toISOString(date) {
2156
+ return date.toISOString();
2157
+ }
2158
+ /** Returns a new date with `days` added. */
2159
+ function addDays(date, days) {
2160
+ const result = new Date(date);
2161
+ result.setDate(result.getDate() + days);
2162
+ return result;
2163
+ }
2164
+ /** Returns a new date with `months` added. */
2165
+ function addMonths(date, months) {
2166
+ const result = new Date(date);
2167
+ result.setMonth(result.getMonth() + months);
2168
+ return result;
2169
+ }
2170
+ /** Returns a new date with `years` added. */
2171
+ function addYears(date, years) {
2172
+ const result = new Date(date);
2173
+ result.setFullYear(result.getFullYear() + years);
2174
+ return result;
2175
+ }
2176
+ /** Returns a new date with `hours` added. */
2177
+ function addHours(date, hours) {
2178
+ return new Date(date.getTime() + hours * 3_600_000);
2179
+ }
2180
+ /** Returns a new date with `minutes` added. */
2181
+ function addMinutes(date, minutes) {
2182
+ return new Date(date.getTime() + minutes * 60_000);
2183
+ }
2184
+ /** Returns a new date with `days` subtracted. */
2185
+ function subtractDays(date, days) {
2186
+ return addDays(date, -days);
2187
+ }
2188
+ /** Returns a new date with `months` subtracted. */
2189
+ function subtractMonths(date, months) {
2190
+ return addMonths(date, -months);
2191
+ }
2192
+ /** Returns a new date with `years` subtracted. */
2193
+ function subtractYears(date, years) {
2194
+ return addYears(date, -years);
2195
+ }
2196
+ /** Returns the absolute difference in whole days between two dates. */
2197
+ function diffInDays(date1, date2) {
2198
+ return Math.abs(Math.floor((date1.getTime() - date2.getTime()) / 86_400_000));
2199
+ }
2200
+ /** Returns the absolute difference in whole months between two dates. */
2201
+ function diffInMonths(date1, date2) {
2202
+ return Math.abs((date1.getFullYear() - date2.getFullYear()) * 12 +
2203
+ (date1.getMonth() - date2.getMonth()));
2204
+ }
2205
+ /** Returns the absolute difference in whole years between two dates. */
2206
+ function diffInYears(date1, date2) {
2207
+ return Math.abs(date1.getFullYear() - date2.getFullYear());
2208
+ }
2209
+ /** Returns the difference in minutes between two dates (date1 - date2). */
2210
+ function diffInMinutes(date1, date2) {
2211
+ return Math.floor((date1.getTime() - date2.getTime()) / 60_000);
2212
+ }
2213
+ /** Returns true if date1 is strictly before date2. */
2214
+ function isBefore(date1, date2) {
2215
+ return date1.getTime() < date2.getTime();
2216
+ }
2217
+ /** Returns true if date1 is strictly after date2. */
2218
+ function isAfter(date1, date2) {
2219
+ return date1.getTime() > date2.getTime();
2220
+ }
2221
+ /** Returns true if both dates fall on the same calendar day. */
2222
+ function isSameDay(date1, date2) {
2223
+ return (date1.getFullYear() === date2.getFullYear() &&
2224
+ date1.getMonth() === date2.getMonth() &&
2225
+ date1.getDate() === date2.getDate());
2226
+ }
2227
+ /** Returns true if the date falls on a Saturday or Sunday. */
2228
+ function isWeekend(date) {
2229
+ return date.getDay() === 0 || date.getDay() === 6;
2230
+ }
2231
+ /** Returns true if the date is today. */
2232
+ function isToday(date) {
2233
+ return isSameDay(date, new Date());
2234
+ }
2235
+ /** Returns true if the date falls in the past (before now). */
2236
+ function isPast(date) {
2237
+ return date.getTime() < Date.now();
2238
+ }
2239
+ /** Returns true if the date falls in the future (after now). */
2240
+ function isFuture(date) {
2241
+ return date.getTime() > Date.now();
2242
+ }
2243
+ /** Returns the date with time set to 00:00:00.000. */
2244
+ function startOfDay(date) {
2245
+ const result = new Date(date);
2246
+ result.setHours(0, 0, 0, 0);
2247
+ return result;
2248
+ }
2249
+ /** Returns the date with time set to 23:59:59.999. */
2250
+ function endOfDay(date) {
2251
+ const result = new Date(date);
2252
+ result.setHours(23, 59, 59, 999);
2253
+ return result;
2254
+ }
2255
+ /** Returns the first day of the month (time 00:00:00.000). */
2256
+ function startOfMonth(date) {
2257
+ return new Date(date.getFullYear(), date.getMonth(), 1);
2258
+ }
2259
+ /** Returns the last day of the month (time 23:59:59.999). */
2260
+ function endOfMonth(date) {
2261
+ const result = new Date(date.getFullYear(), date.getMonth() + 1, 0);
2262
+ result.setHours(23, 59, 59, 999);
2263
+ return result;
2264
+ }
2265
+ /** Returns the first day of the year (Jan 1, 00:00:00.000). */
2266
+ function startOfYear(date) {
2267
+ return new Date(date.getFullYear(), 0, 1);
2268
+ }
2269
+ /** Returns the last day of the year (Dec 31, 23:59:59.999). */
2270
+ function endOfYear(date) {
2271
+ const result = new Date(date.getFullYear(), 11, 31);
2272
+ result.setHours(23, 59, 59, 999);
2273
+ return result;
2274
+ }
2275
+ /** Calculates the age in years from a birth date. */
2276
+ function getAge(birthDate) {
2277
+ const n = new Date();
2278
+ let age = n.getFullYear() - birthDate.getFullYear();
2279
+ const monthDiff = n.getMonth() - birthDate.getMonth();
2280
+ if (monthDiff < 0 || (monthDiff === 0 && n.getDate() < birthDate.getDate()))
2281
+ age--;
2282
+ return age;
2283
+ }
2284
+ /** Returns the number of days in a given month (0-based month). */
2285
+ function daysInMonth(year, month) {
2286
+ return new Date(year, month + 1, 0).getDate();
2287
+ }
2288
+ /** Returns true if the given year is a leap year. */
2289
+ function isLeapYear(year) {
2290
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
2291
+ }
2292
+ /**
2293
+ * Returns a human-friendly relative time string.
2294
+ * @example timeAgo(new Date(Date.now() - 3600_000)) → '1 hour ago'
2295
+ */
2296
+ function timeAgo(date) {
2297
+ const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
2298
+ const abs = Math.abs(seconds);
2299
+ const future = seconds < 0;
2300
+ const intervals = [
2301
+ [31_536_000, 'year'],
2302
+ [2_592_000, 'month'],
2303
+ [604_800, 'week'],
2304
+ [86_400, 'day'],
2305
+ [3_600, 'hour'],
2306
+ [60, 'minute'],
2307
+ [1, 'second'],
2308
+ ];
2309
+ for (const [secs, label] of intervals) {
2310
+ const count = Math.floor(abs / secs);
2311
+ if (count >= 1) {
2312
+ const unit = count === 1 ? label : `${label}s`;
2313
+ return future ? `in ${count} ${unit}` : `${count} ${unit} ago`;
2314
+ }
2315
+ }
2316
+ return 'just now';
2317
+ }
2318
+ /** Returns the ISO week number (1–53) for the given date. */
2319
+ function getWeekNumber(date) {
2320
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
2321
+ d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
2322
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
2323
+ return Math.ceil((((d.getTime() - yearStart.getTime()) / 86_400_000) + 1) / 7);
2324
+ }
2325
+ /** Returns the next weekday (Mon–Fri) after the given date. */
2326
+ function nextWorkday(date) {
2327
+ const result = addDays(date, 1);
2328
+ while (isWeekend(result)) {
2329
+ result.setDate(result.getDate() + 1);
2330
+ }
2331
+ return result;
2332
+ }
2333
+ /** Returns true if a date falls within the range [start, end] (inclusive). */
2334
+ function inRange$2(date, start, end) {
2335
+ return date >= start && date <= end;
2336
+ }
2337
+ /** Parses a `YYYY-MM-DD` string and returns a local-midnight Date or null. */
2338
+ function parseDate(dateStr) {
2339
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateStr);
2340
+ if (!match)
2341
+ return null;
2342
+ const [, y, mo, d] = match.map(Number);
2343
+ const result = new Date(y, mo - 1, d);
2344
+ return isValidDate$1(result) ? result : null;
2345
+ }
2346
+
2347
+ var date_util = /*#__PURE__*/Object.freeze({
2348
+ __proto__: null,
2349
+ addDays: addDays,
2350
+ addHours: addHours,
2351
+ addMinutes: addMinutes,
2352
+ addMonths: addMonths,
2353
+ addYears: addYears,
2354
+ daysInMonth: daysInMonth,
2355
+ diffInDays: diffInDays,
2356
+ diffInMinutes: diffInMinutes,
2357
+ diffInMonths: diffInMonths,
2358
+ diffInYears: diffInYears,
2359
+ endOfDay: endOfDay,
2360
+ endOfMonth: endOfMonth,
2361
+ endOfYear: endOfYear,
2362
+ formatDate: formatDate,
2363
+ getAge: getAge,
2364
+ getWeekNumber: getWeekNumber,
2365
+ inRange: inRange$2,
2366
+ isAfter: isAfter,
2367
+ isBefore: isBefore,
2368
+ isFuture: isFuture,
2369
+ isLeapYear: isLeapYear,
2370
+ isPast: isPast,
2371
+ isSameDay: isSameDay,
2372
+ isToday: isToday,
2373
+ isValidDate: isValidDate$1,
2374
+ isWeekend: isWeekend,
2375
+ nextWorkday: nextWorkday,
2376
+ now: now,
2377
+ parseDate: parseDate,
2378
+ startOfDay: startOfDay,
2379
+ startOfMonth: startOfMonth,
2380
+ startOfYear: startOfYear,
2381
+ subtractDays: subtractDays,
2382
+ subtractMonths: subtractMonths,
2383
+ subtractYears: subtractYears,
2384
+ timeAgo: timeAgo,
2385
+ toDateOnly: toDateOnly,
2386
+ toISOString: toISOString,
2387
+ today: today
2388
+ });
2389
+
2390
+ class OslDatetimepicker {
2391
+ label = '';
2392
+ required = false;
2393
+ disabled = false;
2394
+ dateModel = null;
2395
+ set model(val) {
2396
+ this.dateModel = this._parseToDate(val);
2397
+ }
2398
+ placeholder = '';
2399
+ minDate = null;
2400
+ maxDate = null;
2401
+ set minDatetime(val) {
2402
+ this.minDate = this._parseToDate(val);
2403
+ }
2404
+ set maxDatetime(val) {
2405
+ this.maxDate = this._parseToDate(val);
2406
+ }
2407
+ /** Output format for the emitted string value. Uses date.util tokens: YYYY, MM, DD, HH, mm, ss */
2408
+ format = 'YYYY-MM-DDTHH:mm';
2409
+ showSeconds = false;
2410
+ enableMeridian = false;
2411
+ skeletonLoading = false;
2412
+ skeletonTheme = 'light';
2413
+ modelChange = new EventEmitter();
2414
+ changeEv = new EventEmitter();
2415
+ onDateChange(date) {
2416
+ this.dateModel = date;
2417
+ const str = date ? formatDate(date, this.format) : '';
2418
+ this.modelChange.emit(str);
2419
+ this.changeEv.emit(str);
2420
+ }
2421
+ _parseToDate(val) {
2422
+ if (!val)
2423
+ return null;
2424
+ const d = new Date(val);
2425
+ return isNaN(d.getTime()) ? null : d;
2426
+ }
2427
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslDatetimepicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
2428
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslDatetimepicker, isStandalone: false, selector: "osl-datetimepicker", inputs: { label: "label", required: "required", disabled: "disabled", model: "model", placeholder: "placeholder", minDatetime: "minDatetime", maxDatetime: "maxDatetime", format: "format", showSeconds: "showSeconds", enableMeridian: "enableMeridian", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme" }, outputs: { modelChange: "modelChange", changeEv: "changeEv" }, ngImport: i0, template: "<div class=\"d-flex flex-column\">\n @if (label) {\n <div [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\n <label class=\"label\" [class.txt-clr-red]=\"dtField.touched && dtField.invalid\">\n {{label}} <span class=\"txt-clr-red\">{{required ? '*' : ''}}</span>\n </label>\n </div>\n }\n <div class=\"input-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\n <input\n class=\"dt-input\"\n [ngxMatDatetimePicker]=\"picker\"\n [ngModel]=\"dateModel\"\n (ngModelChange)=\"onDateChange($event)\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [min]=\"minDate\"\n [max]=\"maxDate\"\n [placeholder]=\"placeholder\"\n [class.error]=\"dtField.touched && dtField.invalid\"\n #dtField=\"ngModel\"\n />\n <ngx-mat-datepicker-toggle\n [for]=\"picker\"\n [disabled]=\"disabled\"\n class=\"dt-toggle\">\n </ngx-mat-datepicker-toggle>\n <ngx-mat-datetime-picker\n #picker\n [showSpinners]=\"true\"\n [showSeconds]=\"showSeconds\"\n [enableMeridian]=\"enableMeridian\">\n </ngx-mat-datetime-picker>\n </div>\n @if (dtField.touched && dtField.invalid && required) {\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\n }\n</div>\n", styles: [".label{font-size:var(--osl-label-font-size);margin-bottom:5px}.txt-clr-red{color:var(--osl-error-color)}.hint{color:var(--osl-error-color);margin-top:2px;font-size:var(--osl-hint-font-size)}.input-wrapper{position:relative;display:flex;align-items:center}.dt-toggle{position:absolute;right:2px;top:50%;transform:translateY(-50%);display:flex;align-items:center}.dt-toggle ::ng-deep .mat-mdc-icon-button{width:32px;height:32px;padding:4px;color:#666}.dt-toggle ::ng-deep .mat-mdc-icon-button:hover:not([disabled]){color:var(--osl-focus-border-color)}.dt-toggle ::ng-deep .mat-mdc-icon-button[disabled]{opacity:.4;cursor:not-allowed}.dt-input{height:var(--osl-control-height);width:100%;border-radius:var(--osl-border-radius);outline:none;border:1px solid var(--osl-border-color);padding:0 38px 0 10px;font-size:var(--osl-text-font-size);font-family:inherit;color:#333;background-color:#fff;transition:border-color .2s,box-shadow .2s;letter-spacing:.01em;box-sizing:border-box}.dt-input::placeholder{color:#bbb}.dt-input:hover:not(:disabled){border-color:var(--osl-focus-border-color)}.dt-input:focus{border-color:var(--osl-focus-border-color);box-shadow:0 0 0 3px var(--osl-focus-shadow, rgba(99, 102, 241, .14))}.dt-input:disabled{background-color:#f5f5f5;cursor:not-allowed;opacity:.7}.dt-input.error{border-color:var(--osl-error-color)}.dt-input.error:focus{box-shadow:0 0 0 3px var(--osl-error-shadow, rgba(220, 38, 38, .14))}\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.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: "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: i4.NgxMatDatetimepicker, selector: "ngx-mat-datetime-picker", exportAs: ["ngxMatDatetimePicker"] }, { kind: "directive", type: i4.NgxMatDatepickerInput, selector: "input[ngxMatDatetimePicker]", inputs: ["ngxMatDatetimePicker", "min", "max", "matDatepickerFilter"], exportAs: ["ngxMatDatepickerInput"] }, { kind: "component", type: i4.NgxMatDatepickerToggle, selector: "ngx-mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["ngxMatDatepickerToggle"] }] });
2429
+ }
2430
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslDatetimepicker, decorators: [{
2431
+ type: Component,
2432
+ args: [{ selector: 'osl-datetimepicker', standalone: false, template: "<div class=\"d-flex flex-column\">\n @if (label) {\n <div [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\n <label class=\"label\" [class.txt-clr-red]=\"dtField.touched && dtField.invalid\">\n {{label}} <span class=\"txt-clr-red\">{{required ? '*' : ''}}</span>\n </label>\n </div>\n }\n <div class=\"input-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\n <input\n class=\"dt-input\"\n [ngxMatDatetimePicker]=\"picker\"\n [ngModel]=\"dateModel\"\n (ngModelChange)=\"onDateChange($event)\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [min]=\"minDate\"\n [max]=\"maxDate\"\n [placeholder]=\"placeholder\"\n [class.error]=\"dtField.touched && dtField.invalid\"\n #dtField=\"ngModel\"\n />\n <ngx-mat-datepicker-toggle\n [for]=\"picker\"\n [disabled]=\"disabled\"\n class=\"dt-toggle\">\n </ngx-mat-datepicker-toggle>\n <ngx-mat-datetime-picker\n #picker\n [showSpinners]=\"true\"\n [showSeconds]=\"showSeconds\"\n [enableMeridian]=\"enableMeridian\">\n </ngx-mat-datetime-picker>\n </div>\n @if (dtField.touched && dtField.invalid && required) {\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\n }\n</div>\n", styles: [".label{font-size:var(--osl-label-font-size);margin-bottom:5px}.txt-clr-red{color:var(--osl-error-color)}.hint{color:var(--osl-error-color);margin-top:2px;font-size:var(--osl-hint-font-size)}.input-wrapper{position:relative;display:flex;align-items:center}.dt-toggle{position:absolute;right:2px;top:50%;transform:translateY(-50%);display:flex;align-items:center}.dt-toggle ::ng-deep .mat-mdc-icon-button{width:32px;height:32px;padding:4px;color:#666}.dt-toggle ::ng-deep .mat-mdc-icon-button:hover:not([disabled]){color:var(--osl-focus-border-color)}.dt-toggle ::ng-deep .mat-mdc-icon-button[disabled]{opacity:.4;cursor:not-allowed}.dt-input{height:var(--osl-control-height);width:100%;border-radius:var(--osl-border-radius);outline:none;border:1px solid var(--osl-border-color);padding:0 38px 0 10px;font-size:var(--osl-text-font-size);font-family:inherit;color:#333;background-color:#fff;transition:border-color .2s,box-shadow .2s;letter-spacing:.01em;box-sizing:border-box}.dt-input::placeholder{color:#bbb}.dt-input:hover:not(:disabled){border-color:var(--osl-focus-border-color)}.dt-input:focus{border-color:var(--osl-focus-border-color);box-shadow:0 0 0 3px var(--osl-focus-shadow, rgba(99, 102, 241, .14))}.dt-input:disabled{background-color:#f5f5f5;cursor:not-allowed;opacity:.7}.dt-input.error{border-color:var(--osl-error-color)}.dt-input.error:focus{box-shadow:0 0 0 3px var(--osl-error-shadow, rgba(220, 38, 38, .14))}\n"] }]
2433
+ }], propDecorators: { label: [{
2434
+ type: Input,
2435
+ args: ['label']
2436
+ }], required: [{
2437
+ type: Input,
2438
+ args: ['required']
2439
+ }], disabled: [{
2440
+ type: Input,
2441
+ args: ['disabled']
2442
+ }], model: [{
2443
+ type: Input,
2444
+ args: ['model']
2445
+ }], placeholder: [{
2446
+ type: Input,
2447
+ args: ['placeholder']
2448
+ }], minDatetime: [{
2449
+ type: Input,
2450
+ args: ['minDatetime']
2451
+ }], maxDatetime: [{
2452
+ type: Input,
2453
+ args: ['maxDatetime']
2454
+ }], format: [{
2455
+ type: Input,
2456
+ args: ['format']
2457
+ }], showSeconds: [{
2458
+ type: Input,
2459
+ args: ['showSeconds']
2460
+ }], enableMeridian: [{
2461
+ type: Input,
2462
+ args: ['enableMeridian']
2463
+ }], skeletonLoading: [{
2464
+ type: Input,
2465
+ args: ['skeletonLoading']
2466
+ }], skeletonTheme: [{
2467
+ type: Input,
2468
+ args: ['skeletonTheme']
2469
+ }], modelChange: [{
2470
+ type: Output
2471
+ }], changeEv: [{
2472
+ type: Output
2473
+ }] } });
2474
+
2475
+ class OslCheckbox {
2476
+ checkboxEl;
2477
+ label = '';
2478
+ disabled = false;
2479
+ required = false;
2480
+ model = false;
2481
+ indeterminate = false;
2482
+ skeletonLoading = false;
2483
+ skeletonTheme = 'light';
2484
+ modelChange = new EventEmitter();
2485
+ changeEv = new EventEmitter();
2486
+ touched = false;
2487
+ get isInvalid() {
2488
+ return this.touched && this.required && !this.model;
2489
+ }
2490
+ ngOnChanges(changes) {
2491
+ if (changes['indeterminate'] && this.checkboxEl) {
2492
+ this.checkboxEl.nativeElement.indeterminate = this.indeterminate;
2493
+ }
2494
+ }
2495
+ ngAfterViewInit() {
2496
+ if (this.checkboxEl) {
2497
+ this.checkboxEl.nativeElement.indeterminate = this.indeterminate;
2498
+ }
2499
+ }
2500
+ onModelChange(event) {
2501
+ this.touched = true;
2502
+ this.model = event;
2503
+ this.modelChange.emit(this.model);
2504
+ this.changeEv.emit(this.model);
2505
+ }
2506
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
2507
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslCheckbox, isStandalone: false, selector: "osl-checkbox", inputs: { label: "label", disabled: "disabled", required: "required", model: "model", indeterminate: "indeterminate", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme" }, outputs: { modelChange: "modelChange", changeEv: "changeEv" }, viewQueries: [{ propertyName: "checkboxEl", first: true, predicate: ["checkboxEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"d-flex flex-column\">\r\n\r\n <label class=\"checkbox-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.checkbox-disabled]=\"disabled\" [class.checkbox-invalid]=\"isInvalid\">\r\n <input\r\n #checkboxEl\r\n type=\"checkbox\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n [disabled]=\"disabled\"\r\n >\r\n <span class=\"checkbox-label\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n {{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span>\r\n </span>\r\n </label>\r\n @if(isInvalid) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n }\r\n</div>\r\n", styles: [".checkbox-wrapper{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:var(--osl-label-font-size);width:fit-content}.checkbox-wrapper input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:#333;flex-shrink:0}.checkbox-wrapper .checkbox-label{-webkit-user-select:none;user-select:none}.checkbox-wrapper.checkbox-disabled{opacity:.6;cursor:not-allowed}.checkbox-wrapper.checkbox-disabled input[type=checkbox]{cursor:not-allowed}.checkbox-wrapper.checkbox-invalid{color:var(--osl-error-color)}.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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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: "directive", type: i2$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { 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"] }] });
2508
+ }
2509
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslCheckbox, decorators: [{
2510
+ type: Component,
2511
+ args: [{ selector: 'osl-checkbox', standalone: false, template: "<div class=\"d-flex flex-column\">\r\n\r\n <label class=\"checkbox-wrapper\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\" [class.checkbox-disabled]=\"disabled\" [class.checkbox-invalid]=\"isInvalid\">\r\n <input\r\n #checkboxEl\r\n type=\"checkbox\"\r\n [ngModel]=\"model\"\r\n (ngModelChange)=\"onModelChange($event)\"\r\n [disabled]=\"disabled\"\r\n >\r\n <span class=\"checkbox-label\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\r\n {{label}} <span class=\"txt-clr-red\">{{required?'*':''}}</span>\r\n </span>\r\n </label>\r\n @if(isInvalid) {\r\n <mat-hint class=\"hint\">{{label}} is Required!</mat-hint>\r\n }\r\n</div>\r\n", styles: [".checkbox-wrapper{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:var(--osl-label-font-size);width:fit-content}.checkbox-wrapper input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:#333;flex-shrink:0}.checkbox-wrapper .checkbox-label{-webkit-user-select:none;user-select:none}.checkbox-wrapper.checkbox-disabled{opacity:.6;cursor:not-allowed}.checkbox-wrapper.checkbox-disabled input[type=checkbox]{cursor:not-allowed}.checkbox-wrapper.checkbox-invalid{color:var(--osl-error-color)}.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"] }]
2512
+ }], propDecorators: { checkboxEl: [{
2513
+ type: ViewChild,
2514
+ args: ['checkboxEl']
2515
+ }], label: [{
2516
+ type: Input,
2517
+ args: ['label']
2518
+ }], disabled: [{
2519
+ type: Input,
2520
+ args: ['disabled']
2521
+ }], required: [{
2522
+ type: Input,
2523
+ args: ['required']
2524
+ }], model: [{
2525
+ type: Input,
2526
+ args: ['model']
2527
+ }], indeterminate: [{
2528
+ type: Input,
2529
+ args: ['indeterminate']
2530
+ }], skeletonLoading: [{
2531
+ type: Input,
2532
+ args: ['skeletonLoading']
2533
+ }], skeletonTheme: [{
2534
+ type: Input,
2535
+ args: ['skeletonTheme']
2536
+ }], modelChange: [{
2537
+ type: Output
2538
+ }], changeEv: [{
2539
+ type: Output
2540
+ }] } });
2541
+
2542
+ class OslButton {
2543
+ label = 'Button';
2544
+ icon = '';
2545
+ variant = 'primary';
2546
+ size = 'md';
2547
+ disabled = false;
2548
+ loading = false;
2549
+ type = 'button';
2550
+ fullWidth = false;
2551
+ clickEv = new EventEmitter();
2552
+ get classes() {
2553
+ return [
2554
+ 'osl-btn',
2555
+ `osl-btn--${this.variant}`,
2556
+ `osl-btn--${this.size}`,
2557
+ this.fullWidth ? 'osl-btn--full' : '',
2558
+ ]
2559
+ .filter(Boolean)
2560
+ .join(' ');
2561
+ }
2562
+ onClick() {
2563
+ if (!this.disabled && !this.loading) {
2564
+ this.clickEv.emit();
2565
+ }
2566
+ }
2567
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2568
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslButton, isStandalone: false, selector: "osl-button", inputs: { label: "label", icon: "icon", variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type", fullWidth: "fullWidth" }, outputs: { clickEv: "clickEv" }, ngImport: i0, template: "@if (variant == 'icon' && icon) {\r\n <button class=\"icon-btn\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n } @else {\r\n <mat-icon>{{ icon }}</mat-icon>\r\n }\r\n </button>\r\n} @else {\r\n <button [class]=\"classes\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n }\r\n <span class=\"osl-btn__label\">{{ label }}</span>\r\n @if (icon) {\r\n <span class=\"osl-btn__label-icon\"\r\n ><mat-icon>{{ icon }}</mat-icon></span\r\n >\r\n }\r\n </button>\r\n}\r\n", styles: ["@charset \"UTF-8\";.osl-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border:none;border-radius:var(--osl-border-radius);cursor:pointer;font-size:var(--osl-label-font-size);font-weight:500;line-height:1;transition:background-color .2s ease,border-color .2s ease,opacity .2s ease;white-space:nowrap;outline:none}.osl-btn--sm{height:28px;padding:0 var(--osl-hint-font-size);font-size:var(--osl-hint-font-size)}.osl-btn--sm mat-icon{font-size:var(--osl-hint-font-size)}.osl-btn--md{height:36px;padding:0 18px;font-size:var(--osl-label-font-size)}.osl-btn--lg{height:44px;padding:0 24px;font-size:16px}.osl-btn--full{width:100%}.osl-btn:disabled{opacity:var(--osl-disabled-opacity);cursor:not-allowed}.osl-btn--primary{background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--primary:hover:not(:disabled){background-color:var(--osl-primary-hover)}.osl-btn--secondary{background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--secondary:hover:not(:disabled){background-color:var(--osl-secondary-hover)}.osl-btn--success{background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--success:hover:not(:disabled){background-color:var(--osl-success-hover)}.osl-btn--danger{background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--danger:hover:not(:disabled){background-color:var(--osl-danger-hover)}.osl-btn--warning{background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--warning:hover:not(:disabled){background-color:var(--osl-warning-hover)}.osl-btn--info{background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn--info:hover:not(:disabled){background-color:var(--osl-info-hover)}.osl-btn--outline-primary{background-color:transparent;border:1.5px solid var(--osl-primary);color:var(--osl-primary)}.osl-btn--outline-primary:hover:not(:disabled){background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--outline-secondary{background-color:transparent;border:1.5px solid var(--osl-secondary);color:var(--osl-secondary)}.osl-btn--outline-secondary:hover:not(:disabled){background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--outline-success{background-color:transparent;border:1.5px solid var(--osl-success);color:var(--osl-success)}.osl-btn--outline-success:hover:not(:disabled){background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--outline-danger{background-color:transparent;border:1.5px solid var(--osl-danger);color:var(--osl-danger)}.osl-btn--outline-danger:hover:not(:disabled){background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--outline-warning{background-color:transparent;border:1.5px solid var(--osl-warning);color:var(--osl-warning)}.osl-btn--outline-warning:hover:not(:disabled){background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--outline-info{background-color:transparent;border:1.5px solid var(--osl-info);color:var(--osl-info)}.osl-btn--outline-info:hover:not(:disabled){background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn__spinner{display:inline-block;width:var(--osl-label-font-size);height:var(--osl-label-font-size);border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:osl-spin .7s linear infinite}@keyframes osl-spin{to{transform:rotate(360deg)}}.osl-btn__label-icon{color:var(--color-white)}.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}.icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"], dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
2569
+ }
2570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslButton, decorators: [{
2571
+ type: Component,
2572
+ args: [{ selector: 'osl-button', standalone: false, template: "@if (variant == 'icon' && icon) {\r\n <button class=\"icon-btn\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n } @else {\r\n <mat-icon>{{ icon }}</mat-icon>\r\n }\r\n </button>\r\n} @else {\r\n <button [class]=\"classes\" [type]=\"type\" [disabled]=\"disabled || loading\" (click)=\"onClick()\">\r\n @if (loading) {\r\n <span class=\"osl-btn__spinner\"></span>\r\n }\r\n <span class=\"osl-btn__label\">{{ label }}</span>\r\n @if (icon) {\r\n <span class=\"osl-btn__label-icon\"\r\n ><mat-icon>{{ icon }}</mat-icon></span\r\n >\r\n }\r\n </button>\r\n}\r\n", styles: ["@charset \"UTF-8\";.osl-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border:none;border-radius:var(--osl-border-radius);cursor:pointer;font-size:var(--osl-label-font-size);font-weight:500;line-height:1;transition:background-color .2s ease,border-color .2s ease,opacity .2s ease;white-space:nowrap;outline:none}.osl-btn--sm{height:28px;padding:0 var(--osl-hint-font-size);font-size:var(--osl-hint-font-size)}.osl-btn--sm mat-icon{font-size:var(--osl-hint-font-size)}.osl-btn--md{height:36px;padding:0 18px;font-size:var(--osl-label-font-size)}.osl-btn--lg{height:44px;padding:0 24px;font-size:16px}.osl-btn--full{width:100%}.osl-btn:disabled{opacity:var(--osl-disabled-opacity);cursor:not-allowed}.osl-btn--primary{background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--primary:hover:not(:disabled){background-color:var(--osl-primary-hover)}.osl-btn--secondary{background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--secondary:hover:not(:disabled){background-color:var(--osl-secondary-hover)}.osl-btn--success{background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--success:hover:not(:disabled){background-color:var(--osl-success-hover)}.osl-btn--danger{background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--danger:hover:not(:disabled){background-color:var(--osl-danger-hover)}.osl-btn--warning{background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--warning:hover:not(:disabled){background-color:var(--osl-warning-hover)}.osl-btn--info{background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn--info:hover:not(:disabled){background-color:var(--osl-info-hover)}.osl-btn--outline-primary{background-color:transparent;border:1.5px solid var(--osl-primary);color:var(--osl-primary)}.osl-btn--outline-primary:hover:not(:disabled){background-color:var(--osl-primary);color:var(--osl-primary-text)}.osl-btn--outline-secondary{background-color:transparent;border:1.5px solid var(--osl-secondary);color:var(--osl-secondary)}.osl-btn--outline-secondary:hover:not(:disabled){background-color:var(--osl-secondary);color:var(--osl-secondary-text)}.osl-btn--outline-success{background-color:transparent;border:1.5px solid var(--osl-success);color:var(--osl-success)}.osl-btn--outline-success:hover:not(:disabled){background-color:var(--osl-success);color:var(--osl-success-text)}.osl-btn--outline-danger{background-color:transparent;border:1.5px solid var(--osl-danger);color:var(--osl-danger)}.osl-btn--outline-danger:hover:not(:disabled){background-color:var(--osl-danger);color:var(--osl-danger-text)}.osl-btn--outline-warning{background-color:transparent;border:1.5px solid var(--osl-warning);color:var(--osl-warning)}.osl-btn--outline-warning:hover:not(:disabled){background-color:var(--osl-warning);color:var(--osl-warning-text)}.osl-btn--outline-info{background-color:transparent;border:1.5px solid var(--osl-info);color:var(--osl-info)}.osl-btn--outline-info:hover:not(:disabled){background-color:var(--osl-info);color:var(--osl-info-text)}.osl-btn__spinner{display:inline-block;width:var(--osl-label-font-size);height:var(--osl-label-font-size);border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:osl-spin .7s linear infinite}@keyframes osl-spin{to{transform:rotate(360deg)}}.osl-btn__label-icon{color:var(--color-white)}.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}.icon-btn mat-icon{font-size:16px;width:16px;height:16px;line-height:16px}.icon-btn:hover{border-color:var(--osl-primary);color:var(--osl-primary);background:#6366f10f}.icon-btn--danger:hover{border-color:#ef4444;color:#ef4444;background:#ef44440f}\n"] }]
2573
+ }], propDecorators: { label: [{
2574
+ type: Input,
2575
+ args: ['label']
2576
+ }], icon: [{
2577
+ type: Input,
2578
+ args: ['icon']
2579
+ }], variant: [{
2580
+ type: Input,
2581
+ args: ['variant']
2582
+ }], size: [{
2583
+ type: Input,
2584
+ args: ['size']
2585
+ }], disabled: [{
2586
+ type: Input,
2587
+ args: ['disabled']
2588
+ }], loading: [{
2589
+ type: Input,
2590
+ args: ['loading']
2591
+ }], type: [{
2592
+ type: Input,
2593
+ args: ['type']
2594
+ }], fullWidth: [{
2595
+ type: Input,
2596
+ args: ['fullWidth']
2597
+ }], clickEv: [{
2598
+ type: Output
2599
+ }] } });
2600
+
2601
+ class DynamicForm {
2602
+ cdr;
2603
+ elements = [];
2604
+ _model;
2605
+ set model(val) {
2606
+ this._model = val;
2607
+ }
2608
+ get model() {
2609
+ return this._model;
2610
+ }
2611
+ skeletonLoading = false;
2612
+ skeletonTheme = 'light';
2613
+ modelChange = new EventEmitter();
2614
+ datasourceCache = inject(DatasourceCacheService);
2615
+ constructor(cdr) {
2616
+ this.cdr = cdr;
2617
+ }
2618
+ ngOnInit() {
2619
+ this.loadApiDatasources();
2620
+ }
2621
+ ngOnChanges(changes) {
2622
+ if (changes['elements']) {
2623
+ this.loadApiDatasources();
2624
+ }
2625
+ }
2626
+ loadApiDatasources() {
2627
+ this._loadForList(this.elements);
2628
+ }
2629
+ async _loadForList(list) {
2630
+ for (const elem of list) {
2631
+ if (elem.elementType === 'fieldset' && elem.rows?.length) {
2632
+ this._loadForList(elem.rows);
2633
+ }
2634
+ else if (elem.apiService && elem.apiMethod && (!elem.searchType || elem.searchType == 'Local')) {
2635
+ elem.loadingIf = () => true;
2636
+ const data = await this.datasourceCache.load(elem.apiService, elem.apiMethod, elem.apiBody ? elem.apiBody(this.model) : null);
2637
+ elem.loadingIf = () => false;
2638
+ this.cdr.markForCheck();
2639
+ if (data && data.length > 0) {
2640
+ elem.datasource = data;
2641
+ }
2642
+ }
2643
+ }
2644
+ }
2645
+ onModelChange(event, key) {
2646
+ this.model[key] = event;
2647
+ this.modelChange.emit(this.model);
2648
+ }
2649
+ onSelectChange(elem, value) {
2650
+ if (!elem.change)
2651
+ return;
2652
+ let selectedObj = undefined;
2653
+ if (elem.datasource) {
2654
+ if (Array.isArray(value)) {
2655
+ selectedObj = value.map(v => elem.datasource.find(item => (elem.valueField ? item[elem.valueField] : item) === v) ?? null);
2656
+ }
2657
+ else if (value !== null && value !== undefined) {
2658
+ selectedObj = elem.datasource.find(item => (elem.valueField ? item[elem.valueField] : item) === (isNaN(Number(value)) ? value : Number(value))) ?? null;
2659
+ }
2660
+ else {
2661
+ selectedObj = null;
2662
+ }
2663
+ }
2664
+ elem.change(this.model, undefined, selectedObj);
2665
+ }
2666
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DynamicForm, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2667
+ 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 [isCapitalize]=\"elem.isCapitalize\"\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.minDateIf ? elem.minDateIf(model): elem.minDate ? elem.minDate : ''\"\r\n [maxDate]=\"elem.maxDateIf ? elem.maxDateIf(model): elem.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 (\"datetimepicker\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-datetimepicker\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 [placeholder]=\"elem.placeholder || ''\"\r\n [minDatetime]=\"elem.minDatetimeIf ? elem.minDatetimeIf(model) : elem.minDatetime || ''\"\r\n [maxDatetime]=\"elem.maxDatetimeIf ? elem.maxDatetimeIf(model) : elem.maxDatetime || ''\"\r\n [format]=\"elem.datetimepickerFormat || 'YYYY-MM-DDTHH:mm'\"\r\n [showSeconds]=\"!!elem.datetimepickerShowSeconds\"\r\n [enableMeridian]=\"!!elem.datetimepickerEnableMeridian\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-datetimepicker>\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", "isCapitalize", "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: ["datasourceChange", "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: OslDatetimepicker, selector: "osl-datetimepicker", inputs: ["label", "required", "disabled", "model", "placeholder", "minDatetime", "maxDatetime", "format", "showSeconds", "enableMeridian", "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"] }] });
2668
+ }
2669
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DynamicForm, decorators: [{
2670
+ type: Component,
2671
+ 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 [isCapitalize]=\"elem.isCapitalize\"\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.minDateIf ? elem.minDateIf(model): elem.minDate ? elem.minDate : ''\"\r\n [maxDate]=\"elem.maxDateIf ? elem.maxDateIf(model): elem.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 (\"datetimepicker\") {\r\n <div [class]=\"'col-md-'+elem.columns+' mt-2'\">\r\n <osl-datetimepicker\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 [placeholder]=\"elem.placeholder || ''\"\r\n [minDatetime]=\"elem.minDatetimeIf ? elem.minDatetimeIf(model) : elem.minDatetime || ''\"\r\n [maxDatetime]=\"elem.maxDatetimeIf ? elem.maxDatetimeIf(model) : elem.maxDatetime || ''\"\r\n [format]=\"elem.datetimepickerFormat || 'YYYY-MM-DDTHH:mm'\"\r\n [showSeconds]=\"!!elem.datetimepickerShowSeconds\"\r\n [enableMeridian]=\"!!elem.datetimepickerEnableMeridian\"\r\n (changeEv)=\"elem.change ? elem.change(model) : null\"\r\n [(model)]=\"model[elem.key]\"\r\n ></osl-datetimepicker>\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"] }]
2672
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { elements: [{
2673
+ type: Input,
2674
+ args: ['elements']
2675
+ }], model: [{
2676
+ type: Input,
2677
+ args: ['model']
2678
+ }], skeletonLoading: [{
2679
+ type: Input,
2680
+ args: ['skeletonLoading']
2681
+ }], skeletonTheme: [{
2682
+ type: Input,
2683
+ args: ['skeletonTheme']
2684
+ }], modelChange: [{
2685
+ type: Output
2686
+ }] } });
2687
+
2688
+ class OslSetupStateService {
2689
+ _map = new Map();
2690
+ save(key, state) {
2691
+ this._map.set(key, state);
2692
+ }
2693
+ consume(key) {
2694
+ const state = this._map.get(key);
2695
+ if (state)
2696
+ this._map.delete(key);
2697
+ return state;
2698
+ }
2699
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslSetupStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2700
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslSetupStateService, providedIn: 'root' });
2701
+ }
2702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslSetupStateService, decorators: [{
2703
+ type: Injectable,
2704
+ args: [{ providedIn: 'root' }]
2705
+ }] });
2706
+
2707
+ class OslSearchbar {
2708
+ label = "Type to Search...";
2709
+ onSearch = new EventEmitter();
2710
+ searchQuery = "";
2711
+ searchControl = new FormControl('');
2712
+ onKeyChange() {
2713
+ if (!this.searchQuery) {
2714
+ this.onSearch.emit(this.searchQuery);
2715
+ }
2716
+ }
2717
+ ngOnInit() {
2718
+ this.searchControl.valueChanges.pipe(debounceTime$1(300), distinctUntilChanged$1()).subscribe(value => {
2719
+ if (value) {
2337
2720
  this.onSearch.emit(value);
2338
2721
  }
2339
2722
  });
@@ -3332,11 +3715,11 @@ class OslFormGrid {
3332
3715
  elem.change(row, i, selectedObj);
3333
3716
  }
3334
3717
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslFormGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
3335
- 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\" [style.width]=\"col.width\">\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", "isCapitalize", "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: ["datasourceChange", "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"] }] });
3718
+ 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\" [style.width]=\"col.width\">\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 ('datetimepicker') {\r\n <osl-datetimepicker\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [minDatetime]=\"col.formElem.minDatetime || ''\"\r\n [maxDatetime]=\"col.formElem.maxDatetime || ''\"\r\n [format]=\"col.formElem.datetimepickerFormat || 'YYYY-MM-DDTHH:mm'\"\r\n [showSeconds]=\"!!col.formElem.datetimepickerShowSeconds\"\r\n [enableMeridian]=\"!!col.formElem.datetimepickerEnableMeridian\"\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-datetimepicker>\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", "isCapitalize", "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: ["datasourceChange", "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: OslDatetimepicker, selector: "osl-datetimepicker", inputs: ["label", "required", "disabled", "model", "placeholder", "minDatetime", "maxDatetime", "format", "showSeconds", "enableMeridian", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }, { kind: "component", type: OslCheckbox, selector: "osl-checkbox", inputs: ["label", "disabled", "required", "model", "indeterminate", "skeletonLoading", "skeletonTheme"], outputs: ["modelChange", "changeEv"] }] });
3336
3719
  }
3337
3720
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslFormGrid, decorators: [{
3338
3721
  type: Component,
3339
- 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\" [style.width]=\"col.width\">\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"] }]
3722
+ 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\" [style.width]=\"col.width\">\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 ('datetimepicker') {\r\n <osl-datetimepicker\r\n [label]=\"''\"\r\n [required]=\"false\"\r\n [disabled]=\"isDisabled(col.formElem,row,i)\"\r\n [placeholder]=\"col.formElem.placeholder || col.displayName\"\r\n [minDatetime]=\"col.formElem.minDatetime || ''\"\r\n [maxDatetime]=\"col.formElem.maxDatetime || ''\"\r\n [format]=\"col.formElem.datetimepickerFormat || 'YYYY-MM-DDTHH:mm'\"\r\n [showSeconds]=\"!!col.formElem.datetimepickerShowSeconds\"\r\n [enableMeridian]=\"!!col.formElem.datetimepickerEnableMeridian\"\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-datetimepicker>\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"] }]
3340
3723
  }], propDecorators: { columns: [{
3341
3724
  type: Input,
3342
3725
  args: ['columns']
@@ -4657,6 +5040,7 @@ class FormStructureModule {
4657
5040
  OslAutocomplete,
4658
5041
  OslFileUpload,
4659
5042
  OslDatepicker,
5043
+ OslDatetimepicker,
4660
5044
  OslCheckbox,
4661
5045
  OslButton,
4662
5046
  OslSetup,
@@ -4683,7 +5067,10 @@ class FormStructureModule {
4683
5067
  MatDatepickerModule,
4684
5068
  MatMenuModule,
4685
5069
  ScrollingModule,
4686
- DragDropModule], exports: [DynamicForm, OslSetup, OslGrid, OslFormGrid, Oslinput,
5070
+ DragDropModule,
5071
+ NgxMatDatetimepicker,
5072
+ NgxMatDatepickerInput,
5073
+ NgxMatDatepickerToggle], exports: [DynamicForm, OslSetup, OslGrid, OslFormGrid, Oslinput,
4687
5074
  Osltextarea,
4688
5075
  OslSelect,
4689
5076
  OslRadio,
@@ -4691,12 +5078,26 @@ class FormStructureModule {
4691
5078
  OslAutocomplete,
4692
5079
  OslFileUpload,
4693
5080
  OslDatepicker,
5081
+ OslDatetimepicker,
4694
5082
  OslCheckbox,
4695
5083
  OslButton,
4696
5084
  OslSetup,
4697
5085
  OslSearchbar, OslAutocompleteLister, OslReportGrid, OslReportForm] });
4698
5086
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FormStructureModule, providers: [
4699
5087
  { provide: AUTOCOMPLETE_LISTER_COMPONENT, useValue: OslAutocompleteLister },
5088
+ { provide: DateAdapter, useClass: NativeDateAdapter },
5089
+ {
5090
+ provide: MAT_DATE_FORMATS,
5091
+ useValue: {
5092
+ parse: { dateInput: null },
5093
+ display: {
5094
+ dateInput: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' },
5095
+ monthYearLabel: { year: 'numeric', month: 'short' },
5096
+ dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
5097
+ monthYearA11yLabel: { year: 'numeric', month: 'long' },
5098
+ },
5099
+ },
5100
+ },
4700
5101
  ], imports: [FormsModule,
4701
5102
  ReactiveFormsModule,
4702
5103
  MatFormFieldModule,
@@ -4708,7 +5109,9 @@ class FormStructureModule {
4708
5109
  MatDatepickerModule,
4709
5110
  MatMenuModule,
4710
5111
  ScrollingModule,
4711
- DragDropModule] });
5112
+ DragDropModule,
5113
+ NgxMatDatetimepicker,
5114
+ NgxMatDatepickerToggle] });
4712
5115
  }
4713
5116
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FormStructureModule, decorators: [{
4714
5117
  type: NgModule,
@@ -4723,6 +5126,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4723
5126
  OslAutocomplete,
4724
5127
  OslFileUpload,
4725
5128
  OslDatepicker,
5129
+ OslDatetimepicker,
4726
5130
  OslCheckbox,
4727
5131
  OslButton,
4728
5132
  OslSetup,
@@ -4753,6 +5157,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4753
5157
  MatMenuModule,
4754
5158
  ScrollingModule,
4755
5159
  DragDropModule,
5160
+ NgxMatDatetimepicker,
5161
+ NgxMatDatepickerInput,
5162
+ NgxMatDatepickerToggle,
4756
5163
  ],
4757
5164
  exports: [DynamicForm, OslSetup, OslGrid, OslFormGrid, Oslinput,
4758
5165
  Osltextarea,
@@ -4762,522 +5169,241 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
4762
5169
  OslAutocomplete,
4763
5170
  OslFileUpload,
4764
5171
  OslDatepicker,
5172
+ OslDatetimepicker,
4765
5173
  OslCheckbox,
4766
5174
  OslButton,
4767
5175
  OslSetup,
4768
5176
  OslSearchbar, OslAutocompleteLister, OslReportGrid, OslReportForm],
4769
5177
  providers: [
4770
5178
  { provide: AUTOCOMPLETE_LISTER_COMPONENT, useValue: OslAutocompleteLister },
5179
+ { provide: DateAdapter, useClass: NativeDateAdapter },
5180
+ {
5181
+ provide: MAT_DATE_FORMATS,
5182
+ useValue: {
5183
+ parse: { dateInput: null },
5184
+ display: {
5185
+ dateInput: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' },
5186
+ monthYearLabel: { year: 'numeric', month: 'short' },
5187
+ dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
5188
+ monthYearA11yLabel: { year: 'numeric', month: 'long' },
5189
+ },
5190
+ },
5191
+ },
4771
5192
  ],
4772
5193
  }]
4773
5194
  }] });
4774
-
4775
- // ─── Array Utilities ────────────────────────────────────────────────────────
4776
- /** Splits an array into chunks of the given size. */
4777
- function chunk(array, size) {
4778
- if (size <= 0)
4779
- return [];
4780
- const result = [];
4781
- for (let i = 0; i < array.length; i += size) {
4782
- result.push(array.slice(i, i + size));
4783
- }
4784
- return result;
4785
- }
4786
- /** Removes duplicate primitive values. */
4787
- function unique(array) {
4788
- return [...new Set(array)];
4789
- }
4790
- /** Removes duplicates by object key. */
4791
- function uniqueBy(array, key) {
4792
- const seen = new Set();
4793
- return array.filter(item => {
4794
- const val = item[key];
4795
- if (seen.has(val))
4796
- return false;
4797
- seen.add(val);
4798
- return true;
4799
- });
4800
- }
4801
- /** Flattens one level of nesting. */
4802
- function flatten(array) {
4803
- return array.flat();
4804
- }
4805
- /** Deeply flattens a nested array. */
4806
- function flattenDeep(array) {
4807
- return array.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : [...acc, val], []);
4808
- }
4809
- /** Groups array elements by a key. */
4810
- function groupBy(array, key) {
4811
- return array.reduce((acc, item) => {
4812
- const group = String(item[key]);
4813
- acc[group] = acc[group] ?? [];
4814
- acc[group].push(item);
4815
- return acc;
4816
- }, {});
4817
- }
4818
- /** Sorts array by key ascending or descending. */
4819
- function sortBy(array, key, direction = 'asc') {
4820
- return [...array].sort((a, b) => {
4821
- const aVal = a[key];
4822
- const bVal = b[key];
4823
- if (aVal < bVal)
4824
- return direction === 'asc' ? -1 : 1;
4825
- if (aVal > bVal)
4826
- return direction === 'asc' ? 1 : -1;
4827
- return 0;
4828
- });
4829
- }
4830
- /** Filters array where key matches value (strict equality). */
4831
- function filterBy(array, key, value) {
4832
- return array.filter(item => item[key] === value);
4833
- }
4834
- /** Sums values at the given numeric key. */
4835
- function sumBy(array, key) {
4836
- return array.reduce((acc, item) => acc + Number(item[key]), 0);
4837
- }
4838
- /** Returns the item with the minimum value at key. */
4839
- function minBy(array, key) {
4840
- if (!array.length)
4841
- return undefined;
4842
- return array.reduce((min, item) => (item[key] < min[key] ? item : min));
4843
- }
4844
- /** Returns the item with the maximum value at key. */
4845
- function maxBy(array, key) {
4846
- if (!array.length)
4847
- return undefined;
4848
- return array.reduce((max, item) => (item[key] > max[key] ? item : max));
4849
- }
4850
- /** Computes the average of an array of numbers. */
4851
- function average$1(numbers) {
4852
- if (!numbers.length)
4853
- return 0;
4854
- return numbers.reduce((a, b) => a + b, 0) / numbers.length;
4855
- }
4856
- /** Returns true if the array is null, undefined, or has no elements. */
4857
- function isEmpty$2(array) {
4858
- return !array || array.length === 0;
4859
- }
4860
- /** Returns the last element. */
4861
- function last(array) {
4862
- return array[array.length - 1];
4863
- }
4864
- /** Returns the first element. */
4865
- function first(array) {
4866
- return array[0];
4867
- }
4868
- /** Returns a slice of the array for the given page (1-based). */
4869
- function paginate(array, page, pageSize) {
4870
- const start = (page - 1) * pageSize;
4871
- return array.slice(start, start + pageSize);
4872
- }
4873
- /** Moves an element from one index to another (immutable). */
4874
- function move(array, fromIndex, toIndex) {
4875
- const result = [...array];
4876
- const [item] = result.splice(fromIndex, 1);
4877
- result.splice(toIndex, 0, item);
4878
- return result;
4879
- }
4880
- /** Adds the item if absent, removes it if present. */
4881
- function toggle(array, item) {
4882
- return array.includes(item) ? array.filter(i => i !== item) : [...array, item];
4883
- }
4884
- /** Returns elements present in both arrays. */
4885
- function intersection(a, b) {
4886
- const setB = new Set(b);
4887
- return a.filter(item => setB.has(item));
4888
- }
4889
- /** Returns elements in `a` not present in `b`. */
4890
- function difference(a, b) {
4891
- const setB = new Set(b);
4892
- return a.filter(item => !setB.has(item));
4893
- }
4894
- /** Converts an array to a lookup map keyed by the given property. */
4895
- function toMap(array, key) {
4896
- return array.reduce((acc, item) => {
4897
- acc[String(item[key])] = item;
4898
- return acc;
4899
- }, {});
4900
- }
4901
- /** Removes falsy values (null, undefined, 0, '', false). */
4902
- function compact(array) {
4903
- return array.filter(Boolean);
4904
- }
4905
- /** Returns a new randomly shuffled copy. */
4906
- function shuffle(array) {
4907
- const result = [...array];
4908
- for (let i = result.length - 1; i > 0; i--) {
4909
- const j = Math.floor(Math.random() * (i + 1));
4910
- [result[i], result[j]] = [result[j], result[i]];
5195
+
5196
+ // ─── Array Utilities ────────────────────────────────────────────────────────
5197
+ /** Splits an array into chunks of the given size. */
5198
+ function chunk(array, size) {
5199
+ if (size <= 0)
5200
+ return [];
5201
+ const result = [];
5202
+ for (let i = 0; i < array.length; i += size) {
5203
+ result.push(array.slice(i, i + size));
4911
5204
  }
4912
5205
  return result;
4913
5206
  }
4914
- function sample(array, count) {
4915
- if (count === undefined)
4916
- return array[Math.floor(Math.random() * array.length)];
4917
- return shuffle(array).slice(0, count);
5207
+ /** Removes duplicate primitive values. */
5208
+ function unique(array) {
5209
+ return [...new Set(array)];
4918
5210
  }
4919
- /** Counts occurrences of each value at the given key. */
4920
- function countBy(array, key) {
5211
+ /** Removes duplicates by object key. */
5212
+ function uniqueBy(array, key) {
5213
+ const seen = new Set();
5214
+ return array.filter(item => {
5215
+ const val = item[key];
5216
+ if (seen.has(val))
5217
+ return false;
5218
+ seen.add(val);
5219
+ return true;
5220
+ });
5221
+ }
5222
+ /** Flattens one level of nesting. */
5223
+ function flatten(array) {
5224
+ return array.flat();
5225
+ }
5226
+ /** Deeply flattens a nested array. */
5227
+ function flattenDeep(array) {
5228
+ return array.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : [...acc, val], []);
5229
+ }
5230
+ /** Groups array elements by a key. */
5231
+ function groupBy(array, key) {
4921
5232
  return array.reduce((acc, item) => {
4922
5233
  const group = String(item[key]);
4923
- acc[group] = (acc[group] ?? 0) + 1;
5234
+ acc[group] = acc[group] ?? [];
5235
+ acc[group].push(item);
4924
5236
  return acc;
4925
5237
  }, {});
4926
5238
  }
4927
- /** Returns the union of two arrays (unique values from both). */
4928
- function union(a, b) {
4929
- return unique([...a, ...b]);
4930
- }
4931
- /** Zips multiple arrays into an array of tuples. */
4932
- function zip(...arrays) {
4933
- const length = Math.max(...arrays.map(a => a.length));
4934
- return Array.from({ length }, (_, i) => arrays.map(a => a[i]));
4935
- }
4936
- /** Returns true if predicate holds for all elements. */
4937
- function every(array, predicate) {
4938
- return array.every(predicate);
4939
- }
4940
- /** Returns true if predicate holds for at least one element. */
4941
- function some(array, predicate) {
4942
- return array.some(predicate);
4943
- }
4944
- /** Partitions an array into two groups based on predicate. */
4945
- function partition(array, predicate) {
4946
- const pass = [];
4947
- const fail = [];
4948
- for (const item of array) {
4949
- (predicate(item) ? pass : fail).push(item);
4950
- }
4951
- return [pass, fail];
4952
- }
4953
-
4954
- var array_util = /*#__PURE__*/Object.freeze({
4955
- __proto__: null,
4956
- average: average$1,
4957
- chunk: chunk,
4958
- compact: compact,
4959
- countBy: countBy,
4960
- difference: difference,
4961
- every: every,
4962
- filterBy: filterBy,
4963
- first: first,
4964
- flatten: flatten,
4965
- flattenDeep: flattenDeep,
4966
- groupBy: groupBy,
4967
- intersection: intersection,
4968
- isEmpty: isEmpty$2,
4969
- last: last,
4970
- maxBy: maxBy,
4971
- minBy: minBy,
4972
- move: move,
4973
- paginate: paginate,
4974
- partition: partition,
4975
- sample: sample,
4976
- shuffle: shuffle,
4977
- some: some,
4978
- sortBy: sortBy,
4979
- sumBy: sumBy,
4980
- toMap: toMap,
4981
- toggle: toggle,
4982
- union: union,
4983
- unique: unique,
4984
- uniqueBy: uniqueBy,
4985
- zip: zip
4986
- });
4987
-
4988
- // ─── Date Utilities ───────────────────────────────────────────────────────────
4989
- const MONTH_NAMES_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
4990
- const MONTH_NAMES_FULL = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
4991
- const DAY_NAMES_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
4992
- const DAY_NAMES_FULL = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
4993
- function pad(n) {
4994
- return String(n).padStart(2, '0');
4995
- }
4996
- /** Returns the current date and time. */
4997
- function now() {
4998
- return new Date();
4999
- }
5000
- /** Returns today's date with time set to midnight. */
5001
- function today() {
5002
- return startOfDay(new Date());
5003
- }
5004
- /** Returns true if the value is a valid Date object. */
5005
- function isValidDate$1(value) {
5006
- return value instanceof Date && !isNaN(value.getTime());
5007
- }
5008
- /**
5009
- * Formats a Date using a pattern string.
5010
- * Tokens: YYYY, YY, MM, M, DD, D, HH, H, mm, m, ss, s,
5011
- * MMM (short month), MMMM (full month),
5012
- * ddd (short day), dddd (full day).
5013
- */
5014
- function formatDate(date, pattern) {
5015
- const d = new Date(date);
5016
- if (!isValidDate$1(d))
5017
- return '';
5018
- const year = d.getFullYear();
5019
- const month = d.getMonth();
5020
- const day = d.getDate();
5021
- const hours = d.getHours();
5022
- const mins = d.getMinutes();
5023
- const secs = d.getSeconds();
5024
- const dayOfWeek = d.getDay();
5025
- return pattern
5026
- .replace('YYYY', String(year))
5027
- .replace('YY', String(year).slice(-2))
5028
- .replace('MMMM', MONTH_NAMES_FULL[month])
5029
- .replace('MMM', MONTH_NAMES_SHORT[month])
5030
- .replace('MM', pad(month + 1))
5031
- .replace('M', String(month + 1))
5032
- .replace('dddd', DAY_NAMES_FULL[dayOfWeek])
5033
- .replace('ddd', DAY_NAMES_SHORT[dayOfWeek])
5034
- .replace('DD', pad(day))
5035
- .replace('D', String(day))
5036
- .replace('HH', pad(hours))
5037
- .replace('H', String(hours))
5038
- .replace('mm', pad(mins))
5039
- .replace('m', String(mins))
5040
- .replace('ss', pad(secs))
5041
- .replace('s', String(secs));
5042
- }
5043
- /** Returns date as `YYYY-MM-DD`. */
5044
- function toDateOnly(date) {
5045
- return formatDate(date, 'YYYY-MM-DD');
5046
- }
5047
- /** Returns the ISO 8601 string for a date. */
5048
- function toISOString(date) {
5049
- return date.toISOString();
5050
- }
5051
- /** Returns a new date with `days` added. */
5052
- function addDays(date, days) {
5053
- const result = new Date(date);
5054
- result.setDate(result.getDate() + days);
5055
- return result;
5056
- }
5057
- /** Returns a new date with `months` added. */
5058
- function addMonths(date, months) {
5059
- const result = new Date(date);
5060
- result.setMonth(result.getMonth() + months);
5061
- return result;
5062
- }
5063
- /** Returns a new date with `years` added. */
5064
- function addYears(date, years) {
5065
- const result = new Date(date);
5066
- result.setFullYear(result.getFullYear() + years);
5067
- return result;
5068
- }
5069
- /** Returns a new date with `hours` added. */
5070
- function addHours(date, hours) {
5071
- return new Date(date.getTime() + hours * 3_600_000);
5072
- }
5073
- /** Returns a new date with `minutes` added. */
5074
- function addMinutes(date, minutes) {
5075
- return new Date(date.getTime() + minutes * 60_000);
5076
- }
5077
- /** Returns a new date with `days` subtracted. */
5078
- function subtractDays(date, days) {
5079
- return addDays(date, -days);
5080
- }
5081
- /** Returns a new date with `months` subtracted. */
5082
- function subtractMonths(date, months) {
5083
- return addMonths(date, -months);
5084
- }
5085
- /** Returns a new date with `years` subtracted. */
5086
- function subtractYears(date, years) {
5087
- return addYears(date, -years);
5088
- }
5089
- /** Returns the absolute difference in whole days between two dates. */
5090
- function diffInDays(date1, date2) {
5091
- return Math.abs(Math.floor((date1.getTime() - date2.getTime()) / 86_400_000));
5092
- }
5093
- /** Returns the absolute difference in whole months between two dates. */
5094
- function diffInMonths(date1, date2) {
5095
- return Math.abs((date1.getFullYear() - date2.getFullYear()) * 12 +
5096
- (date1.getMonth() - date2.getMonth()));
5097
- }
5098
- /** Returns the absolute difference in whole years between two dates. */
5099
- function diffInYears(date1, date2) {
5100
- return Math.abs(date1.getFullYear() - date2.getFullYear());
5239
+ /** Sorts array by key ascending or descending. */
5240
+ function sortBy(array, key, direction = 'asc') {
5241
+ return [...array].sort((a, b) => {
5242
+ const aVal = a[key];
5243
+ const bVal = b[key];
5244
+ if (aVal < bVal)
5245
+ return direction === 'asc' ? -1 : 1;
5246
+ if (aVal > bVal)
5247
+ return direction === 'asc' ? 1 : -1;
5248
+ return 0;
5249
+ });
5101
5250
  }
5102
- /** Returns the difference in minutes between two dates (date1 - date2). */
5103
- function diffInMinutes(date1, date2) {
5104
- return Math.floor((date1.getTime() - date2.getTime()) / 60_000);
5251
+ /** Filters array where key matches value (strict equality). */
5252
+ function filterBy(array, key, value) {
5253
+ return array.filter(item => item[key] === value);
5105
5254
  }
5106
- /** Returns true if date1 is strictly before date2. */
5107
- function isBefore(date1, date2) {
5108
- return date1.getTime() < date2.getTime();
5255
+ /** Sums values at the given numeric key. */
5256
+ function sumBy(array, key) {
5257
+ return array.reduce((acc, item) => acc + Number(item[key]), 0);
5109
5258
  }
5110
- /** Returns true if date1 is strictly after date2. */
5111
- function isAfter(date1, date2) {
5112
- return date1.getTime() > date2.getTime();
5259
+ /** Returns the item with the minimum value at key. */
5260
+ function minBy(array, key) {
5261
+ if (!array.length)
5262
+ return undefined;
5263
+ return array.reduce((min, item) => (item[key] < min[key] ? item : min));
5113
5264
  }
5114
- /** Returns true if both dates fall on the same calendar day. */
5115
- function isSameDay(date1, date2) {
5116
- return (date1.getFullYear() === date2.getFullYear() &&
5117
- date1.getMonth() === date2.getMonth() &&
5118
- date1.getDate() === date2.getDate());
5265
+ /** Returns the item with the maximum value at key. */
5266
+ function maxBy(array, key) {
5267
+ if (!array.length)
5268
+ return undefined;
5269
+ return array.reduce((max, item) => (item[key] > max[key] ? item : max));
5119
5270
  }
5120
- /** Returns true if the date falls on a Saturday or Sunday. */
5121
- function isWeekend(date) {
5122
- return date.getDay() === 0 || date.getDay() === 6;
5271
+ /** Computes the average of an array of numbers. */
5272
+ function average$1(numbers) {
5273
+ if (!numbers.length)
5274
+ return 0;
5275
+ return numbers.reduce((a, b) => a + b, 0) / numbers.length;
5123
5276
  }
5124
- /** Returns true if the date is today. */
5125
- function isToday(date) {
5126
- return isSameDay(date, new Date());
5277
+ /** Returns true if the array is null, undefined, or has no elements. */
5278
+ function isEmpty$2(array) {
5279
+ return !array || array.length === 0;
5127
5280
  }
5128
- /** Returns true if the date falls in the past (before now). */
5129
- function isPast(date) {
5130
- return date.getTime() < Date.now();
5281
+ /** Returns the last element. */
5282
+ function last(array) {
5283
+ return array[array.length - 1];
5131
5284
  }
5132
- /** Returns true if the date falls in the future (after now). */
5133
- function isFuture(date) {
5134
- return date.getTime() > Date.now();
5285
+ /** Returns the first element. */
5286
+ function first(array) {
5287
+ return array[0];
5135
5288
  }
5136
- /** Returns the date with time set to 00:00:00.000. */
5137
- function startOfDay(date) {
5138
- const result = new Date(date);
5139
- result.setHours(0, 0, 0, 0);
5140
- return result;
5289
+ /** Returns a slice of the array for the given page (1-based). */
5290
+ function paginate(array, page, pageSize) {
5291
+ const start = (page - 1) * pageSize;
5292
+ return array.slice(start, start + pageSize);
5141
5293
  }
5142
- /** Returns the date with time set to 23:59:59.999. */
5143
- function endOfDay(date) {
5144
- const result = new Date(date);
5145
- result.setHours(23, 59, 59, 999);
5294
+ /** Moves an element from one index to another (immutable). */
5295
+ function move(array, fromIndex, toIndex) {
5296
+ const result = [...array];
5297
+ const [item] = result.splice(fromIndex, 1);
5298
+ result.splice(toIndex, 0, item);
5146
5299
  return result;
5147
5300
  }
5148
- /** Returns the first day of the month (time 00:00:00.000). */
5149
- function startOfMonth(date) {
5150
- return new Date(date.getFullYear(), date.getMonth(), 1);
5301
+ /** Adds the item if absent, removes it if present. */
5302
+ function toggle(array, item) {
5303
+ return array.includes(item) ? array.filter(i => i !== item) : [...array, item];
5151
5304
  }
5152
- /** Returns the last day of the month (time 23:59:59.999). */
5153
- function endOfMonth(date) {
5154
- const result = new Date(date.getFullYear(), date.getMonth() + 1, 0);
5155
- result.setHours(23, 59, 59, 999);
5156
- return result;
5305
+ /** Returns elements present in both arrays. */
5306
+ function intersection(a, b) {
5307
+ const setB = new Set(b);
5308
+ return a.filter(item => setB.has(item));
5157
5309
  }
5158
- /** Returns the first day of the year (Jan 1, 00:00:00.000). */
5159
- function startOfYear(date) {
5160
- return new Date(date.getFullYear(), 0, 1);
5310
+ /** Returns elements in `a` not present in `b`. */
5311
+ function difference(a, b) {
5312
+ const setB = new Set(b);
5313
+ return a.filter(item => !setB.has(item));
5161
5314
  }
5162
- /** Returns the last day of the year (Dec 31, 23:59:59.999). */
5163
- function endOfYear(date) {
5164
- const result = new Date(date.getFullYear(), 11, 31);
5165
- result.setHours(23, 59, 59, 999);
5166
- return result;
5315
+ /** Converts an array to a lookup map keyed by the given property. */
5316
+ function toMap(array, key) {
5317
+ return array.reduce((acc, item) => {
5318
+ acc[String(item[key])] = item;
5319
+ return acc;
5320
+ }, {});
5167
5321
  }
5168
- /** Calculates the age in years from a birth date. */
5169
- function getAge(birthDate) {
5170
- const n = new Date();
5171
- let age = n.getFullYear() - birthDate.getFullYear();
5172
- const monthDiff = n.getMonth() - birthDate.getMonth();
5173
- if (monthDiff < 0 || (monthDiff === 0 && n.getDate() < birthDate.getDate()))
5174
- age--;
5175
- return age;
5322
+ /** Removes falsy values (null, undefined, 0, '', false). */
5323
+ function compact(array) {
5324
+ return array.filter(Boolean);
5176
5325
  }
5177
- /** Returns the number of days in a given month (0-based month). */
5178
- function daysInMonth(year, month) {
5179
- return new Date(year, month + 1, 0).getDate();
5326
+ /** Returns a new randomly shuffled copy. */
5327
+ function shuffle(array) {
5328
+ const result = [...array];
5329
+ for (let i = result.length - 1; i > 0; i--) {
5330
+ const j = Math.floor(Math.random() * (i + 1));
5331
+ [result[i], result[j]] = [result[j], result[i]];
5332
+ }
5333
+ return result;
5180
5334
  }
5181
- /** Returns true if the given year is a leap year. */
5182
- function isLeapYear(year) {
5183
- return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
5335
+ function sample(array, count) {
5336
+ if (count === undefined)
5337
+ return array[Math.floor(Math.random() * array.length)];
5338
+ return shuffle(array).slice(0, count);
5184
5339
  }
5185
- /**
5186
- * Returns a human-friendly relative time string.
5187
- * @example timeAgo(new Date(Date.now() - 3600_000)) '1 hour ago'
5188
- */
5189
- function timeAgo(date) {
5190
- const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
5191
- const abs = Math.abs(seconds);
5192
- const future = seconds < 0;
5193
- const intervals = [
5194
- [31_536_000, 'year'],
5195
- [2_592_000, 'month'],
5196
- [604_800, 'week'],
5197
- [86_400, 'day'],
5198
- [3_600, 'hour'],
5199
- [60, 'minute'],
5200
- [1, 'second'],
5201
- ];
5202
- for (const [secs, label] of intervals) {
5203
- const count = Math.floor(abs / secs);
5204
- if (count >= 1) {
5205
- const unit = count === 1 ? label : `${label}s`;
5206
- return future ? `in ${count} ${unit}` : `${count} ${unit} ago`;
5207
- }
5208
- }
5209
- return 'just now';
5340
+ /** Counts occurrences of each value at the given key. */
5341
+ function countBy(array, key) {
5342
+ return array.reduce((acc, item) => {
5343
+ const group = String(item[key]);
5344
+ acc[group] = (acc[group] ?? 0) + 1;
5345
+ return acc;
5346
+ }, {});
5210
5347
  }
5211
- /** Returns the ISO week number (1–53) for the given date. */
5212
- function getWeekNumber(date) {
5213
- const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
5214
- d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
5215
- const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
5216
- return Math.ceil((((d.getTime() - yearStart.getTime()) / 86_400_000) + 1) / 7);
5348
+ /** Returns the union of two arrays (unique values from both). */
5349
+ function union(a, b) {
5350
+ return unique([...a, ...b]);
5217
5351
  }
5218
- /** Returns the next weekday (Mon–Fri) after the given date. */
5219
- function nextWorkday(date) {
5220
- const result = addDays(date, 1);
5221
- while (isWeekend(result)) {
5222
- result.setDate(result.getDate() + 1);
5223
- }
5224
- return result;
5352
+ /** Zips multiple arrays into an array of tuples. */
5353
+ function zip(...arrays) {
5354
+ const length = Math.max(...arrays.map(a => a.length));
5355
+ return Array.from({ length }, (_, i) => arrays.map(a => a[i]));
5225
5356
  }
5226
- /** Returns true if a date falls within the range [start, end] (inclusive). */
5227
- function inRange$2(date, start, end) {
5228
- return date >= start && date <= end;
5357
+ /** Returns true if predicate holds for all elements. */
5358
+ function every(array, predicate) {
5359
+ return array.every(predicate);
5229
5360
  }
5230
- /** Parses a `YYYY-MM-DD` string and returns a local-midnight Date or null. */
5231
- function parseDate(dateStr) {
5232
- const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateStr);
5233
- if (!match)
5234
- return null;
5235
- const [, y, mo, d] = match.map(Number);
5236
- const result = new Date(y, mo - 1, d);
5237
- return isValidDate$1(result) ? result : null;
5361
+ /** Returns true if predicate holds for at least one element. */
5362
+ function some(array, predicate) {
5363
+ return array.some(predicate);
5364
+ }
5365
+ /** Partitions an array into two groups based on predicate. */
5366
+ function partition(array, predicate) {
5367
+ const pass = [];
5368
+ const fail = [];
5369
+ for (const item of array) {
5370
+ (predicate(item) ? pass : fail).push(item);
5371
+ }
5372
+ return [pass, fail];
5238
5373
  }
5239
5374
 
5240
- var date_util = /*#__PURE__*/Object.freeze({
5375
+ var array_util = /*#__PURE__*/Object.freeze({
5241
5376
  __proto__: null,
5242
- addDays: addDays,
5243
- addHours: addHours,
5244
- addMinutes: addMinutes,
5245
- addMonths: addMonths,
5246
- addYears: addYears,
5247
- daysInMonth: daysInMonth,
5248
- diffInDays: diffInDays,
5249
- diffInMinutes: diffInMinutes,
5250
- diffInMonths: diffInMonths,
5251
- diffInYears: diffInYears,
5252
- endOfDay: endOfDay,
5253
- endOfMonth: endOfMonth,
5254
- endOfYear: endOfYear,
5255
- formatDate: formatDate,
5256
- getAge: getAge,
5257
- getWeekNumber: getWeekNumber,
5258
- inRange: inRange$2,
5259
- isAfter: isAfter,
5260
- isBefore: isBefore,
5261
- isFuture: isFuture,
5262
- isLeapYear: isLeapYear,
5263
- isPast: isPast,
5264
- isSameDay: isSameDay,
5265
- isToday: isToday,
5266
- isValidDate: isValidDate$1,
5267
- isWeekend: isWeekend,
5268
- nextWorkday: nextWorkday,
5269
- now: now,
5270
- parseDate: parseDate,
5271
- startOfDay: startOfDay,
5272
- startOfMonth: startOfMonth,
5273
- startOfYear: startOfYear,
5274
- subtractDays: subtractDays,
5275
- subtractMonths: subtractMonths,
5276
- subtractYears: subtractYears,
5277
- timeAgo: timeAgo,
5278
- toDateOnly: toDateOnly,
5279
- toISOString: toISOString,
5280
- today: today
5377
+ average: average$1,
5378
+ chunk: chunk,
5379
+ compact: compact,
5380
+ countBy: countBy,
5381
+ difference: difference,
5382
+ every: every,
5383
+ filterBy: filterBy,
5384
+ first: first,
5385
+ flatten: flatten,
5386
+ flattenDeep: flattenDeep,
5387
+ groupBy: groupBy,
5388
+ intersection: intersection,
5389
+ isEmpty: isEmpty$2,
5390
+ last: last,
5391
+ maxBy: maxBy,
5392
+ minBy: minBy,
5393
+ move: move,
5394
+ paginate: paginate,
5395
+ partition: partition,
5396
+ sample: sample,
5397
+ shuffle: shuffle,
5398
+ some: some,
5399
+ sortBy: sortBy,
5400
+ sumBy: sumBy,
5401
+ toMap: toMap,
5402
+ toggle: toggle,
5403
+ union: union,
5404
+ unique: unique,
5405
+ uniqueBy: uniqueBy,
5406
+ zip: zip
5281
5407
  });
5282
5408
 
5283
5409
  // ─── Number Utilities ────────────────────────────────────────────────────────
@@ -6325,5 +6451,5 @@ var validation_util = /*#__PURE__*/Object.freeze({
6325
6451
  * Generated bundle index. Do not edit.
6326
6452
  */
6327
6453
 
6328
- export { array_util as ArrayUtil, date_util as DateUtil, DeleteConfirmation, DeleteConfirmationData, Dialog, DialogWrapper, DynamicForm, FormStructureModule, Httpbase, number_util as NumberUtil, object_util as ObjectUtil, OslAutocomplete, OslAutocompleteLister, OslBaseExtended, OslButton, OslCheckbox, OslDatepicker, OslFileUpload, OslFormGrid, OslGrid, OslRadio, OslReportForm, OslReportGrid, OslSearchbar, OslSelect, OslSetup, OslSkeletonDirective, OslSkeletonModule, OslSkeletonThemeService, OslSlideToggle, Oslinput, Osltextarea, storage_util as StorageUtil, string_util as StringUtil, validation_util as ValidationUtil, baseComponent };
6454
+ export { array_util as ArrayUtil, date_util as DateUtil, DeleteConfirmation, DeleteConfirmationData, Dialog, DialogWrapper, DynamicForm, FormStructureModule, Httpbase, number_util as NumberUtil, object_util as ObjectUtil, OslAutocomplete, OslAutocompleteLister, OslBaseExtended, OslButton, OslCheckbox, OslDatepicker, OslDatetimepicker, OslFileUpload, OslFormGrid, OslGrid, OslRadio, OslReportForm, OslReportGrid, OslSearchbar, OslSelect, OslSetup, OslSkeletonDirective, OslSkeletonModule, OslSkeletonThemeService, OslSlideToggle, Oslinput, Osltextarea, storage_util as StorageUtil, string_util as StringUtil, validation_util as ValidationUtil, baseComponent };
6329
6455
  //# sourceMappingURL=osl-base-extended.mjs.map