@decaf-ts/for-angular 0.0.46 → 0.0.48

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.
@@ -1,16 +1,17 @@
1
- import { UIKeys, HTML5InputTypes, parseValueByType, HTML5CheckTypes, escapeHtml, parseToNumber, RenderingEngine, RenderingError, UIMediaBreakPoints } from '@decaf-ts/ui-decorators';
1
+ import { HTML5InputTypes, parseValueByType, HTML5CheckTypes, escapeHtml, parseToNumber, RenderingEngine, DecafComponent, UIKeys, RenderingError, UIMediaBreakPoints, DecafEventHandler } from '@decaf-ts/ui-decorators';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, NgModule, isDevMode, reflectComponentType, Injector, createEnvironmentInjector, runInInjectionContext, createComponent, inject, NgZone, Injectable, ChangeDetectorRef, Renderer2, EventEmitter, ElementRef, Input, Output, ViewChild, Inject, Directive, EnvironmentInjector, ViewContainerRef, TemplateRef, Component, HostListener, CUSTOM_ELEMENTS_SCHEMA, ViewEncapsulation } from '@angular/core';
4
4
  import * as i1$1 from '@angular/common';
5
5
  import { CommonModule, Location, NgComponentOutlet } from '@angular/common';
6
6
  import { VALIDATION_PARENT_KEY, ValidationKeys, DEFAULT_PATTERNS, Validation, Primitives, ComparisonValidationKeys, PathProxyEngine, Model, ModelKeys, isValidDate as isValidDate$1, parseDate, sf, ReservedModels } from '@decaf-ts/decorator-validation';
7
- import { InternalError, OperationKeys, NotFoundError } from '@decaf-ts/db-decorators';
7
+ import { OperationKeys, InternalError, NotFoundError } from '@decaf-ts/db-decorators';
8
8
  import * as i1 from '@angular/forms';
9
9
  import { FormGroup, FormControl, FormsModule, ReactiveFormsModule, FormArray, AbstractControl, Validators } from '@angular/forms';
10
10
  import { InjectableRegistryImp } from '@decaf-ts/injectable-decorators';
11
11
  import { TranslateModule, TranslatePipe, TranslateParser, provideTranslateService, TranslateLoader, provideTranslateParser, TranslateService } from '@ngx-translate/core';
12
- import { Logging, LoggedClass } from '@decaf-ts/logging';
13
- import { uses, Repository, OrderDirection, Condition } from '@decaf-ts/core';
12
+ import { Logging } from '@decaf-ts/logging';
13
+ import { Repository, OrderDirection, Condition } from '@decaf-ts/core';
14
+ import { uses, Metadata, apply, metadata } from '@decaf-ts/decoration';
14
15
  import { faker } from '@faker-js/faker';
15
16
  import { Router, NavigationEnd, NavigationStart } from '@angular/router';
16
17
  import { forkJoin, Subject, BehaviorSubject, fromEvent, merge, of, Observable, timer, firstValueFrom, debounceTime } from 'rxjs';
@@ -21,7 +22,6 @@ import { IonModal, IonSpinner, IonButton, IonButtons, IonContent, IonHeader, Ion
21
22
  import { addIcons } from 'ionicons';
22
23
  import * as allIcons from 'ionicons/icons';
23
24
  import { chevronUpOutline, chevronDownOutline, createOutline, trashOutline, addOutline, alertCircleOutline, arrowUpOutline, arrowDownOutline, searchOutline, closeOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
24
- import { apply, metadata } from '@decaf-ts/reflection';
25
25
  import { DomSanitizer, Title } from '@angular/platform-browser';
26
26
  import { MenuController } from '@ionic/angular';
27
27
 
@@ -50,7 +50,7 @@ import { MenuController } from '@ionic/angular';
50
50
  * @memberOf module:lib/engine/constants
51
51
  */
52
52
  const AngularEngineKeys = {
53
- REFLECT: `${UIKeys.REFLECT}.angular.`,
53
+ REFLECT: `angular`,
54
54
  DYNAMIC: 'dynamic-component',
55
55
  ANNOTATIONS: '__annotations__',
56
56
  ECMP: 'ecmp',
@@ -63,9 +63,9 @@ const AngularEngineKeys = {
63
63
  RENDERED_ID: 'rendered-as-{0}',
64
64
  PARENT: '_parent',
65
65
  VALIDATION_PARENT_KEY: VALIDATION_PARENT_KEY,
66
- FLAVOUR: "angular",
66
+ FLAVOUR: 'angular',
67
67
  LOADED: 'engineLoaded',
68
- DARK_PALETTE_CLASS: 'dcf-palette-dark'
68
+ DARK_PALETTE_CLASS: 'dcf-palette-dark',
69
69
  };
70
70
  /**
71
71
  * @description Form validation state constants.
@@ -138,7 +138,6 @@ var LoggerLevels;
138
138
  LoggerLevels[LoggerLevels["ERROR"] = 4] = "ERROR";
139
139
  LoggerLevels[LoggerLevels["CRITICAL"] = 5] = "CRITICAL";
140
140
  })(LoggerLevels || (LoggerLevels = {}));
141
- ;
142
141
  /**
143
142
  * @description Route direction constants.
144
143
  * @summary Defines the possible navigation directions in the application.
@@ -294,10 +293,10 @@ const DefaultListEmptyOptions = {
294
293
  showButton: false,
295
294
  icon: 'folder-open-outline',
296
295
  buttonText: 'locale.empty.button',
297
- link: ''
296
+ link: '',
298
297
  };
299
298
  const DefaultModalOptions = {
300
- component: "",
299
+ component: '',
301
300
  showBackdrop: true,
302
301
  backdropDismiss: false,
303
302
  animated: true,
@@ -310,12 +309,12 @@ const ActionRoles = {
310
309
  confirm: 'confirm',
311
310
  submit: 'submit',
312
311
  clear: 'clear',
313
- back: 'back'
312
+ back: 'back',
314
313
  };
315
314
  const WindowColorSchemes = {
316
315
  light: 'light',
317
316
  dark: 'dark',
318
- undefined: 'undefined'
317
+ undefined: 'undefined',
319
318
  };
320
319
  const ElementSizes = {
321
320
  xsmall: 'xsmall',
@@ -341,7 +340,7 @@ const LayoutGridGaps = {
341
340
  medium: 'medium',
342
341
  large: 'large',
343
342
  collapse: 'collapse',
344
- none: ''
343
+ none: '',
345
344
  };
346
345
  const ListItemPositions = {
347
346
  uid: 'uid',
@@ -511,7 +510,10 @@ const LOCALE_ROOT_TOKEN = new InjectionToken('LOCALE_ROOT_TOKEN');
511
510
  * // Inject any arbitrary value
512
511
  * { provide: CPTKN, useValue: { key: 'value', data: [1, 2, 3] } }
513
512
  */
514
- const CPTKN = new InjectionToken('CPTKN', { providedIn: 'root', factory: () => '' });
513
+ const CPTKN = new InjectionToken('CPTKN', {
514
+ providedIn: 'root',
515
+ factory: () => '',
516
+ });
515
517
  /**
516
518
  * @description Injection token for i18n resource configuration.
517
519
  * @summary Used to provide configuration for internationalization resources, including
@@ -549,29 +551,35 @@ function provideDynamicComponents(...components) {
549
551
  * @memberOf module:lib/for-angular-common.module
550
552
  * @example
551
553
  * // Get repository by model class
552
- * const userRepo = getModelRepository(User);
554
+ * const userRepo = getModelAndRepository(User);
553
555
  *
554
556
  * // Get repository by model name
555
- * const productRepo = getModelRepository('Product');
557
+ * const productRepo = getModelAndRepository('Product');
556
558
  *
557
559
  * // Use repository for queries
558
560
  * const users = await userRepo.findAll();
559
561
  */
560
- function getModelRepository(model) {
562
+ function getModelAndRepository(model) {
561
563
  try {
562
- const modelName = (typeof model === Primitives.STRING ? model : model.constructor.name);
563
- const constructor = Model.get(modelName.charAt(0).toUpperCase() + modelName.slice(1));
564
+ const modelName = (typeof model === Primitives.STRING
565
+ ? model
566
+ : model.constructor.name);
567
+ const constructor = Model.get((modelName.charAt(0).toUpperCase() + modelName.slice(1)));
564
568
  if (!constructor)
565
- throw new InternalError(`Cannot find model for ${modelName}. was it registered with @model?`);
569
+ return undefined;
566
570
  const dbAdapterFlavour = getOnWindow(DB_ADAPTER_PROVIDER) || undefined;
567
571
  if (dbAdapterFlavour)
568
572
  uses(dbAdapterFlavour)(constructor);
569
- const repo = Repository.forModel(constructor);
573
+ const repository = Repository.forModel(constructor);
570
574
  model = new constructor();
571
- return repo;
575
+ const pk = Model.pk(repository.class);
576
+ if (!pk)
577
+ return undefined;
578
+ return { repository, model, pk };
572
579
  }
573
580
  catch (error) {
574
- throw new InternalError(error?.message || error);
581
+ getLogger(getModelAndRepository).warn(error?.message || error);
582
+ return undefined;
575
583
  }
576
584
  }
577
585
  /**
@@ -596,13 +604,12 @@ function getModelRepository(model) {
596
604
  * provideDbAdapter(PostgresAdapter, { host: 'localhost', port: 5432 })
597
605
  * ]
598
606
  */
599
- function provideDbAdapter(adapterClass, options = {}, flavour) {
600
- const adapter = new adapterClass(options);
607
+ function provideDbAdapter(clazz, options = {}, flavour) {
608
+ const adapter = new clazz(options);
601
609
  if (flavour)
602
610
  flavour = adapter.flavour;
603
- // Log and expose adapter flavour globally
604
611
  getLogger(provideDbAdapter).info(`Using ${adapter.constructor.name} ${flavour} as Db Provider`);
605
- getWindow()[DB_ADAPTER_PROVIDER] = flavour;
612
+ setOnWindow(DB_ADAPTER_PROVIDER, flavour);
606
613
  return {
607
614
  provide: DB_ADAPTER_PROVIDER_TOKEN,
608
615
  useValue: adapter,
@@ -614,7 +621,7 @@ function provideDbAdapter(adapterClass, options = {}, flavour) {
614
621
  * @description Base logger instance for the for-angular module.
615
622
  * @memberOf module:lib/for-angular-common.module
616
623
  */
617
- const log = Logging.for("for-angular");
624
+ const log = Logging.for('for-angular');
618
625
  /**
619
626
  * @description Retrieves a logger instance for the given context.
620
627
  * @summary Creates or retrieves a namespaced logger instance using the Decaf logging system.
@@ -640,7 +647,7 @@ const CommonModules = [
640
647
  FormsModule,
641
648
  ReactiveFormsModule,
642
649
  TranslateModule,
643
- TranslatePipe
650
+ TranslatePipe,
644
651
  ];
645
652
  /**
646
653
  * @description Main Angular module for the Decaf framework.
@@ -1416,6 +1423,7 @@ class NgxFormService {
1416
1423
  partFormGroup[BaseComponentProps.FORM_GROUP_COMPONENT_PROPS] = {
1417
1424
  childOf: childOf || '',
1418
1425
  isMultiple: isMultiple,
1426
+ required: parentProps?.required ?? false,
1419
1427
  name: part,
1420
1428
  pk,
1421
1429
  [ModelKeys.MODEL]: {},
@@ -1963,13 +1971,27 @@ class NgxFormService {
1963
1971
  if (control instanceof FormArray) {
1964
1972
  const totalGroups = control.length;
1965
1973
  const hasValid = control.controls.some(control => control.valid);
1966
- if (totalGroups > 1 && hasValid) {
1974
+ const parentProps = control[BaseComponentProps.FORM_GROUP_COMPONENT_PROPS] || {};
1975
+ const childControl = control.at(0);
1976
+ if (totalGroups === 1) {
1977
+ const parent = childControl.parent;
1978
+ if (!parentProps.required) {
1979
+ parent.setErrors(null);
1980
+ parent.updateValueAndValidity({ emitEvent: true });
1981
+ childControl.disable();
1982
+ }
1983
+ else {
1984
+ this.validateFields(childControl);
1985
+ }
1986
+ }
1987
+ else if (totalGroups > 1 && hasValid) {
1967
1988
  for (let i = control.length - 1; i >= 0; i--) {
1968
1989
  const childControl = control.at(i);
1969
1990
  // disable no valid groups on array
1970
1991
  if (!childControl.valid) {
1971
- childControl.parent.setErrors(null);
1972
- childControl.parent.updateValueAndValidity({ emitEvent: true });
1992
+ const parent = childControl.parent;
1993
+ parent.setErrors(null);
1994
+ parent.updateValueAndValidity({ emitEvent: true });
1973
1995
  childControl.disable();
1974
1996
  }
1975
1997
  else {
@@ -2169,7 +2191,9 @@ class DecafFakerRepository {
2169
2191
  }
2170
2192
  get repository() {
2171
2193
  if (!this._repository) {
2172
- const modelName = typeof this.model === 'string' ? this.model : this.model.constructor.name;
2194
+ const modelName = typeof this.model === 'string'
2195
+ ? this.model
2196
+ : this.model.constructor.name;
2173
2197
  const constructor = Model.get(modelName);
2174
2198
  if (!constructor)
2175
2199
  throw new InternalError(`Cannot find model ${modelName}. was it registered with @model?`);
@@ -2190,23 +2214,23 @@ class DecafFakerRepository {
2190
2214
  if (!this._repository)
2191
2215
  this._repository = this.repository;
2192
2216
  }
2193
- async generateData(pkValues, pk, pkType) {
2194
- const limit = pkValues ? Object.values(pkValues || {}).length - 1 : this.limit;
2195
- if (!pk)
2196
- pk = this._repository?.pk;
2197
- if (!pkType)
2198
- pkType = Reflect.getMetadata("design:type", this.model, pk).name.toLowerCase();
2217
+ async generateData(values, key, keyType) {
2218
+ const limit = values ? Object.values(values || {}).length : this.limit;
2219
+ if (!key)
2220
+ key = Model.pk(this.repository.class);
2221
+ if (!keyType)
2222
+ keyType = Metadata.type(this.repository.class, key).name.toLowerCase();
2199
2223
  const props = Object.keys(this.model).filter((k) => {
2200
- if (pkType === Primitives.STRING)
2224
+ if (keyType === Primitives.STRING)
2201
2225
  return !['updatedBy', 'createdAt', 'createdBy', 'updatedAt'].includes(k);
2202
- return ![pk, 'updatedBy', 'createdAt', 'createdBy', 'updatedAt'].includes(k);
2226
+ return ![key, 'updatedBy', 'createdAt', 'createdBy', 'updatedAt'].includes(k);
2203
2227
  });
2204
2228
  const dataProps = {};
2205
2229
  for (const prop of props) {
2206
- const type = Reflect.getMetadata("design:type", this.model, prop);
2207
- switch ((type?.name || "").toLowerCase()) {
2230
+ const type = Metadata.type(this.repository.class, prop);
2231
+ switch (type.name.toLowerCase()) {
2208
2232
  case 'string':
2209
- dataProps[prop] = () => `${faker.lorem.word()} ${pk === prop ? ' - ' + faker.number.int({ min: 1, max: 200 }) : ''}`;
2233
+ dataProps[prop] = () => `${faker.lorem.word()} ${key === prop ? ' - ' + faker.number.int({ min: 1, max: 200 }) : ''}`;
2210
2234
  break;
2211
2235
  case 'step':
2212
2236
  dataProps[prop] = () => faker.lorem.word();
@@ -2232,20 +2256,25 @@ class DecafFakerRepository {
2232
2256
  }
2233
2257
  }
2234
2258
  const data = getFakerData(limit, dataProps, typeof this.model === 'string' ? this.model : this.model?.constructor.name);
2235
- if (!pkValues)
2259
+ if (!values)
2236
2260
  return data;
2237
- const values = Object.values(pkValues);
2261
+ const _values = Object.values(values);
2238
2262
  const iterated = [];
2239
2263
  function getPkValue(item) {
2240
- if (values.length > 0) {
2241
- const randomIndex = Math.floor(Math.random() * values.length);
2242
- const selected = values.splice(randomIndex, 1)[0];
2243
- const value = pkType === Primitives.STRING ? selected : pkType === Primitives.NUMBER ?
2244
- parseToNumber(selected) : pkType === Array.name ? [selected] : selected;
2245
- item[pk] = value;
2264
+ if (_values.length > 0) {
2265
+ const randomIndex = Math.floor(Math.random() * _values.length);
2266
+ const selected = _values.splice(randomIndex, 1)[0];
2267
+ const value = keyType === Primitives.STRING
2268
+ ? selected
2269
+ : keyType === Primitives.NUMBER
2270
+ ? parseToNumber(selected)
2271
+ : keyType === Array.name
2272
+ ? [selected]
2273
+ : selected;
2274
+ item[key] = value;
2246
2275
  }
2247
- if (!iterated.includes(item[pk])) {
2248
- iterated.push(item[pk]);
2276
+ if (!iterated.includes(item[key])) {
2277
+ iterated.push(item[key]);
2249
2278
  return item;
2250
2279
  }
2251
2280
  return undefined;
@@ -2254,11 +2283,12 @@ class DecafFakerRepository {
2254
2283
  return data
2255
2284
  .map((d) => getPkValue(d))
2256
2285
  .filter((item) => {
2257
- if (!item || uids.has(item[pk]) || !item[pk] || item[pk] === undefined)
2286
+ if (!item || uids.has(item[key]) || !item[key] || item[key] === undefined)
2258
2287
  return false;
2259
- uids.add(item[pk]);
2288
+ uids.add(item[key]);
2260
2289
  return true;
2261
- }).filter(Boolean);
2290
+ })
2291
+ .filter(Boolean);
2262
2292
  }
2263
2293
  }
2264
2294
  function getFakerData(limit = 100, data, model) {
@@ -2267,12 +2297,14 @@ function getFakerData(limit = 100, data, model) {
2267
2297
  const item = {};
2268
2298
  for (const [key, value] of Object.entries(data)) {
2269
2299
  const val = value();
2270
- item[key] = val.constructor === Date ? formatDate(val) : val;
2300
+ item[key] = val?.constructor === Date ? formatDate(val) : val;
2271
2301
  }
2272
2302
  // if ((item as any)?.['code'])
2273
2303
  // (item as any).code = `${index}`;
2274
2304
  // item.id = index;
2275
2305
  // item.createdAt = faker.date.past({ refDate: '2025-01-01' });
2306
+ if (item['productCode'])
2307
+ item['productCode'] = `${index}`;
2276
2308
  index = index + 1;
2277
2309
  return (!model ? item : Model.build(item, model));
2278
2310
  });
@@ -2408,7 +2440,8 @@ class NgxRenderingEngine extends RenderingEngine {
2408
2440
  * @memberOf module:lib/engine/NgxRenderingEngine
2409
2441
  */
2410
2442
  fromFieldDefinition(fieldDef, vcr, injector, tpl, registryFormId = Date.now().toString(36).toUpperCase(), createComponent = true, formGroup) {
2411
- const cmp = fieldDef?.['component'] || NgxRenderingEngine.components(fieldDef.tag);
2443
+ const cmp = fieldDef?.['component'] ||
2444
+ NgxRenderingEngine.components(fieldDef.tag);
2412
2445
  const component = cmp.constructor;
2413
2446
  const componentMetadata = reflectComponentType(component);
2414
2447
  if (!componentMetadata) {
@@ -2416,7 +2449,7 @@ class NgxRenderingEngine extends RenderingEngine {
2416
2449
  }
2417
2450
  const { inputs: possibleInputs } = componentMetadata;
2418
2451
  const inputs = { ...fieldDef.props };
2419
- const unmappedKeys = Object.keys(inputs).filter(input => {
2452
+ const unmappedKeys = Object.keys(inputs).filter((input) => {
2420
2453
  const isMapped = possibleInputs.find(({ propName }) => propName === input);
2421
2454
  if (!isMapped)
2422
2455
  delete inputs[input];
@@ -2432,13 +2465,17 @@ class NgxRenderingEngine extends RenderingEngine {
2432
2465
  // const hasFormRoot = Object.values(possibleInputs).some(({propName}) => propName === AngularEngineKeys.PARENT_FORM);
2433
2466
  // if (hasFormRoot && !inputs?.[AngularEngineKeys.PARENT_FORM] && formGroup)
2434
2467
  // inputs[AngularEngineKeys.PARENT_FORM] = formGroup;
2468
+ if (operation !== OperationKeys.CREATE && hiddenOn.includes(OperationKeys.CREATE)) {
2469
+ fieldDef.props = { ...fieldDef.props, ...{ readonly: true, type: HTML5InputTypes.TEXT } };
2470
+ }
2435
2471
  const result = {
2436
2472
  component,
2437
2473
  inputs,
2438
2474
  injector,
2439
2475
  };
2440
2476
  if (fieldDef.rendererId)
2441
- result.inputs['rendererId'] = fieldDef.rendererId;
2477
+ result.inputs['rendererId'] =
2478
+ fieldDef.rendererId;
2442
2479
  // process children
2443
2480
  // generating DOM
2444
2481
  // const projectable = NgxRenderingEngine._projectable;
@@ -2446,11 +2483,12 @@ class NgxRenderingEngine extends RenderingEngine {
2446
2483
  // const template = [];
2447
2484
  const hasChildren = Object.values(possibleInputs).some(({ propName }) => propName === AngularEngineKeys.CHILDREN);
2448
2485
  const hasModel = Object.values(possibleInputs).some(({ propName }) => propName === ModelKeys.MODEL);
2449
- const componentInputs = Object.assign(inputs, (hasModel ? { model: this._model } : {}), (hasChildren ? { children: fieldDef?.['children'] || [] } : {}));
2486
+ const componentInputs = Object.assign(inputs, hasModel ? { model: this._model } : {}, hasChildren ? { children: fieldDef?.['children'] || [] } : {});
2450
2487
  if (createComponent) {
2451
2488
  vcr.clear();
2452
2489
  const componentInstance = NgxRenderingEngine.createComponent(component, componentInputs, injector, componentMetadata, vcr, []);
2453
- result.component = NgxRenderingEngine._instance = componentInstance;
2490
+ result.component = NgxRenderingEngine._instance =
2491
+ componentInstance;
2454
2492
  }
2455
2493
  if (fieldDef.children?.length) {
2456
2494
  if (!NgxRenderingEngine._parentProps && inputs?.['pages']) {
@@ -2458,8 +2496,9 @@ class NgxRenderingEngine extends RenderingEngine {
2458
2496
  // NgxRenderingEngine._projectable = false;
2459
2497
  }
2460
2498
  result.children = fieldDef.children.map((child) => {
2461
- // const hiddenOn = (child?.props?.hidden || []) as CrudOperations[];
2462
- // moved to ui decorators
2499
+ const readonly = operation === OperationKeys.UPDATE && (child?.props?.hidden || []).includes(OperationKeys.CREATE);
2500
+ // const hiddenOn = (child?.props?.hidden || []) as string[];
2501
+ // // moved to ui decorators
2463
2502
  // if (child?.children?.length) {
2464
2503
  // child.children = child.children.filter(c => {
2465
2504
  // const hiddenOn = c?.props?.hidden || [];
@@ -2468,7 +2507,15 @@ class NgxRenderingEngine extends RenderingEngine {
2468
2507
  // })
2469
2508
  // }
2470
2509
  // if (!hiddenOn?.length || !(hiddenOn as CrudOperations[]).includes(operation as CrudOperations))
2471
- NgxFormService.addControlFromProps(registryFormId, child.props, { ...inputs, ...NgxRenderingEngine._parentProps || {} });
2510
+ if (!readonly) {
2511
+ NgxFormService.addControlFromProps(registryFormId, child.props, {
2512
+ ...inputs,
2513
+ ...(NgxRenderingEngine._parentProps || {}),
2514
+ });
2515
+ }
2516
+ else {
2517
+ child.props = { ...child.props, ...{ readonly: true } };
2518
+ }
2472
2519
  return this.fromFieldDefinition(child, vcr, injector, tpl, registryFormId, false, formGroup);
2473
2520
  });
2474
2521
  }
@@ -2504,24 +2551,29 @@ class NgxRenderingEngine extends RenderingEngine {
2504
2551
  }
2505
2552
  static createHostComponent(component, props = {}, injector) {
2506
2553
  if (!injector)
2507
- injector = NgxRenderingEngine._injector || Injector.create({ providers: [], parent: Injector.NULL });
2554
+ injector =
2555
+ NgxRenderingEngine._injector ||
2556
+ Injector.create({ providers: [], parent: Injector.NULL });
2508
2557
  const envInjector = createEnvironmentInjector([], injector);
2509
2558
  let cmp = {};
2510
2559
  runInInjectionContext(envInjector, () => {
2511
2560
  const host = document.createElement('div');
2512
- component = typeof component === Primitives.STRING ? NgxRenderingEngine.components(component) : component;
2561
+ component =
2562
+ typeof component === Primitives.STRING
2563
+ ? NgxRenderingEngine.components(component)
2564
+ : component;
2513
2565
  if (!host)
2514
2566
  throw new Error('Cant create host element for component');
2515
2567
  cmp = createComponent(component, {
2516
2568
  environmentInjector: envInjector,
2517
- hostElement: host
2569
+ hostElement: host,
2518
2570
  });
2519
2571
  const metadata = reflectComponentType(component);
2520
2572
  if (!metadata)
2521
2573
  throw new InternalError(`Metadata for component ${component} not found.`);
2522
2574
  const { inputs: possibleInputs } = metadata;
2523
2575
  const inputs = { ...props };
2524
- const unmappedKeys = Object.keys(inputs).filter(input => {
2576
+ const unmappedKeys = Object.keys(inputs).filter((input) => {
2525
2577
  const isMapped = possibleInputs.find(({ propName }) => propName === input);
2526
2578
  if (!isMapped)
2527
2579
  delete inputs[input];
@@ -2607,7 +2659,8 @@ class NgxRenderingEngine extends RenderingEngine {
2607
2659
  const props = fieldDef.props;
2608
2660
  if (!NgxRenderingEngine._operation)
2609
2661
  NgxRenderingEngine._operation = props?.operation || undefined;
2610
- const isArray = (props?.pages && props?.pages >= 1 || props?.multiple === true);
2662
+ const isArray = (props?.pages && props?.pages >= 1) ||
2663
+ props?.multiple === true;
2611
2664
  const formGroup = NgxFormService.createForm(formId, isArray);
2612
2665
  result = this.fromFieldDefinition(fieldDef, vcr, injector, tpl, formId, true, formGroup);
2613
2666
  if (result.component)
@@ -2671,20 +2724,6 @@ class NgxRenderingEngine extends RenderingEngine {
2671
2724
  throw new InternalError(`No Component registered under ${selector}`);
2672
2725
  return this._components[selector];
2673
2726
  }
2674
- /**
2675
- * @description Generates a key for reflection metadata storage.
2676
- * @summary This static method generates a key for reflection metadata by prefixing the input key
2677
- * with the Angular engine's reflection prefix. This is used for storing and retrieving
2678
- * metadata in a namespaced way to avoid conflicts with other metadata.
2679
- * @param {string} key - The base key to prefix
2680
- * @return {string} The prefixed key for reflection metadata
2681
- * @static
2682
- * @override
2683
- * @memberOf module:lib/engine/NgxRenderingEngine
2684
- */
2685
- static key(key) {
2686
- return `${AngularEngineKeys.REFLECT}${key}`;
2687
- }
2688
2727
  /**
2689
2728
  * @description Sets input properties on a component instance.
2690
2729
  * @summary This static utility method sets input properties on a component instance
@@ -2720,7 +2759,7 @@ class NgxRenderingEngine extends RenderingEngine {
2720
2759
  */
2721
2760
  static setInputs(component, inputs, metadata) {
2722
2761
  function parseInputValue(component, input) {
2723
- Object.keys(input).forEach(key => {
2762
+ Object.keys(input).forEach((key) => {
2724
2763
  const value = input[key];
2725
2764
  if (typeof value === 'object' && !!value)
2726
2765
  return parseInputValue(component, value);
@@ -2786,6 +2825,10 @@ var operations = {
2786
2825
  "delete": {
2787
2826
  success: "Successfully deleted item with {0} {1}.",
2788
2827
  error: "Error deleting item with {0} {1}."
2828
+ },
2829
+ multiple: {
2830
+ success: "Successfully processed all operations.",
2831
+ error: "Error processing operations."
2789
2832
  }
2790
2833
  };
2791
2834
  var component = {
@@ -2795,7 +2838,8 @@ var component = {
2795
2838
  cancel: "Cancel",
2796
2839
  not_unique: "The value entered already exists. Value {0}",
2797
2840
  max_items: "You can create up to {0} items.",
2798
- max_items_reached: "Maximum of {0} items reached."
2841
+ max_items_reached: "Maximum of {0} items reached.",
2842
+ empty: "No items found."
2799
2843
  },
2800
2844
  list: {
2801
2845
  pagination: "Showing page <span class=\"text-bold\">{0} of {1}</span>",
@@ -3463,7 +3507,7 @@ catch (e) {
3463
3507
  * @implements {OnChanges}
3464
3508
  * @memberOf module:lib/engine/NgxComponentDirective
3465
3509
  */
3466
- class NgxComponentDirective extends LoggedClass {
3510
+ class NgxComponentDirective extends DecafComponent {
3467
3511
  /**
3468
3512
  * @description Constructor for NgxComponentDirective.
3469
3513
  * @summary Initializes the directive by setting up the component name, locale root,
@@ -3506,7 +3550,7 @@ class NgxComponentDirective extends LoggedClass {
3506
3550
  * @summary Defines how fields from the data model should be mapped to properties used by the component.
3507
3551
  * This allows for flexible data binding between the model and the component's display logic. Can be
3508
3552
  * provided as a static object mapping or as a function for dynamic mapping transformations.
3509
- * @type {Record<string, string> | FunctionLike}
3553
+ * @type {Record<string, string> | FunctionLike | Record<string, FunctionLike>}
3510
3554
  * @default {}
3511
3555
  * @memberOf module:lib/engine/NgxComponentDirective
3512
3556
  */
@@ -3528,9 +3572,9 @@ class NgxComponentDirective extends LoggedClass {
3528
3572
  * The operation affects form validation, field availability, and the specific repository
3529
3573
  * method called during data submission.
3530
3574
  *
3531
- * @type {OperationKeys.CREATE | OperationKeys.READ | OperationKeys.UPDATE | OperationKeys.DELETE}
3575
+ * @type {OperationKeys}
3532
3576
  * @default OperationKeys.READ
3533
- * @memberOf ModelPage
3577
+ * @memberOf module:lib/engine/NgxComponentDirective
3534
3578
  */
3535
3579
  this.operation = OperationKeys.READ;
3536
3580
  /**
@@ -3587,7 +3631,7 @@ class NgxComponentDirective extends LoggedClass {
3587
3631
  * @type {NgxMediaService}
3588
3632
  * @memberOf module:lib/engine/NgxComponentDirective
3589
3633
  */
3590
- this.mediaService = new NgxMediaService();
3634
+ this.mediaService = inject(NgxMediaService);
3591
3635
  /**
3592
3636
  * @description Angular Renderer2 service for platform-agnostic DOM manipulation.
3593
3637
  * @summary Injected service that provides a safe, platform-agnostic way to manipulate DOM elements.
@@ -3618,6 +3662,16 @@ class NgxComponentDirective extends LoggedClass {
3618
3662
  * @memberOf module:lib/engine/NgxComponentDirective
3619
3663
  */
3620
3664
  this.listenEvent = new EventEmitter();
3665
+ /**
3666
+ * @description Event emitter for custom component events.
3667
+ * @summary Emits custom events that occur within child components or the component itself.
3668
+ * This allows parent components to listen for and respond to user interactions or
3669
+ * state changes. Events are passed up the component hierarchy to enable coordinated
3670
+ * behavior across the application.
3671
+ * @type {EventEmitter<IBaseCustomEvent>}
3672
+ * @memberOf module:lib/engine/NgxComponentDirective
3673
+ */
3674
+ this.refreshEvent = new EventEmitter();
3621
3675
  /**
3622
3676
  * @description Angular Router instance for programmatic navigation.
3623
3677
  * @summary Injected Router service used for programmatic navigation between routes
@@ -3635,7 +3689,7 @@ class NgxComponentDirective extends LoggedClass {
3635
3689
  * and other properties needed to render list items correctly. The tag property
3636
3690
  * identifies which component should be used to render each item in a list.
3637
3691
  * Additional properties can be included to customize the rendering behavior.
3638
- * @type {Record<string, unknown>}
3692
+ * @type {Record<string, FieldDefinition>}
3639
3693
  * @default {tag: ""}
3640
3694
  * @memberOf module:lib/engine/NgxComponentDirective
3641
3695
  */
@@ -3662,16 +3716,6 @@ class NgxComponentDirective extends LoggedClass {
3662
3716
  * @memberOf module:lib/engine/NgxComponentDirective
3663
3717
  */
3664
3718
  this.route = "";
3665
- /**
3666
- * @description Initialization status flag for the component.
3667
- * @summary Tracks whether the component has completed its initialization process.
3668
- * This flag is used to prevent duplicate initialization and to determine if
3669
- * certain operations that require initialization can be performed.
3670
- * @type {boolean}
3671
- * @default false
3672
- * @memberOf module:lib/engine/NgxComponentDirective
3673
- */
3674
- this.initialized = false;
3675
3719
  /**
3676
3720
  * @description Controls whether borders are displayed around the component.
3677
3721
  * @summary Boolean flag that determines if the component should be visually outlined with borders.
@@ -3681,22 +3725,14 @@ class NgxComponentDirective extends LoggedClass {
3681
3725
  * @default false
3682
3726
  */
3683
3727
  this.borders = false;
3684
- /**
3685
- * @description Reference to CRUD operation constants for template usage.
3686
- * @summary Exposes the OperationKeys enum to the component template, enabling
3687
- * conditional rendering and behavior based on operation types. This protected
3688
- * readonly property ensures that template logic can access operation constants
3689
- * while maintaining encapsulation and preventing accidental modification.
3690
- * @protected
3691
- * @readonly
3692
- * @memberOf module:lib/engine/NgxComponentDirective
3693
- */
3694
- this.OperationKeys = OperationKeys;
3695
3728
  /**
3696
3729
  * @description Angular Location service.
3697
- * @summary Injected service that provides access to the browser's URL and history.
3698
- * This service is used for interacting with the browser's history API, allowing
3699
- * for back navigation and URL manipulation outside of Angular's router.
3730
+ * @summary Injected service that provides direct access to the browser's URL and history.
3731
+ * Unlike the Router, Location allows for low-level manipulation of the browser's history stack
3732
+ * and URL path, such as programmatically navigating back or forward, or updating the URL without
3733
+ * triggering a route change. This is useful for scenarios where you need to interact with the
3734
+ * browser history or URL outside of Angular's routing system, such as closing modals, handling
3735
+ * popstate events, or supporting custom navigation logic.
3700
3736
  *
3701
3737
  * @private
3702
3738
  * @type {Location}
@@ -3715,13 +3751,24 @@ class NgxComponentDirective extends LoggedClass {
3715
3751
  * @memberOf module:lib/engine/NgxComponentDirective
3716
3752
  */
3717
3753
  this.isModalChild = false;
3718
- this.componentName = componentName || "NgxComponentDirective";
3754
+ this.handlers = {};
3755
+ this.events = {};
3756
+ /**
3757
+ * @description Indicates whether a refresh operation is in progress.
3758
+ * @summary When true, the component is currently fetching new data. This is used
3759
+ * to control loading indicators and prevent duplicate refresh operations from
3760
+ * being triggered simultaneously.
3761
+ *
3762
+ * @type {boolean}
3763
+ * @default false
3764
+ */
3765
+ this.refreshing = false;
3766
+ this.componentName = componentName || 'NgxComponentDirective';
3719
3767
  this.localeRoot = localeRoot;
3720
3768
  if (!this.localeRoot && this.componentName)
3721
3769
  this.localeRoot = this.componentName;
3722
3770
  if (this.localeRoot)
3723
3771
  this.getLocale(this.localeRoot);
3724
- this.logger = this.log;
3725
3772
  this.uid = `${this.componentName}-${generateRandomValue(8)}`;
3726
3773
  }
3727
3774
  /**
@@ -3735,6 +3782,11 @@ class NgxComponentDirective extends LoggedClass {
3735
3782
  ngOnDestroy() {
3736
3783
  this.mediaService.destroy();
3737
3784
  }
3785
+ //TODO: Pass to ui decoretators
3786
+ async refresh(...args) {
3787
+ this.log.for(this.refresh).debug(`Refresh called with args: ${args}`);
3788
+ this.refreshEvent.emit(true);
3789
+ }
3738
3790
  /**
3739
3791
  * @description Getter for the current locale context identifier.
3740
3792
  * @summary Returns the current locale identifier by calling the getLocale method.
@@ -3758,10 +3810,9 @@ class NgxComponentDirective extends LoggedClass {
3758
3810
  get repository() {
3759
3811
  try {
3760
3812
  if (!this._repository) {
3761
- this._repository = getModelRepository(this.model);
3813
+ this._repository = getModelAndRepository(this.model)?.repository;
3762
3814
  if (this.model && !this.pk)
3763
- this.pk =
3764
- this._repository.pk || 'id';
3815
+ this.pk = Model.pk(this._repository?.class);
3765
3816
  }
3766
3817
  }
3767
3818
  catch (error) {
@@ -3769,6 +3820,9 @@ class NgxComponentDirective extends LoggedClass {
3769
3820
  }
3770
3821
  return this._repository;
3771
3822
  }
3823
+ set repository(repository) {
3824
+ this._repository = repository;
3825
+ }
3772
3826
  /**
3773
3827
  * @description Angular lifecycle hook for handling input property changes.
3774
3828
  * @summary Responds to changes in component input properties, specifically monitoring changes
@@ -3779,7 +3833,7 @@ class NgxComponentDirective extends LoggedClass {
3779
3833
  * @return {void}
3780
3834
  * @memberOf module:lib/engine/NgxComponentDirective
3781
3835
  */
3782
- ngOnChanges(changes) {
3836
+ async ngOnChanges(changes) {
3783
3837
  if (changes[BaseComponentProps.MODEL]) {
3784
3838
  const { currentValue } = changes[BaseComponentProps.MODEL];
3785
3839
  if (currentValue)
@@ -3788,6 +3842,44 @@ class NgxComponentDirective extends LoggedClass {
3788
3842
  if (!this.initialized)
3789
3843
  this.initialized = true;
3790
3844
  }
3845
+ // if (changes[UIKeys.HANDLERS]) {
3846
+ // const { currentValue, previousValue } = changes[UIKeys.HANDLERS];
3847
+ // if (currentValue && typeof currentValue !== previousValue) {
3848
+ // for(const key in currentValue) {
3849
+ // const event = currentValue[key]();
3850
+ // if (event && typeof event === 'function') {
3851
+ // const clazz = new event();
3852
+ // this.handlers[key] = clazz[key].bind(this);
3853
+ // console.log(this.handlers);
3854
+ // }
3855
+ // }
3856
+ // }
3857
+ // }
3858
+ if (changes[UIKeys.EVENTS]) {
3859
+ const { currentValue, previousValue } = changes[UIKeys.EVENTS];
3860
+ if (currentValue && currentValue !== previousValue) {
3861
+ if (!this._repository)
3862
+ this._repository = this.repository;
3863
+ for (const key in currentValue) {
3864
+ const event = currentValue[key]();
3865
+ if (event && typeof event === 'function') {
3866
+ try {
3867
+ const clazz = new event();
3868
+ this.events[key] = clazz[key].bind(this);
3869
+ if (event[key] instanceof Promise) {
3870
+ await clazz[key].bind(this)();
3871
+ }
3872
+ else {
3873
+ clazz[key].bind(this)();
3874
+ }
3875
+ }
3876
+ catch (error) {
3877
+ this.log.for(this.ngOnChanges).warn(`Error occurred while processing event "${key}": ${error?.message || error}`);
3878
+ }
3879
+ }
3880
+ }
3881
+ }
3882
+ }
3791
3883
  if (changes[BaseComponentProps.LOCALE_ROOT] || changes[BaseComponentProps.COMPONENT_NAME])
3792
3884
  this.locale = this.localeContext;
3793
3885
  if (this.enableDarkMode)
@@ -3811,23 +3903,8 @@ class NgxComponentDirective extends LoggedClass {
3811
3903
  return await firstValueFrom(this.translateService.get(phrase, (params || {})));
3812
3904
  ;
3813
3905
  }
3814
- /**
3815
- * @description Initializes the component asynchronously with custom logic.
3816
- * @summary Abstract initialization method that can be overridden by child components to perform
3817
- * custom initialization logic. By default, it simply sets the initialized flag to true.
3818
- * Child components can extend this method to load data, configure settings, or perform
3819
- * other setup operations required before the component is fully functional.
3820
- * @protected
3821
- * @param {...unknown[]} args - Variable number of arguments that can be used by child implementations
3822
- * @return {Promise<void>} A promise that resolves when initialization is complete
3823
- * @memberOf module:lib/engine/NgxComponentDirective
3824
- */
3825
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3826
- async initialize(...args) {
3827
- this.initialized = true;
3828
- }
3829
3906
  checkDarkMode() {
3830
- this.mediaService.isDarkMode().subscribe(isDark => {
3907
+ this.mediaService.isDarkMode().subscribe((isDark) => {
3831
3908
  this.isDarkMode = isDark;
3832
3909
  this.mediaService.toggleClass([this.component], AngularEngineKeys.DARK_PALETTE_CLASS, this.isDarkMode);
3833
3910
  });
@@ -4004,7 +4081,7 @@ class NgxComponentDirective extends LoggedClass {
4004
4081
  * end
4005
4082
  * @memberOf module:lib/engine/NgxComponentDirective
4006
4083
  */
4007
- async handleEvent(event) {
4084
+ async handleEvent(event, repository) {
4008
4085
  let name = "";
4009
4086
  const log = this.log.for(this.handleEvent);
4010
4087
  if (event instanceof CustomEvent) {
@@ -4019,8 +4096,11 @@ class NgxComponentDirective extends LoggedClass {
4019
4096
  if (!handlers[name])
4020
4097
  return log.debug(`No handler found for event ${name}`);
4021
4098
  try {
4022
- const clazz = new handlers[name](this.router);
4023
- const result = clazz.handle(event);
4099
+ const clazz = new handlers[name]();
4100
+ const handler = clazz.handle.bind(this);
4101
+ //const clazz = new event();
4102
+ // this.events[key] = clazz[key].bind(this);
4103
+ const result = handler(event);
4024
4104
  return (result instanceof Promise) ?
4025
4105
  await result : result;
4026
4106
  }
@@ -4030,6 +4110,10 @@ class NgxComponentDirective extends LoggedClass {
4030
4110
  }
4031
4111
  this.listenEvent.emit(event);
4032
4112
  }
4113
+ // passed for ui decorators
4114
+ // async submit(...args: unknown[]): Promise<any> {
4115
+ // this.log.for(this.submit).info(`submit for ${this.componentName} with ${JSON.stringify(args)}`);
4116
+ // }
4033
4117
  /**
4034
4118
  * @description Determines if a specific operation is allowed in the current context.
4035
4119
  * @summary This method checks if an operation is included in the list of available
@@ -4056,7 +4140,9 @@ class NgxComponentDirective extends LoggedClass {
4056
4140
  isAllowed(operation) {
4057
4141
  if (!this.operations)
4058
4142
  return false;
4059
- return this.operations.includes(operation) && (this.operation !== OperationKeys.CREATE && ((this.operation || "").toLowerCase() !== operation || !this.operation));
4143
+ return (this.operations.includes(operation) &&
4144
+ this.operation !== OperationKeys.CREATE &&
4145
+ ((this.operation || '').toLowerCase() !== operation || !this.operation));
4060
4146
  }
4061
4147
  /**
4062
4148
  * @description Navigates to a different operation for the current model.
@@ -4093,7 +4179,7 @@ class NgxComponentDirective extends LoggedClass {
4093
4179
  return this.router.navigateByUrl(page);
4094
4180
  }
4095
4181
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxComponentDirective, deps: [{ token: CPTKN }, { token: CPTKN }], target: i0.ɵɵFactoryTarget.Directive }); }
4096
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxComponentDirective, isStandalone: true, inputs: { enableDarkMode: "enableDarkMode", isDarkMode: "isDarkMode", name: "name", childOf: "childOf", uid: "uid", model: "model", modelId: "modelId", pk: "pk", mapper: "mapper", operations: "operations", operation: "operation", row: "row", col: "col", className: "className", locale: "locale", item: "item", props: "props", route: "route", borders: "borders", isModalChild: "isModalChild" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
4182
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxComponentDirective, isStandalone: true, inputs: { enableDarkMode: "enableDarkMode", isDarkMode: "isDarkMode", name: "name", childOf: "childOf", uid: "uid", model: "model", modelId: "modelId", value: "value", pk: "pk", mapper: "mapper", operations: "operations", operation: "operation", row: "row", col: "col", className: "className", locale: "locale", item: "item", props: "props", route: "route", borders: "borders", isModalChild: "isModalChild", handlers: "handlers", events: "events" }, outputs: { listenEvent: "listenEvent", refreshEvent: "refreshEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
4097
4183
  }
4098
4184
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxComponentDirective, decorators: [{
4099
4185
  type: Directive,
@@ -4121,6 +4207,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4121
4207
  type: Input
4122
4208
  }], modelId: [{
4123
4209
  type: Input
4210
+ }], value: [{
4211
+ type: Input
4124
4212
  }], pk: [{
4125
4213
  type: Input
4126
4214
  }], mapper: [{
@@ -4137,6 +4225,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4137
4225
  type: Input
4138
4226
  }], listenEvent: [{
4139
4227
  type: Output
4228
+ }], refreshEvent: [{
4229
+ type: Output
4140
4230
  }], locale: [{
4141
4231
  type: Input
4142
4232
  }], item: [{
@@ -4149,6 +4239,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4149
4239
  type: Input
4150
4240
  }], isModalChild: [{
4151
4241
  type: Input
4242
+ }], handlers: [{
4243
+ type: Input
4244
+ }], events: [{
4245
+ type: Input
4152
4246
  }] } });
4153
4247
 
4154
4248
  class NgxRenderableComponentDirective extends NgxComponentDirective {
@@ -4687,9 +4781,9 @@ class NgxFormFieldDirective extends NgxComponentDirective {
4687
4781
  * @return {void}
4688
4782
  * @public
4689
4783
  */
4690
- ngOnChanges(changes) {
4784
+ async ngOnChanges(changes) {
4691
4785
  if (!this.initialized)
4692
- super.ngOnChanges(changes);
4786
+ await super.ngOnChanges(changes);
4693
4787
  if (changes['activeFormGroupIndex'] && this.multiple &&
4694
4788
  !changes['activeFormGroupIndex'].isFirstChange() && changes['activeFormGroupIndex'].currentValue !== this.activeFormGroupIndex) {
4695
4789
  this.activeFormGroupIndex = changes['activeFormGroupIndex'].currentValue;
@@ -4811,8 +4905,39 @@ function Dynamic() {
4811
4905
  if (!metadata)
4812
4906
  throw new InternalError(`Could not find Component metadata. @Dynamic decorator must come above @Component`);
4813
4907
  NgxRenderingEngine.registerComponent(metadata.selector, original);
4814
- }, metadata(NgxRenderingEngine.key(AngularEngineKeys.DYNAMIC), true));
4908
+ }, metadata(Metadata.key(AngularEngineKeys.REFLECT, AngularEngineKeys.DYNAMIC), true));
4815
4909
  }
4910
+ // export interface UICustomEvents {
4911
+ // render: () => HandlerLike;
4912
+ // init: () => FunctionLike;
4913
+ // }
4914
+ // export function uion(event: string, handler: FunctionLike) {
4915
+ // return (target: any, propertyKey?: any) => {
4916
+ // const metadata = {
4917
+ // [event]: handler,
4918
+ // };
4919
+ // propMetadata(getUIAttributeKey(propertyKey, 'handlers'), metadata)(
4920
+ // target,
4921
+ // propertyKey
4922
+ // );
4923
+ // };
4924
+ // // return (model: unknown, property: unknown) => {
4925
+ // // const meta: UIHandlerMetadata = {
4926
+ // // [event]: handler,
4927
+ // // };
4928
+ // // return metadata(
4929
+ // // getUIAttributeKey(property as string, 'on'),
4930
+ // // meta
4931
+ // // )(model, property);
4932
+ // // };
4933
+ // }
4934
+ // export function uionrender(handler: FunctionLike) {
4935
+ // return uion("render", handler);
4936
+ // }
4937
+ // @uion(op, handler)
4938
+ // @uionrender(handler){
4939
+ // return uion("redenr", handler)
4940
+ // }
4816
4941
 
4817
4942
  /**
4818
4943
  * @module module:lib/components/model-renderer/model-renderer.component
@@ -4866,7 +4991,7 @@ class ModelRendererComponent extends NgxRenderableComponentDirective {
4866
4991
  * @description Refreshes the rendered model
4867
4992
  * @param {string | M} model - The model to be rendered
4868
4993
  */
4869
- refresh(model) {
4994
+ async refresh(model) {
4870
4995
  model =
4871
4996
  typeof model === 'string'
4872
4997
  ? Model.build({}, model)
@@ -4881,7 +5006,7 @@ class ModelRendererComponent extends NgxRenderableComponentDirective {
4881
5006
  * @description Lifecycle hook that is called when data-bound properties of a directive change
4882
5007
  * @param {SimpleChanges} changes - Object containing changes
4883
5008
  */
4884
- ngOnChanges(changes) {
5009
+ async ngOnChanges(changes) {
4885
5010
  if (changes[BaseComponentProps.MODEL]) {
4886
5011
  const { currentValue } = changes[BaseComponentProps.MODEL];
4887
5012
  this.refresh(currentValue);
@@ -4920,12 +5045,12 @@ class NgxParentComponentDirective extends NgxComponentDirective {
4920
5045
  constructor() {
4921
5046
  super(...arguments);
4922
5047
  /**
4923
- * @description Unique identifier for the current record.
4924
- * @summary A unique identifier for the current record being displayed or manipulated.
4925
- * This is typically used in conjunction with the primary key for operations on specific records.
4926
- *
4927
- * @type {string | number}
4928
- */
5048
+ * @description Unique identifier for the current record.
5049
+ * @summary A unique identifier for the current record being displayed or manipulated.
5050
+ * This is typically used in conjunction with the primary key for operations on specific records.
5051
+ *
5052
+ * @type {string | number}
5053
+ */
4929
5054
  this.page = 1;
4930
5055
  /**
4931
5056
  * @description Unique identifier for the current record.
@@ -5047,7 +5172,7 @@ class NgxParentComponentDirective extends NgxComponentDirective {
5047
5172
  const content = this.children[page];
5048
5173
  this.activePage = undefined;
5049
5174
  this.preloadCards = [...new Array(1)];
5050
- this.timerSubscription = timer(1).subscribe(() => this.activePage = { ...this.children[page] });
5175
+ this.timerSubscription = timer(25).subscribe(() => this.activePage = { ...this.children[page] });
5051
5176
  this.activeIndex = page;
5052
5177
  if (content)
5053
5178
  return content;
@@ -5404,6 +5529,15 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5404
5529
  * @memberOf CrudFieldComponent
5405
5530
  */
5406
5531
  this.hidden = false;
5532
+ /**
5533
+ * @description Whether the field is read-only.
5534
+ * @summary When true, the field will be rendered in a read-only state. Unlike disabled fields,
5535
+ * read-only fields are still focusable but cannot be modified by the user.
5536
+ *
5537
+ * @type {boolean}
5538
+ * @memberOf CrudFieldComponent
5539
+ */
5540
+ this.readonly = false;
5407
5541
  /**
5408
5542
  * @description Interface style for select inputs.
5409
5543
  * @summary Specifies the interface style for select inputs, such as 'alert', 'action-sheet', or 'popover'.
@@ -5561,8 +5695,11 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5561
5695
  this.options = this.options();
5562
5696
  }
5563
5697
  else {
5564
- const repo = getModelRepository(this.options?.['name']);
5565
- this.options = await repo?.select().execute();
5698
+ const repo = getModelAndRepository(this.options?.['name']);
5699
+ if (repo) {
5700
+ const { repository } = repo;
5701
+ this.options = await repository.select().execute();
5702
+ }
5566
5703
  }
5567
5704
  }
5568
5705
  }
@@ -5607,11 +5744,10 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5607
5744
  * This ensures proper initialization of read-only fields that don't require
5608
5745
  * form functionality but still need view setup.
5609
5746
  *
5610
- * @returns {void}
5747
+ * @returns {Promise<void>}
5611
5748
  * @memberOf CrudFieldComponent
5612
5749
  */
5613
- ngAfterViewInit() {
5614
- super.afterViewInit();
5750
+ async ngAfterViewInit() {
5615
5751
  if (this.type === HTML5InputTypes.RADIO && !this.value)
5616
5752
  this.setValue(this.options[0].value); // TODO: migrate to RenderingEngine
5617
5753
  }
@@ -5665,7 +5801,7 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5665
5801
  this.value = this.formControl.value;
5666
5802
  }
5667
5803
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5668
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", className: "className", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", page: "page", translatable: "translatable" }, host: { listeners: { "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)" }, properties: { "attr.id": "uid", "attr.class": "className" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if (operation === 'read' || operation === 'delete') {\n <ng-container>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon aria-hidden=\"true\" class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if (formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n [class.dcf-field-required]=\"required\"\n >\n @if (type === 'textarea') {\n <ion-textarea\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if (type === 'checkbox') {\n @if (!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if (type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if (type === 'select') {\n <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n (click)=\"openSelectOptions($event, interface)\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem;--background: transparent}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5804
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", className: "className", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", page: "page", translatable: "translatable" }, host: { listeners: { "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)" }, properties: { "attr.id": "uid", "attr.class": "className" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if (operation === 'read' || operation === 'delete') {\n <ng-container>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon aria-hidden=\"true\" class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if (formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n [class.dcf-field-required]=\"required\"\n [class.dcf-field-readonly]=\"readonly\"\n >\n @if (type === 'textarea') {\n <ion-textarea\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if (type === 'checkbox') {\n @if (!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if (type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if (type === 'select') {\n <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n (click)=\"openSelectOptions($event, interface)\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem;--background: transparent}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5669
5805
  };
5670
5806
  CrudFieldComponent = __decorate([
5671
5807
  Dynamic()
@@ -5685,7 +5821,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
5685
5821
  IonLabel,
5686
5822
  IonText,
5687
5823
  IonTextarea
5688
- ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid', '[attr.class]': 'className' }, template: "@if (operation === 'read' || operation === 'delete') {\n <ng-container>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon aria-hidden=\"true\" class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if (formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n [class.dcf-field-required]=\"required\"\n >\n @if (type === 'textarea') {\n <ion-textarea\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if (type === 'checkbox') {\n @if (!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if (type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if (type === 'select') {\n <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n (click)=\"openSelectOptions($event, interface)\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem;--background: transparent}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
5824
+ ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid', '[attr.class]': 'className' }, template: "@if (operation === 'read' || operation === 'delete') {\n <ng-container>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon aria-hidden=\"true\" class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if (formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n [class.dcf-field-required]=\"required\"\n [class.dcf-field-readonly]=\"readonly\"\n >\n @if (type === 'textarea') {\n <ion-textarea\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if (type === 'checkbox') {\n @if (!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if (type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if (type === 'select') {\n <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n (click)=\"openSelectOptions($event, interface)\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem;--background: transparent}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
5689
5825
  }], propDecorators: { operation: [{
5690
5826
  type: Input,
5691
5827
  args: [{ required: true }]
@@ -5934,7 +6070,7 @@ class NgxFormDirective extends NgxParentComponentDirective {
5934
6070
  this.formGroup = undefined;
5935
6071
  this.initialized = true;
5936
6072
  }
5937
- ngAfterViewInit() {
6073
+ async ngAfterViewInit() {
5938
6074
  if (this.isModalChild)
5939
6075
  this.changeDetectorRef.detectChanges();
5940
6076
  }
@@ -6002,7 +6138,7 @@ class NgxFormDirective extends NgxParentComponentDirective {
6002
6138
  return NgxFormService.reset(this.formGroup);
6003
6139
  this.location.back();
6004
6140
  }
6005
- async handleSubmit(event, eventName, componentName) {
6141
+ async submit(event, eventName, componentName) {
6006
6142
  if (event) {
6007
6143
  event.preventDefault();
6008
6144
  event.stopImmediatePropagation();
@@ -6108,10 +6244,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
6108
6244
  * @param {string} title - Primary title text displayed in the card header.
6109
6245
  * @param {('small'|'default'|'blank')} body - Body size preset controlling padding/typography; defaults to 'default'.
6110
6246
  * @param {string} subtitle - Optional subtitle rendered under the title.
6111
- * @param {import('@ionic/core').Color} color - Ionic color token applied to the card header/title.
6247
+ * @param {Color} color - Ionic color token applied to the card header/title.
6112
6248
  * @param {boolean} separator - When true, renders a divider between header and body.
6113
6249
  * @param {boolean} borders - Controls whether borders are rendered; defaults to true.
6114
- * @param {string|import('@angular/platform-browser').SafeHtml} inlineContent - Inline HTML/SafeHtml to render inside the body.
6250
+ * @param {string|SafeHtml} inlineContent - Inline HTML/SafeHtml to render inside the body.
6115
6251
  * @param {('top'|'bottom')} inlineContentPosition - Where to render `inlineContent` relative to the body; defaults to 'bottom'.
6116
6252
  * @return {void}
6117
6253
  * @class CardComponent
@@ -6173,7 +6309,7 @@ let CardComponent = class CardComponent extends NgxComponentDirective {
6173
6309
  /**
6174
6310
  * @description Ionic color token applied to the card.
6175
6311
  * @summary When provided, the color token (for example 'primary' or 'tertiary') is applied to title/header elements where supported.
6176
- * @type {import('@ionic/core').Color}
6312
+ * @type {Color}
6177
6313
  * @default ''
6178
6314
  */
6179
6315
  this.color = '';
@@ -6215,7 +6351,6 @@ let CardComponent = class CardComponent extends NgxComponentDirective {
6215
6351
  * @return {void}
6216
6352
  */
6217
6353
  ngOnInit() {
6218
- console.log(this.componentName, this.borders);
6219
6354
  this.mediaService.isDarkMode().subscribe(isDark => {
6220
6355
  this.isDarkMode = isDark;
6221
6356
  this.mediaService.toggleClass([this.component], AngularEngineKeys.DARK_PALETTE_CLASS, this.isDarkMode);
@@ -6473,7 +6608,7 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
6473
6608
  this.changeDetectorRef.detectChanges();
6474
6609
  }
6475
6610
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6476
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { gap: "gap", grid: "grid", flexMode: "flexMode", rowCard: "rowCard", maxColsLength: "maxColsLength" }, usesInheritance: true, ngImport: i0, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\"\n (!grid\n ? 'dcf-layout-row '\n : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap) +\n ' ' +\n (className || '')\n \"\n [class.dcf-grid-match]=\"match\"\n [class.dcf-grid-bordered]=\"borders\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{ row.title | translate }}</h3>\n </div>\n }\n @for (\n child of row.cols;\n track trackItemFn($index, child.col);\n let colIndex = $index\n ) {\n\n <div\n [class]=\"'dcf-grid-col ' + child.colClass\"\n [class.dcf-first-column]=\"$index === 0\"\n [class.dcf-layout-separator]=\"child.props?.separator ?? false\"\n >\n <div>\n\n @if (child.tag === \"ngx-decaf-crud-form\") {\n\n <ngx-decaf-card\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [parentForm]=\"parentForm || child.parentForm || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{ props: child.props }\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n</section>\n", styles: [".dcf-grid.dcf-grid-bordered>div>div{padding:var(--dcf-padding-small) var(--dcf-padding);border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-2);background:var(--dcf-card-background)!important}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-match ::ng-deep ngx-decaf-component-renderer>*>*{height:100%!important}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div.dcf-layout-separator{margin-bottom:1rem}.dcf-grid.dcf-grid-small>div.dcf-grid-bordered:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small+.dcf-grid-small.dcf-layout-separator{margin-bottom:1rem}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["projectable"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6611
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { gap: "gap", grid: "grid", flexMode: "flexMode", rowCard: "rowCard", maxColsLength: "maxColsLength" }, usesInheritance: true, ngImport: i0, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\"\n (!grid\n ? 'dcf-layout-row '\n : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap) +\n ' ' +\n (className || '')\n \"\n [class.dcf-grid-match]=\"match\"\n [class.dcf-grid-bordered]=\"borders\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{ row.title | translate }}</h3>\n </div>\n }\n @for (\n child of row.cols;\n track trackItemFn($index, child.col);\n let colIndex = $index\n ) {\n\n <div\n [class]=\"'dcf-grid-col ' + child.colClass\"\n [class.dcf-first-column]=\"$index === 0\"\n [class.dcf-layout-separator]=\"child.props?.separator ?? false\"\n >\n <div>\n\n @if (child.tag === \"ngx-decaf-crud-form\") {\n\n <ngx-decaf-card\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [parentForm]=\"parentForm || child.parentForm || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{ props: child.props }\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n</section>\n", styles: [".dcf-grid.dcf-grid-collapse.read>div{margin:var(--dcf-margin-small) 0!important}.dcf-grid.dcf-grid-bordered>div>div{padding:var(--dcf-padding-small) var(--dcf-padding);border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-2);background:var(--dcf-card-background)!important}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-match ::ng-deep ngx-decaf-component-renderer>*>*{height:100%!important}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div.dcf-layout-separator{margin-bottom:1rem}.dcf-grid.dcf-grid-small>div.dcf-grid-bordered:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small+.dcf-grid-small.dcf-layout-separator{margin-bottom:1rem}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["projectable"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6477
6612
  };
6478
6613
  LayoutComponent = __decorate([
6479
6614
  Dynamic(),
@@ -6481,7 +6616,7 @@ LayoutComponent = __decorate([
6481
6616
  ], LayoutComponent);
6482
6617
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LayoutComponent, decorators: [{
6483
6618
  type: Component,
6484
- args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, CardComponent, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\"\n (!grid\n ? 'dcf-layout-row '\n : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap) +\n ' ' +\n (className || '')\n \"\n [class.dcf-grid-match]=\"match\"\n [class.dcf-grid-bordered]=\"borders\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{ row.title | translate }}</h3>\n </div>\n }\n @for (\n child of row.cols;\n track trackItemFn($index, child.col);\n let colIndex = $index\n ) {\n\n <div\n [class]=\"'dcf-grid-col ' + child.colClass\"\n [class.dcf-first-column]=\"$index === 0\"\n [class.dcf-layout-separator]=\"child.props?.separator ?? false\"\n >\n <div>\n\n @if (child.tag === \"ngx-decaf-crud-form\") {\n\n <ngx-decaf-card\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [parentForm]=\"parentForm || child.parentForm || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{ props: child.props }\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n</section>\n", styles: [".dcf-grid.dcf-grid-bordered>div>div{padding:var(--dcf-padding-small) var(--dcf-padding);border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-2);background:var(--dcf-card-background)!important}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-match ::ng-deep ngx-decaf-component-renderer>*>*{height:100%!important}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div.dcf-layout-separator{margin-bottom:1rem}.dcf-grid.dcf-grid-small>div.dcf-grid-bordered:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small+.dcf-grid-small.dcf-layout-separator{margin-bottom:1rem}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"] }]
6619
+ args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, CardComponent, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\"\n (!grid\n ? 'dcf-layout-row '\n : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap) +\n ' ' +\n (className || '')\n \"\n [class.dcf-grid-match]=\"match\"\n [class.dcf-grid-bordered]=\"borders\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{ row.title | translate }}</h3>\n </div>\n }\n @for (\n child of row.cols;\n track trackItemFn($index, child.col);\n let colIndex = $index\n ) {\n\n <div\n [class]=\"'dcf-grid-col ' + child.colClass\"\n [class.dcf-first-column]=\"$index === 0\"\n [class.dcf-layout-separator]=\"child.props?.separator ?? false\"\n >\n <div>\n\n @if (child.tag === \"ngx-decaf-crud-form\") {\n\n <ngx-decaf-card\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [parentForm]=\"parentForm || child.parentForm || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{ props: child.props }\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n</section>\n", styles: [".dcf-grid.dcf-grid-collapse.read>div{margin:var(--dcf-margin-small) 0!important}.dcf-grid.dcf-grid-bordered>div>div{padding:var(--dcf-padding-small) var(--dcf-padding);border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-2);background:var(--dcf-card-background)!important}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-match ::ng-deep ngx-decaf-component-renderer>*>*{height:100%!important}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div.dcf-layout-separator{margin-bottom:1rem}.dcf-grid.dcf-grid-small>div.dcf-grid-bordered:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small+.dcf-grid-small.dcf-layout-separator{margin-bottom:1rem}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"] }]
6485
6620
  }], ctorParameters: () => [], propDecorators: { gap: [{
6486
6621
  type: Input
6487
6622
  }], grid: [{
@@ -6530,7 +6665,7 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
6530
6665
  });
6531
6666
  }
6532
6667
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6533
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"handleSubmit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div class=\"dcf-form-item\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if (options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
6668
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div class=\"dcf-form-item\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if (options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
6534
6669
  };
6535
6670
  CrudFormComponent = __decorate([
6536
6671
  Dynamic(),
@@ -6538,7 +6673,7 @@ CrudFormComponent = __decorate([
6538
6673
  ], CrudFormComponent);
6539
6674
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CrudFormComponent, decorators: [{
6540
6675
  type: Component,
6541
- args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"handleSubmit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div class=\"dcf-form-item\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if (options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
6676
+ args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div class=\"dcf-form-item\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if (options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
6542
6677
  }], ctorParameters: () => [] });
6543
6678
 
6544
6679
  class NgxSvgDirective {
@@ -6589,12 +6724,10 @@ let IconComponent = class IconComponent {
6589
6724
  this.type = 'image';
6590
6725
  this.isSvg = this.name.endsWith('.svg');
6591
6726
  }
6592
- this.initialized = true;
6593
- }
6594
- ngAfterViewInit() {
6595
6727
  this.mediaService.isDarkMode().subscribe(isDark => {
6596
6728
  this.isDarkMode = isDark;
6597
6729
  });
6730
+ this.initialized = true;
6598
6731
  }
6599
6732
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6600
6733
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: IconComponent, isStandalone: true, selector: "ngx-decaf-icon", inputs: { name: "name", color: "color", slot: "slot", button: "button", buttonFill: "buttonFill", buttonShape: "buttonShape", width: "width", size: "size", inline: "inline" }, host: { properties: { "attr.id": "uid", "attr.aria-hidden": "!button" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"dcf-icon\" #component>\n @if (initialized) {\n @if (button) {\n <ion-button [fill]=\"buttonFill\" [shape]=\"buttonShape\" [color]=\"isDarkMode ? 'light' : color\" [size]=\"size\">\n @if (type === \"image\") {\n @if (isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n >\n ></span\n >\n } @else {\n <img\n aria-hidden=\"true\"\n [alt]=\"name\"\n [title]=\"name\"\n [slot]=\"slot\"\n [src]=\"name\"\n [style.width]=\"width\"\n title=\"icon\"\n />\n }\n } @else {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [color]=\"isDarkMode ? 'light' : color\"\n [name]=\"name\"\n />\n }\n </ion-button>\n } @else {\n @if (type === \"image\") {\n @if (isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n >\n </span>\n } @else {\n <img\n aria-hidden=\"true\"\n [alt]=\"name\"\n [title]=\"name\"\n [slot]=\"slot\"\n [src]=\"name\"\n [style.width]=\"width\"\n title=\"icon\"\n />\n }\n }\n @if (type === \"ionic\") {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"isDarkMode ? 'light' : color\"\n [name]=\"name\"\n />\n }\n }\n }\n</div>\n", styles: ["::ng-deep .dcf-icon.dcf-palette-dark ion-icon{color:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg{fill:var(--dcf-text-color);fill-opacity:.25!important;stroke:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg *{fill:var(--dcf-color-primary)!important;stroke:var(--dcf-color-gray-1)!important}ion-button{cursor:pointer!important}.dcf-icon ion-icon:not([size]){font-size:1.35rem!important}\n"], dependencies: [{ kind: "directive", type: NgxSvgDirective, selector: "[ngx-decaf-svg]", inputs: ["ngx-decaf-svg"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }] }); }
@@ -7021,7 +7154,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7021
7154
  * @memberOf FieldsetComponent
7022
7155
  */
7023
7156
  constructor() {
7024
- super("FieldsetComponent");
7157
+ super('FieldsetComponent');
7025
7158
  /**
7026
7159
  * @description The parent component identifier for hierarchical fieldset relationships.
7027
7160
  * @summary Specifies the parent component name that this fieldset belongs to in a hierarchical
@@ -7175,6 +7308,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7175
7308
  * @memberOf FieldsetComponent
7176
7309
  */
7177
7310
  async ngOnInit() {
7311
+ console.log(this.title);
7178
7312
  await super.ngOnInit(this.model);
7179
7313
  if (this.max && this.max === 1)
7180
7314
  this.multiple = false;
@@ -7196,8 +7330,10 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7196
7330
  }
7197
7331
  if (!this.formGroup && this.parentForm instanceof FormArray)
7198
7332
  this.formGroup = this.parentForm;
7199
- if (!this.formGroup && this.children[0]?.['formGroup'] instanceof FormGroup)
7200
- this.formGroup = this.children[0]?.['formGroup'].parent;
7333
+ if (!this.formGroup &&
7334
+ this.children[0]?.['formGroup'] instanceof FormGroup)
7335
+ this.formGroup = this.children[0]?.['formGroup']
7336
+ .parent;
7201
7337
  if (this.formGroup && !(this.formGroup instanceof FormArray))
7202
7338
  this.formGroup = this.formGroup?.parent;
7203
7339
  }
@@ -7216,36 +7352,36 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7216
7352
  this.initialized = true;
7217
7353
  }
7218
7354
  /**
7219
- * @description Initializes the component state after view and child components are rendered.
7220
- * @summary This lifecycle hook implements intelligent auto-state management based on the current
7221
- * CRUD operation. For READ and DELETE operations, the fieldset automatically opens to provide
7222
- * immediate access to information, while CREATE and UPDATE operations keep it closed to maintain
7223
- * a clean initial interface. The method directly manipulates the DOM to ensure proper accordion
7224
- * synchronization and triggers change detection to reflect the programmatic state changes.
7225
- *
7226
- * @mermaid
7227
- * sequenceDiagram
7228
- * participant A as Angular Lifecycle
7229
- * participant F as FieldsetComponent
7230
- * participant D as DOM
7231
- * participant C as ChangeDetector
7232
- *
7233
- * A->>F: ngAfterViewInit()
7234
- * alt operation is READ or DELETE
7235
- * F->>F: Set isOpen = true
7236
- * F->>D: Query ion-accordion-group element
7237
- * alt accordion element exists
7238
- * F->>D: Set value attribute to 'open'
7239
- * end
7240
- * end
7241
- * F->>C: detectChanges()
7242
- * C->>F: Update view with new state
7243
- *
7244
- * @returns {void}
7245
- * @memberOf FieldsetComponent
7246
- */
7247
- ngAfterViewInit() {
7248
- super.ngAfterViewInit();
7355
+ * @description Initializes the component state after view and child components are rendered.
7356
+ * @summary This lifecycle hook implements intelligent auto-state management based on the current
7357
+ * CRUD operation. For READ and DELETE operations, the fieldset automatically opens to provide
7358
+ * immediate access to information, while CREATE and UPDATE operations keep it closed to maintain
7359
+ * a clean initial interface. The method directly manipulates the DOM to ensure proper accordion
7360
+ * synchronization and triggers change detection to reflect the programmatic state changes.
7361
+ *
7362
+ * @mermaid
7363
+ * sequenceDiagram
7364
+ * participant A as Angular Lifecycle
7365
+ * participant F as FieldsetComponent
7366
+ * participant D as DOM
7367
+ * participant C as ChangeDetector
7368
+ *
7369
+ * A->>F: ngAfterViewInit()
7370
+ * alt operation is READ or DELETE
7371
+ * F->>F: Set isOpen = true
7372
+ * F->>D: Query ion-accordion-group element
7373
+ * alt accordion element exists
7374
+ * F->>D: Set value attribute to 'open'
7375
+ * end
7376
+ * end
7377
+ * F->>C: detectChanges()
7378
+ * C->>F: Update view with new state
7379
+ *
7380
+ * @returns {Promise<void>}
7381
+ * @memberOf FieldsetComponent
7382
+ */
7383
+ async ngAfterViewInit() {
7384
+ await super.ngAfterViewInit();
7249
7385
  // if (!this.collapsable)
7250
7386
  // this.isOpen = true;
7251
7387
  // if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE) {
@@ -7266,6 +7402,29 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7266
7402
  // this.formGroup = (this.formGroup as FormGroup)
7267
7403
  // this.changeDetectorRef.detectChanges();
7268
7404
  }
7405
+ async refresh() {
7406
+ this.refreshing = true;
7407
+ this.changeDetectorRef.detectChanges();
7408
+ if ([OperationKeys.READ, OperationKeys.DELETE].includes(this.operation)) {
7409
+ // if(!this.multiple) {
7410
+ // this.required = this.collapsable = false;
7411
+ // }
7412
+ this.items = [...this.value.map((v) => {
7413
+ return this.children.map((child) => {
7414
+ const { props, tag } = child;
7415
+ return {
7416
+ tag,
7417
+ props: {
7418
+ ...props,
7419
+ value: v[props.name] || ""
7420
+ }
7421
+ };
7422
+ });
7423
+ })];
7424
+ }
7425
+ this.refreshing = false;
7426
+ this.changeDetectorRef.detectChanges();
7427
+ }
7269
7428
  /**
7270
7429
  * @description Handles removal of the fieldset with slide animation.
7271
7430
  * @summary Initiates the removal process for the fieldset with a smooth slide-up animation.
@@ -7326,7 +7485,9 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7326
7485
  const value = formGroup.value;
7327
7486
  const hasSomeValue = this.hasValue(value);
7328
7487
  if (hasSomeValue) {
7329
- const action = this.updatingItem ? OperationKeys.UPDATE : OperationKeys.CREATE;
7488
+ const action = this.updatingItem
7489
+ ? OperationKeys.UPDATE
7490
+ : OperationKeys.CREATE;
7330
7491
  const isValid = NgxFormService.validateFields(formGroup);
7331
7492
  // must pass correct pk here
7332
7493
  const isUnique = NgxFormService.isUniqueOnGroup(formGroup, action, action === OperationKeys.UPDATE ? this.updatingItem?.index : undefined);
@@ -7336,12 +7497,15 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7336
7497
  this.isUniqueError = this.updatingItem = undefined;
7337
7498
  this.setValue();
7338
7499
  NgxFormService.addGroupToParent(formGroup.parent);
7339
- this.activeFormGroupIndex = formGroup.parent.length - 1;
7500
+ this.activeFormGroupIndex =
7501
+ formGroup.parent.length - 1;
7340
7502
  this.activePage = this.getActivePage();
7341
7503
  }
7342
7504
  else {
7343
- this.isUniqueError = typeof value === ReservedModels.OBJECT ?
7344
- value?.[this.pk] || undefined : value;
7505
+ this.isUniqueError =
7506
+ typeof value === ReservedModels.OBJECT.name.toLowerCase()
7507
+ ? value?.[this.pk] || undefined
7508
+ : value;
7345
7509
  }
7346
7510
  }
7347
7511
  }
@@ -7387,7 +7551,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7387
7551
  const formArray = this.formGroup;
7388
7552
  if (formArray.length === 1) {
7389
7553
  const currentGroup = formArray.at(0);
7390
- Object.keys(currentGroup?.controls).forEach(controlName => {
7554
+ Object.keys(currentGroup?.controls).forEach((controlName) => {
7391
7555
  currentGroup.get(controlName)?.setValue(null);
7392
7556
  });
7393
7557
  }
@@ -7430,7 +7594,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7430
7594
  // reorder visual data
7431
7595
  const itemToMove = items.splice(fromIndex, 1)[0];
7432
7596
  items.splice(toIndex, 0, itemToMove);
7433
- items.forEach((item, index) => item['index'] = index + 1);
7597
+ items.forEach((item, index) => (item['index'] = index + 1));
7434
7598
  // reorder FormArray controls
7435
7599
  const controlToMove = formArray.at(fromIndex);
7436
7600
  formArray.removeAt(fromIndex);
@@ -7514,14 +7678,17 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7514
7678
  this.accordionComponent.value = 'open';
7515
7679
  this.changeDetectorRef.detectChanges();
7516
7680
  this.timerSubscription = timer(10).subscribe(() => {
7517
- this.children = this.children.map(child => {
7681
+ this.children = this.children.map((child) => {
7518
7682
  if (!child.props)
7519
7683
  child.props = {};
7520
- child.props = Object.assign(child.props, { activeFormGroup: this.activeFormGroupIndex, multiple: this.multiple });
7684
+ child.props = Object.assign(child.props, {
7685
+ activeFormGroup: this.activeFormGroupIndex,
7686
+ multiple: this.multiple,
7687
+ });
7521
7688
  return child;
7522
7689
  });
7523
7690
  });
7524
- if (this.multiple)
7691
+ if (this.multiple && [OperationKeys.CREATE, OperationKeys.UPDATE].includes(this.operation))
7525
7692
  this.getFormArrayIndex(this.activeFormGroupIndex);
7526
7693
  return this.children;
7527
7694
  }
@@ -7538,11 +7705,11 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7538
7705
  setValue() {
7539
7706
  this.value = this.formGroup.controls.map(({ value }) => value);
7540
7707
  this.items = this.value
7541
- .filter(v => (v[this.pk] || "").trim().length)
7708
+ .filter((v) => (v[this.pk] || '').trim().length)
7542
7709
  .map((v, index) => {
7543
7710
  return {
7544
7711
  ...itemMapper(Object.assign({}, v), this.mapper),
7545
- index: index + 1
7712
+ index: index + 1,
7546
7713
  };
7547
7714
  });
7548
7715
  this.updatingItem = undefined;
@@ -7563,9 +7730,10 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7563
7730
  this.pk = Object.keys(value)[0];
7564
7731
  if (!Object.keys(this.mapper).length)
7565
7732
  this.mapper['title'] = this.pk;
7566
- this.mapper['index'] = "index";
7733
+ this.mapper['index'] = 'index';
7567
7734
  for (const key in value) {
7568
- if (Object.keys(this.mapper).length >= 2 || Object.keys(this.mapper).length === Object.keys(value).length)
7735
+ if (Object.keys(this.mapper).length >= 2 ||
7736
+ Object.keys(this.mapper).length === Object.keys(value).length)
7569
7737
  break;
7570
7738
  if (!this.mapper['title']) {
7571
7739
  this.mapper['title'] = key;
@@ -7577,7 +7745,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7577
7745
  return this.mapper;
7578
7746
  }
7579
7747
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7580
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders", max: "max", required: "required", ordenable: "ordenable", editable: "editable" }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.dcf-not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable || required) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion\n value=\"open\"\n [class.dcf-disabled]=\"!activePage\"\n [class.dcf-empty]=\"!items?.length\"\n >\n @if (collapsable && !required) {\n <ion-item slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable && multiple) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleClear($event)\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n }\n\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (activePage) {\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"activePage?.borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [hidden]=\"items.length === max && !updatingItem\"\n />\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(ordenable) {\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon aria-hidden=\"true\" name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon aria-hidden=\"true\" class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n }\n\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n\n @if(editable) {\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"create-outline\" color=\"dark\" ></ion-icon>\n </ion-button>\n }\n }\n\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleRemoveItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"close-outline\" color=\"dark\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon aria-hidden=\"true\" name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\" [class.dcf-not-collapsable]=\"!collapsable\" [class.dcf-empty]=\"!activePage\" [class.dcf-blank]=\"!borders\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ locale + '.cancel' | translate }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n }\n }\n </div>\n }\n </div>\n</fieldset>\n\n", styles: ["ion-accordion ion-item[slot=header] .dcf-delete{width:30px}ion-accordion ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}ion-accordion.dcf-disabled [slot=content]{padding-bottom:0rem!important}ion-accordion.dcf-empty,ion-accordion.dcf-disabled{opacity:1!important}ion-accordion.dcf-empty ::ng-deep .ion-accordion-toggle-icon,ion-accordion.dcf-disabled ::ng-deep .ion-accordion-toggle-icon{display:none!important}ion-accordion.dcf-empty .dcf-delete,ion-accordion.dcf-disabled .dcf-delete{display:none!important}ion-accordion.dcf-empty ion-item[slot=header],ion-accordion.dcf-disabled ion-item[slot=header]{pointer-events:none;cursor:default!important}.dcf-not-collapsable .dcf-max-message-container{margin:.75rem;margin-top:0rem!important}.dcf-not-collapsable .dcf-max-message-container+.dcf-buttons-container{margin-top:var(--dcf-margin-small)!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component *{overflow-x:hidden!important}.dcf-fieldset-component ion-accordion:not(.dcf-empty){background:var(--dcf-card-background)!important}.dcf-fieldset-component ion-accordion ion-item{--background-hover: transparent !important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component.read [slot=header],.dcf-fieldset-component.delete [slot=header]{margin-bottom:0rem!important}.dcf-fieldset-component [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .65rem;--color: var(--ion-color-text) !important;margin:unset}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-weight:500;font-size:1rem;line-height:1.5rem;font-weight:600;margin:0;color:var(--ion-color-text)!important}.dcf-fieldset-component .dcf-title{padding:.8rem!important}.dcf-fieldset-component [slot=content]{padding:var(--dcf-padding-small) .25rem!important}.dcf-fieldset-component [slot=content]>div{padding-top:.25rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{margin-top:.125rem}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small) .75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important;margin-top:-.5rem;padding:0rem .125rem}.dcf-buttons-container:not(.dcf-blank){padding-bottom:var(--dcf-padding-small)!important}.dcf-buttons-container.dcf-not-collapsable.dcf-empty{position:relative;top:-1rem!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
7748
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders", max: "max", required: "required", ordenable: "ordenable", editable: "editable" }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n <fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.dcf-not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable || required) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion\n value=\"open\"\n [class.dcf-disabled]=\"!activePage\"\n [class.dcf-empty]=\"!items?.length\"\n >\n @if (collapsable && !required) {\n <ion-item slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable && multiple) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleClear($event)\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n }\n\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (['create', 'update'].includes(operation) || !multiple) {\n @if(activePage) {\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"activePage?.borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [hidden]=\"items.length === max && !updatingItem\"\n />\n </div>\n }\n } @else {\n @if(refreshing) {\n <div class=\"dcf-loading-container\">\n <ion-spinner name=\"crescent\" color=\"primary\"></ion-spinner>\n </div>\n } @else {\n @if(!items.length) {\n <div class=\"dcf-padding-xsmall\">\n <ion-text class=\"dcf-text-small\">{{ locale + '.empty' | translate }}</ion-text>\n </div>\n } @else {\n @for(item of items; track trackItemFn($index, item)) {\n <div class=\"dcf-fieldset-item\">\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested ' + operation\"\n [flexMode]=\"item?.props?.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'collapse'\"\n [children]=\"item || []\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"item?.props?.borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n />\n </div>\n </div>\n }\n }\n }\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(ordenable) {\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon aria-hidden=\"true\" name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon aria-hidden=\"true\" class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n }\n\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n\n @if(editable) {\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"create-outline\" color=\"dark\" ></ion-icon>\n </ion-button>\n }\n }\n\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleRemoveItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"close-outline\" color=\"dark\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon aria-hidden=\"true\" name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n\n @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\" [class.dcf-not-collapsable]=\"!collapsable\" [class.dcf-empty]=\"!activePage\" [class.dcf-blank]=\"!borders\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ locale + '.cancel' | translate }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n }\n }\n </div>\n }\n </div>\n </fieldset>\n\n\n", styles: [".dcf-fieldset-item{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small);padding:var(--dcf-padding-small) var(--dcf-padding-xsmall);padding-bottom:0;margin-bottom:var(--dcf-margin-small)}.dcf-loading-container{height:50%;display:flex;justify-content:center;align-items:center}.dcf-loading-container ion-spinner{width:30px;height:30px}ion-accordion{background:transparent!important;--background: transparent !important}ion-accordion ion-item[slot=header] .dcf-delete{width:30px}ion-accordion ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}ion-accordion.dcf-disabled [slot=content]{padding-bottom:0rem!important}ion-accordion.dcf-empty,ion-accordion.dcf-disabled{opacity:1!important}ion-accordion.dcf-empty ::ng-deep .ion-accordion-toggle-icon,ion-accordion.dcf-disabled ::ng-deep .ion-accordion-toggle-icon{display:none!important}ion-accordion.dcf-empty .dcf-delete,ion-accordion.dcf-disabled .dcf-delete{display:none!important}ion-accordion.dcf-empty ion-item[slot=header],ion-accordion.dcf-disabled ion-item[slot=header]{pointer-events:none;cursor:default!important}.dcf-not-collapsable .dcf-max-message-container{margin:.75rem;margin-top:0rem!important}.dcf-not-collapsable .dcf-max-message-container+.dcf-buttons-container{margin-top:var(--dcf-margin-small)!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component *{overflow-x:hidden!important}.dcf-fieldset-component ion-accordion ion-item{--background-hover: transparent !important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component.read [slot=header],.dcf-fieldset-component.delete [slot=header]{margin-bottom:0rem!important}.dcf-fieldset-component [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .65rem;--color: var(--ion-color-text) !important;margin:unset}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-weight:500;font-size:1rem;line-height:1.5rem;font-weight:600;margin:0;color:var(--ion-color-text)!important}.dcf-fieldset-component .dcf-title{padding:.8rem!important}.dcf-fieldset-component [slot=content]{padding:var(--dcf-padding-small) .25rem!important;background:transparent!important;--background: transparent !important}.dcf-fieldset-component [slot=content]>div{padding-top:.25rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{margin-top:.125rem}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small) .75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important;margin-top:-.5rem;padding:0rem .125rem}.dcf-buttons-container:not(.dcf-blank){padding-bottom:var(--dcf-padding-small)!important}.dcf-buttons-container.dcf-not-collapsable.dcf-empty{position:relative;top:-1rem!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
7581
7749
  };
7582
7750
  FieldsetComponent = __decorate([
7583
7751
  Dynamic(),
@@ -7598,8 +7766,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
7598
7766
  IonReorderGroup,
7599
7767
  IonButton,
7600
7768
  IonIcon,
7601
- LayoutComponent
7602
- ], template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.dcf-not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable || required) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion\n value=\"open\"\n [class.dcf-disabled]=\"!activePage\"\n [class.dcf-empty]=\"!items?.length\"\n >\n @if (collapsable && !required) {\n <ion-item slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable && multiple) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleClear($event)\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n }\n\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (activePage) {\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"activePage?.borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [hidden]=\"items.length === max && !updatingItem\"\n />\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(ordenable) {\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon aria-hidden=\"true\" name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon aria-hidden=\"true\" class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n }\n\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n\n @if(editable) {\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"create-outline\" color=\"dark\" ></ion-icon>\n </ion-button>\n }\n }\n\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleRemoveItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"close-outline\" color=\"dark\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon aria-hidden=\"true\" name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\" [class.dcf-not-collapsable]=\"!collapsable\" [class.dcf-empty]=\"!activePage\" [class.dcf-blank]=\"!borders\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ locale + '.cancel' | translate }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n }\n }\n </div>\n }\n </div>\n</fieldset>\n\n", styles: ["ion-accordion ion-item[slot=header] .dcf-delete{width:30px}ion-accordion ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}ion-accordion.dcf-disabled [slot=content]{padding-bottom:0rem!important}ion-accordion.dcf-empty,ion-accordion.dcf-disabled{opacity:1!important}ion-accordion.dcf-empty ::ng-deep .ion-accordion-toggle-icon,ion-accordion.dcf-disabled ::ng-deep .ion-accordion-toggle-icon{display:none!important}ion-accordion.dcf-empty .dcf-delete,ion-accordion.dcf-disabled .dcf-delete{display:none!important}ion-accordion.dcf-empty ion-item[slot=header],ion-accordion.dcf-disabled ion-item[slot=header]{pointer-events:none;cursor:default!important}.dcf-not-collapsable .dcf-max-message-container{margin:.75rem;margin-top:0rem!important}.dcf-not-collapsable .dcf-max-message-container+.dcf-buttons-container{margin-top:var(--dcf-margin-small)!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component *{overflow-x:hidden!important}.dcf-fieldset-component ion-accordion:not(.dcf-empty){background:var(--dcf-card-background)!important}.dcf-fieldset-component ion-accordion ion-item{--background-hover: transparent !important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component.read [slot=header],.dcf-fieldset-component.delete [slot=header]{margin-bottom:0rem!important}.dcf-fieldset-component [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .65rem;--color: var(--ion-color-text) !important;margin:unset}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-weight:500;font-size:1rem;line-height:1.5rem;font-weight:600;margin:0;color:var(--ion-color-text)!important}.dcf-fieldset-component .dcf-title{padding:.8rem!important}.dcf-fieldset-component [slot=content]{padding:var(--dcf-padding-small) .25rem!important}.dcf-fieldset-component [slot=content]>div{padding-top:.25rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{margin-top:.125rem}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small) .75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important;margin-top:-.5rem;padding:0rem .125rem}.dcf-buttons-container:not(.dcf-blank){padding-bottom:var(--dcf-padding-small)!important}.dcf-buttons-container.dcf-not-collapsable.dcf-empty{position:relative;top:-1rem!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\n"] }]
7769
+ LayoutComponent,
7770
+ IonSpinner
7771
+ ], template: "\n\n <fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.dcf-not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable || required) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion\n value=\"open\"\n [class.dcf-disabled]=\"!activePage\"\n [class.dcf-empty]=\"!items?.length\"\n >\n @if (collapsable && !required) {\n <ion-item slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable && multiple) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleClear($event)\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n }\n\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (['create', 'update'].includes(operation) || !multiple) {\n @if(activePage) {\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"activePage?.borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [hidden]=\"items.length === max && !updatingItem\"\n />\n </div>\n }\n } @else {\n @if(refreshing) {\n <div class=\"dcf-loading-container\">\n <ion-spinner name=\"crescent\" color=\"primary\"></ion-spinner>\n </div>\n } @else {\n @if(!items.length) {\n <div class=\"dcf-padding-xsmall\">\n <ion-text class=\"dcf-text-small\">{{ locale + '.empty' | translate }}</ion-text>\n </div>\n } @else {\n @for(item of items; track trackItemFn($index, item)) {\n <div class=\"dcf-fieldset-item\">\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested ' + operation\"\n [flexMode]=\"item?.props?.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'collapse'\"\n [children]=\"item || []\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"item?.props?.borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n />\n </div>\n </div>\n }\n }\n }\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(ordenable) {\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon aria-hidden=\"true\" name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon aria-hidden=\"true\" class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n }\n\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n\n @if(editable) {\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"create-outline\" color=\"dark\" ></ion-icon>\n </ion-button>\n }\n }\n\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleRemoveItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"close-outline\" color=\"dark\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon aria-hidden=\"true\" name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n\n @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\" [class.dcf-not-collapsable]=\"!collapsable\" [class.dcf-empty]=\"!activePage\" [class.dcf-blank]=\"!borders\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ locale + '.cancel' | translate }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n }\n }\n </div>\n }\n </div>\n </fieldset>\n\n\n", styles: [".dcf-fieldset-item{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small);padding:var(--dcf-padding-small) var(--dcf-padding-xsmall);padding-bottom:0;margin-bottom:var(--dcf-margin-small)}.dcf-loading-container{height:50%;display:flex;justify-content:center;align-items:center}.dcf-loading-container ion-spinner{width:30px;height:30px}ion-accordion{background:transparent!important;--background: transparent !important}ion-accordion ion-item[slot=header] .dcf-delete{width:30px}ion-accordion ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}ion-accordion.dcf-disabled [slot=content]{padding-bottom:0rem!important}ion-accordion.dcf-empty,ion-accordion.dcf-disabled{opacity:1!important}ion-accordion.dcf-empty ::ng-deep .ion-accordion-toggle-icon,ion-accordion.dcf-disabled ::ng-deep .ion-accordion-toggle-icon{display:none!important}ion-accordion.dcf-empty .dcf-delete,ion-accordion.dcf-disabled .dcf-delete{display:none!important}ion-accordion.dcf-empty ion-item[slot=header],ion-accordion.dcf-disabled ion-item[slot=header]{pointer-events:none;cursor:default!important}.dcf-not-collapsable .dcf-max-message-container{margin:.75rem;margin-top:0rem!important}.dcf-not-collapsable .dcf-max-message-container+.dcf-buttons-container{margin-top:var(--dcf-margin-small)!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component *{overflow-x:hidden!important}.dcf-fieldset-component ion-accordion ion-item{--background-hover: transparent !important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component.read [slot=header],.dcf-fieldset-component.delete [slot=header]{margin-bottom:0rem!important}.dcf-fieldset-component [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .65rem;--color: var(--ion-color-text) !important;margin:unset}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-weight:500;font-size:1rem;line-height:1.5rem;font-weight:600;margin:0;color:var(--ion-color-text)!important}.dcf-fieldset-component .dcf-title{padding:.8rem!important}.dcf-fieldset-component [slot=content]{padding:var(--dcf-padding-small) .25rem!important;background:transparent!important;--background: transparent !important}.dcf-fieldset-component [slot=content]>div{padding-top:.25rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{margin-top:.125rem}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small) .75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important;margin-top:-.5rem;padding:0rem .125rem}.dcf-buttons-container:not(.dcf-blank){padding-bottom:var(--dcf-padding-small)!important}.dcf-buttons-container.dcf-not-collapsable.dcf-empty{position:relative;top:-1rem!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\n"] }]
7603
7772
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
7604
7773
  type: ViewChild,
7605
7774
  args: ['accordionComponent', { static: false }]
@@ -8172,7 +8341,7 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8172
8341
  * @memberOf FilterComponent
8173
8342
  */
8174
8343
  constructor() {
8175
- super("FilterComponent");
8344
+ super('FilterComponent');
8176
8345
  /**
8177
8346
  * @description Available field indexes for filtering operations.
8178
8347
  * @summary Defines the list of field names that users can filter by. These represent
@@ -8195,7 +8364,14 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8195
8364
  * @default []
8196
8365
  * @memberOf FilterComponent
8197
8366
  */
8198
- this.conditions = ['Equal', 'Contains', 'Not Contains', 'Greater Than', 'Less Than', 'Not Equal'];
8367
+ this.conditions = [
8368
+ 'Equal',
8369
+ 'Contains',
8370
+ 'Not Contains',
8371
+ 'Greater Than',
8372
+ 'Less Than',
8373
+ 'Not Equal',
8374
+ ];
8199
8375
  /**
8200
8376
  * @description Available sorting options for the filtered data.
8201
8377
  * @summary Defines the list of field names that can be used for sorting the filtered results.
@@ -8328,7 +8504,15 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8328
8504
  * @memberOf FilterComponent
8329
8505
  */
8330
8506
  this.searchEvent = new EventEmitter();
8331
- addIcons({ chevronDownOutline, trashOutline, closeOutline, searchOutline, arrowDownOutline, arrowUpOutline, chevronUpOutline });
8507
+ addIcons({
8508
+ chevronDownOutline,
8509
+ trashOutline,
8510
+ closeOutline,
8511
+ searchOutline,
8512
+ arrowDownOutline,
8513
+ arrowUpOutline,
8514
+ chevronUpOutline,
8515
+ });
8332
8516
  }
8333
8517
  /**
8334
8518
  * @description Initializes the component after Angular first displays the data-bound properties.
@@ -8377,11 +8561,13 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8377
8561
  */
8378
8562
  getIndexes() {
8379
8563
  if (this.model)
8380
- this.indexes = Object.keys(Repository.indexes(this.model) || {});
8564
+ this.indexes = Object.keys(Model.indexes(this.model) || {});
8381
8565
  if (!this.disableSort) {
8382
8566
  this.sortBy = [...this.sortBy, ...this.indexes];
8383
- if (this.repository)
8384
- this.sortValue = this.repository.pk || this.sortValue;
8567
+ if (this.repository) {
8568
+ const pk = Model.pk(this.repository.class);
8569
+ this.sortValue = pk || this.sortValue;
8570
+ }
8385
8571
  }
8386
8572
  }
8387
8573
  /**
@@ -8513,13 +8699,13 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8513
8699
  *
8514
8700
  * @memberOf FilterComponent
8515
8701
  */
8516
- addFilter(value, event) {
8702
+ async addFilter(value, event) {
8517
8703
  value = value.trim();
8518
8704
  if (event instanceof KeyboardEvent && !value) {
8519
8705
  this.submit();
8520
8706
  }
8521
8707
  else {
8522
- if ((value && (!(event instanceof KeyboardEvent)) || this.step === 3)) {
8708
+ if ((value && !(event instanceof KeyboardEvent)) || this.step === 3) {
8523
8709
  const filter = this.lastFilter;
8524
8710
  switch (this.step) {
8525
8711
  case 1:
@@ -8547,7 +8733,7 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8547
8733
  this.filterValue[this.filterValue.length - 1] = filter;
8548
8734
  this.lastFilter = {};
8549
8735
  if (!this.multiple)
8550
- return this.submit();
8736
+ return await this.submit();
8551
8737
  }
8552
8738
  this.step++;
8553
8739
  this.value = '';
@@ -8581,7 +8767,8 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8581
8767
  * @memberOf FilterComponent
8582
8768
  */
8583
8769
  allowClear(option) {
8584
- return this.indexes.indexOf(option) === -1 && this.conditions.indexOf(option) === -1;
8770
+ return (this.indexes.indexOf(option) === -1 &&
8771
+ this.conditions.indexOf(option) === -1);
8585
8772
  }
8586
8773
  /**
8587
8774
  * @description Removes a complete filter from the collection based on filter value.
@@ -8610,11 +8797,11 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8610
8797
  function cleanString(filter) {
8611
8798
  return filter
8612
8799
  .toLowerCase() // convert all characters to lowercase
8613
- .normalize("NFD") // separate accent marks from characters
8614
- .replace(/[\u0300-\u036f]/g, "") // remove accent marks
8615
- .replace(/\s+/g, ""); // remove all whitespace
8800
+ .normalize('NFD') // separate accent marks from characters
8801
+ .replace(/[\u0300-\u036f]/g, '') // remove accent marks
8802
+ .replace(/\s+/g, ''); // remove all whitespace
8616
8803
  }
8617
- this.value = "";
8804
+ this.value = '';
8618
8805
  this.filterValue = this.filterValue.filter((item) => item?.['value'] && cleanString(item?.['value']) !== cleanString(filter));
8619
8806
  if (this.filterValue.length === 0) {
8620
8807
  this.step = 1;
@@ -8659,16 +8846,16 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8659
8846
  * @summary Emits the current filter array to parent components when filters are ready
8660
8847
  * to be applied. Only emits if there are active filters. Clears options after submission.
8661
8848
  *
8662
- * @returns {void}
8849
+ * @returns {Promise<void>}
8663
8850
  * @memberOf FilterComponent
8664
8851
  */
8665
- submit() {
8852
+ async submit() {
8666
8853
  this.filterEvent.emit({
8667
8854
  query: this.filterValue.length > 0 ? this.filterValue : undefined,
8668
8855
  sort: {
8669
8856
  value: this.sortValue,
8670
- direction: this.sortDirection
8671
- }
8857
+ direction: this.sortDirection,
8858
+ },
8672
8859
  });
8673
8860
  if (this.filterValue.length === 0)
8674
8861
  this.options = [];
@@ -8683,7 +8870,9 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8683
8870
  * @memberOf FilterComponent
8684
8871
  */
8685
8872
  handleSortDirectionChange() {
8686
- const direction = this.sortDirection === OrderDirection.ASC ? OrderDirection.DSC : OrderDirection.ASC;
8873
+ const direction = this.sortDirection === OrderDirection.ASC
8874
+ ? OrderDirection.DSC
8875
+ : OrderDirection.ASC;
8687
8876
  if (direction !== this.sortDirection) {
8688
8877
  this.sortDirection = direction;
8689
8878
  this.submit();
@@ -8745,7 +8934,9 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
8745
8934
  }
8746
8935
  const options = optionsElement.querySelectorAll('.dcf-item');
8747
8936
  for (const option of options) {
8748
- const isActive = option.textContent?.toLowerCase().includes(value.toLowerCase());
8937
+ const isActive = option.textContent
8938
+ ?.toLowerCase()
8939
+ .includes(value.toLowerCase());
8749
8940
  if (isActive) {
8750
8941
  option.classList.add('dcf-filtering-item');
8751
8942
  break;
@@ -8784,7 +8975,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
8784
8975
  IonSelect,
8785
8976
  IonSelectOption,
8786
8977
  IonIcon,
8787
- SearchbarComponent
8978
+ SearchbarComponent,
8788
8979
  ], standalone: true, host: { '[attr.id]': 'uid' }, template: "\n@if (!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-component\" [class.dcf-hidden]=\"!indexes.length\" #component>\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if (filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if (filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if (filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon tabindex=\"0\" name=\"close-outline\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n id=\"dcf-filter-field\"\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n\n />\n @if (windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if (filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon aria-hidden=\"true\" name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if (windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'light'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [":host{position:relative;z-index:1000!important}:host *{z-index:1000!important}.dcf-filter-component{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-input input{color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown{background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-filter ::-webkit-input-placeholder,.dcf-filter-component.dcf-palette-dark .dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter-component.dcf-palette-dark .dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark .dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter-component.dcf-palette-dark ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-input input{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}\n"] }]
8789
8980
  }], ctorParameters: () => [], propDecorators: { optionsFilterElement: [{
8790
8981
  type: ViewChild,
@@ -9203,7 +9394,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9203
9394
  * @memberOf ListComponent
9204
9395
  */
9205
9396
  constructor() {
9206
- super("ListComponent");
9397
+ super('ListComponent');
9207
9398
  /**
9208
9399
  * @description The display mode for the list component.
9209
9400
  * @summary Determines how the list data is loaded and displayed. Options include:
@@ -9279,7 +9470,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9279
9470
  * @default "full"
9280
9471
  * @memberOf ListComponent
9281
9472
  */
9282
- this.lines = "full";
9473
+ this.lines = 'full';
9283
9474
  /**
9284
9475
  * @description Controls whether the list has inset styling.
9285
9476
  * @summary When set to true, the list will have inset styling with rounded corners
@@ -9300,7 +9491,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9300
9491
  * @default "15%"
9301
9492
  * @memberOf ListComponent
9302
9493
  */
9303
- this.scrollThreshold = "15%";
9494
+ this.scrollThreshold = '15%';
9304
9495
  /**
9305
9496
  * @description The position where new items are added during infinite scrolling.
9306
9497
  * @summary Determines whether new items are added to the top or bottom of the list
@@ -9310,7 +9501,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9310
9501
  * @default "bottom"
9311
9502
  * @memberOf ListComponent
9312
9503
  */
9313
- this.scrollPosition = "bottom";
9504
+ this.scrollPosition = 'bottom';
9314
9505
  /**
9315
9506
  * @description Controls the visibility of the pull-to-refresh feature.
9316
9507
  * @summary When set to true, enables the pull-to-refresh functionality that allows
@@ -9339,7 +9530,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9339
9530
  * @default "circular"
9340
9531
  * @memberOf ListComponent
9341
9532
  */
9342
- this.loadingSpinner = "circular";
9533
+ this.loadingSpinner = 'circular';
9343
9534
  // /**
9344
9535
  // * @description Query parameters for data fetching.
9345
9536
  // * @summary Specifies additional query parameters to use when fetching data from
@@ -9408,17 +9599,6 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9408
9599
  * @memberOf ListComponent
9409
9600
  */
9410
9601
  this.page = 1;
9411
- /**
9412
- * @description Indicates whether a refresh operation is in progress.
9413
- * @summary When true, the component is currently fetching new data. This is used
9414
- * to control loading indicators and prevent duplicate refresh operations from
9415
- * being triggered simultaneously.
9416
- *
9417
- * @type {boolean}
9418
- * @default false
9419
- * @memberOf ListComponent
9420
- */
9421
- this.refreshing = false;
9422
9602
  /**
9423
9603
  * @description Array used for rendering skeleton loading placeholders.
9424
9604
  * @summary Contains placeholder items that are displayed during data loading.
@@ -9440,15 +9620,6 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9440
9620
  * @memberOf ListComponent
9441
9621
  */
9442
9622
  this.lastPage = 1;
9443
- /**
9444
- * @description Event emitter for refresh operations.
9445
- * @summary Emits an event when the list data is refreshed, either through pull-to-refresh
9446
- * or programmatic refresh. The event includes the refreshed data and component information.
9447
- *
9448
- * @type {EventEmitter<IBaseCustomEvent>}
9449
- * @memberOf ListComponent
9450
- */
9451
- this.refreshEvent = new EventEmitter();
9452
9623
  /**
9453
9624
  * @description Event emitter for item click interactions.
9454
9625
  * @summary Emits an event when a list item is clicked. The event includes the data
@@ -9509,9 +9680,15 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9509
9680
  * @memberOf ListComponent
9510
9681
  */
9511
9682
  async ngOnInit() {
9512
- this.observer = { refresh: async (...args) => this.observeRepository(...args) };
9513
- this.clickItemSubject.pipe(debounceTime(100)).subscribe(event => this.clickEventEmit(event));
9514
- this.observerSubjet.pipe(debounceTime(100)).subscribe(args => this.handleObserveEvent(args[0], args[1], args[2]));
9683
+ this.observer = {
9684
+ refresh: async (...args) => this.observeRepository(...args),
9685
+ };
9686
+ this.clickItemSubject
9687
+ .pipe(debounceTime(100))
9688
+ .subscribe((event) => this.clickEventEmit(event));
9689
+ this.observerSubjet
9690
+ .pipe(debounceTime(100))
9691
+ .subscribe((args) => this.handleObserveEvent(args[0], args[1], args[2]));
9515
9692
  this.limit = Number(this.limit);
9516
9693
  this.start = Number(this.start);
9517
9694
  this.enableFilter = stringToBoolean(this.enableFilter);
@@ -9619,7 +9796,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9619
9796
  async handleCreate(uid) {
9620
9797
  const result = await this._repository?.read(uid);
9621
9798
  const item = this.mapResults([result])[0];
9622
- this.items = this.data = [item, ...this.items || []];
9799
+ this.items = this.data = [item, ...(this.items || [])];
9623
9800
  }
9624
9801
  /**
9625
9802
  * @description Handles the update event from the repository.
@@ -9631,7 +9808,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9631
9808
  * @memberOf ListComponent
9632
9809
  */
9633
9810
  async handleUpdate(uid) {
9634
- const item = this.itemMapper(await this._repository?.read(uid) || {}, this.mapper);
9811
+ const item = this.itemMapper((await this._repository?.read(uid)) || {}, this.mapper);
9635
9812
  this.data = [];
9636
9813
  for (const key in this.items) {
9637
9814
  const child = this.items[key];
@@ -9658,7 +9835,8 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9658
9835
  handleDelete(uid, pk) {
9659
9836
  if (!pk)
9660
9837
  pk = this.pk;
9661
- this.items = this.data?.filter((item) => item['uid'] !== uid) || [];
9838
+ this.items =
9839
+ this.data?.filter((item) => item['uid'] !== uid) || [];
9662
9840
  }
9663
9841
  /**
9664
9842
  * @description Handles click events from list items.
@@ -9762,7 +9940,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9762
9940
  this.refreshEvent.emit({
9763
9941
  name: ComponentEventNames.REFRESH,
9764
9942
  data: data || [],
9765
- component: this.componentName
9943
+ component: this.componentName,
9766
9944
  });
9767
9945
  }
9768
9946
  /**
@@ -9838,10 +10016,10 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9838
10016
  // }
9839
10017
  this.refreshing = true;
9840
10018
  const start = this.page > 1 ? (this.page - 1) * this.limit : this.start;
9841
- const limit = (this.page * (this.limit > 12 ? 12 : this.limit));
9842
- this.data = !this.model ?
9843
- await this.getFromRequest(!!event, start, limit)
9844
- : await this.getFromModel(!!event);
10019
+ const limit = this.page * (this.limit > 12 ? 12 : this.limit);
10020
+ this.data = !this.model
10021
+ ? await this.getFromRequest(!!event, start, limit)
10022
+ : (await this.getFromModel(!!event));
9845
10023
  if (this.type === ListComponentsTypes.INFINITE) {
9846
10024
  if (this.page === this.pages) {
9847
10025
  if (event?.target)
@@ -9852,7 +10030,9 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9852
10030
  this.page += 1;
9853
10031
  this.refreshing = false;
9854
10032
  setTimeout(() => {
9855
- if (event?.target && event?.type !== ComponentEventNames.BACK_BUTTON_NAVIGATION)
10033
+ if (event?.target &&
10034
+ event?.type !==
10035
+ ComponentEventNames.BACK_BUTTON_NAVIGATION)
9856
10036
  event.target.complete();
9857
10037
  }, 200);
9858
10038
  }
@@ -9864,16 +10044,16 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9864
10044
  }
9865
10045
  }
9866
10046
  /**
9867
- * @description Handles pagination events from the pagination component.
9868
- * @summary Processes pagination events by updating the current page number and
9869
- * refreshing the list data to display the selected page. This method is called
9870
- * when a user interacts with the pagination controls to navigate between pages.
9871
- *
9872
- * @param {IPaginationCustomEvent} event - The pagination event containing page information
9873
- * @returns {void}
9874
- *
9875
- * @memberOf ListComponent
9876
- */
10047
+ * @description Handles pagination events from the pagination component.
10048
+ * @summary Processes pagination events by updating the current page number and
10049
+ * refreshing the list data to display the selected page. This method is called
10050
+ * when a user interacts with the pagination controls to navigate between pages.
10051
+ *
10052
+ * @param {IPaginationCustomEvent} event - The pagination event containing page information
10053
+ * @returns {void}
10054
+ *
10055
+ * @memberOf ListComponent
10056
+ */
9877
10057
  handlePaginate(event) {
9878
10058
  const { page } = event.data;
9879
10059
  this.page = page;
@@ -9911,8 +10091,11 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9911
10091
  * @memberOf ListComponent
9912
10092
  */
9913
10093
  parseSearchResults(results, search) {
9914
- const filtered = results.filter((item) => Object.values(item).some(v => {
9915
- if (v.toString().toLowerCase().includes(search?.toLowerCase()))
10094
+ const filtered = results.filter((item) => Object.values(item).some((v) => {
10095
+ if (v
10096
+ .toString()
10097
+ .toLowerCase()
10098
+ .includes(search?.toLowerCase()))
9916
10099
  return v;
9917
10100
  }));
9918
10101
  return filtered;
@@ -9931,25 +10114,31 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9931
10114
  * @memberOf ListComponent
9932
10115
  */
9933
10116
  async getFromRequest(force = false, start, limit) {
9934
- let data = [...this.data || []];
9935
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
10117
+ let data = [...(this.data || [])];
10118
+ if (!this.data?.length ||
10119
+ force ||
10120
+ this.searchValue?.length ||
10121
+ !!this.searchValue) {
9936
10122
  // (self.data as ListItem[]) = [];
9937
- if (!this.searchValue?.length && !this.searchValue) {
10123
+ if (!this.searchValue?.length &&
10124
+ !this.searchValue) {
9938
10125
  if (!this.source && !this.data?.length) {
9939
- this.logger.info('No data and source passed to infinite list');
10126
+ this.log.info('No data and source passed to infinite list');
9940
10127
  return [];
9941
10128
  }
9942
10129
  if (this.source instanceof Function) {
9943
- data = await this.source();
10130
+ data = (await this.source());
9944
10131
  if (!Array.isArray(data))
9945
10132
  data = data?.['response']?.['data'] || data?.['results'] || [];
9946
10133
  }
9947
10134
  if (!data?.length && this.data?.length)
9948
10135
  data = this.data;
9949
- this.data = [...await this.parseResult(data)];
10136
+ this.data = [...(await this.parseResult(data))];
9950
10137
  if (this.data?.length)
9951
- this.items = this.type === ListComponentsTypes.INFINITE ?
9952
- (this.items || []).concat([...this.data.slice(start, limit)]) : [...data.slice(start, limit)];
10138
+ this.items =
10139
+ this.type === ListComponentsTypes.INFINITE
10140
+ ? (this.items || []).concat([...this.data.slice(start, limit)])
10141
+ : [...data.slice(start, limit)];
9953
10142
  }
9954
10143
  else {
9955
10144
  const data = await this.parseResult(this.parseSearchResults(this.data, this.searchValue));
@@ -9959,8 +10148,11 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9959
10148
  }
9960
10149
  }
9961
10150
  else {
9962
- const data = [...await this.parseResult(this.data)];
9963
- this.items = this.type === ListComponentsTypes.INFINITE ? [...(this.items || []), ...(data || [])] : [...(data || [])];
10151
+ const data = [...(await this.parseResult(this.data))];
10152
+ this.items =
10153
+ this.type === ListComponentsTypes.INFINITE
10154
+ ? [...(this.items || []), ...(data || [])]
10155
+ : [...(data || [])];
9964
10156
  if (this.isModalChild)
9965
10157
  this.changeDetectorRef.detectChanges();
9966
10158
  }
@@ -9982,7 +10174,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9982
10174
  * @memberOf ListComponent
9983
10175
  */
9984
10176
  async getFromModel(force = false) {
9985
- let data = [...this.data || []];
10177
+ let data = [...(this.data || [])];
9986
10178
  let request = [];
9987
10179
  // getting model repository
9988
10180
  if (!this._repository) {
@@ -9991,9 +10183,13 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9991
10183
  this._repository.observe(this.observer);
9992
10184
  }
9993
10185
  const repo = this._repository;
9994
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
10186
+ if (!this.data?.length ||
10187
+ force ||
10188
+ this.searchValue?.length ||
10189
+ !!this.searchValue) {
9995
10190
  try {
9996
- if (!this.searchValue?.length && !this.searchValue) {
10191
+ if (!this.searchValue?.length &&
10192
+ !this.searchValue) {
9997
10193
  this.data = [];
9998
10194
  // const rawQuery = this.parseQuery(self.model as Repository<Model>, start, limit);
9999
10195
  // request = this.parseResult(await (this.model as any)?.paginate(start, limit));
@@ -10007,17 +10203,21 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10007
10203
  }
10008
10204
  else {
10009
10205
  if (!this.indexes)
10010
- this.indexes = (Object.values(this.mapper) || [this.pk]);
10206
+ this.indexes = Object.values(this.mapper) || [this.pk];
10011
10207
  const condition = this.parseConditions(this.searchValue);
10012
10208
  this.changeDetectorRef.detectChanges();
10013
10209
  request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
10014
10210
  data = [];
10015
10211
  this.changeDetectorRef.detectChanges();
10016
10212
  }
10017
- data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
10213
+ data =
10214
+ this.type === ListComponentsTypes.INFINITE
10215
+ ? [...data.concat(request)]
10216
+ : [...request];
10018
10217
  }
10019
10218
  catch (error) {
10020
- this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
10219
+ this.log.error(error?.message ||
10220
+ `Unable to find ${this.model} on registry. Return empty array from component`);
10021
10221
  }
10022
10222
  }
10023
10223
  if (data?.length) {
@@ -10057,7 +10257,8 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10057
10257
  */
10058
10258
  parseConditions(value) {
10059
10259
  let _condition;
10060
- if (typeof value === Primitives.STRING || typeof value === Primitives.NUMBER) {
10260
+ if (typeof value === Primitives.STRING ||
10261
+ typeof value === Primitives.NUMBER) {
10061
10262
  _condition = Condition.attribute(this.pk).eq(!isNaN(value) ? Number(value) : value);
10062
10263
  for (const index of this.indexes) {
10063
10264
  if (index === this.pk)
@@ -10084,27 +10285,28 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10084
10285
  val = Number(val);
10085
10286
  let orCondition;
10086
10287
  switch (condition) {
10087
- case "Equal":
10288
+ case 'Equal':
10088
10289
  orCondition = Condition.attribute(index).eq(val);
10089
10290
  break;
10090
- case "Not Equal":
10291
+ case 'Not Equal':
10091
10292
  orCondition = Condition.attribute(index).dif(val);
10092
10293
  break;
10093
- case "Not Contains":
10294
+ case 'Not Contains':
10094
10295
  orCondition = !Condition.attribute(index).regexp(new RegExp(`^(?!.*${val}).*$`));
10095
10296
  break;
10096
- case "Contains":
10297
+ case 'Contains':
10097
10298
  orCondition = Condition.attribute(index).regexp(val);
10098
10299
  break;
10099
- case "Greater Than":
10300
+ case 'Greater Than':
10100
10301
  orCondition = Condition.attribute(index).gte(val);
10101
10302
  break;
10102
- case "Less Than":
10303
+ case 'Less Than':
10103
10304
  orCondition = Condition.attribute(index).lte(val);
10104
10305
  break;
10105
10306
  }
10106
- _condition = (!_condition ?
10107
- orCondition : _condition.and(orCondition));
10307
+ _condition = (!_condition
10308
+ ? orCondition
10309
+ : _condition.and(orCondition));
10108
10310
  });
10109
10311
  this.sortBy = sort?.value || this.pk;
10110
10312
  this.sortDirection = sort?.direction || this.sortDirection;
@@ -10124,22 +10326,24 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10124
10326
  * @memberOf ListComponent
10125
10327
  */
10126
10328
  async parseResult(result) {
10127
- if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
10329
+ if (!Array.isArray(result) && 'page' in result && 'total' in result) {
10128
10330
  const paginator = result;
10129
10331
  try {
10130
10332
  result = await paginator.page(this.page);
10131
10333
  this.getMoreData(paginator.total);
10132
10334
  }
10133
10335
  catch (error) {
10134
- this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
10336
+ this.log.info(error?.message ||
10337
+ 'Unable to get page from paginator. Return empty array from component');
10135
10338
  result = [];
10136
10339
  }
10137
10340
  }
10138
10341
  else {
10139
10342
  this.getMoreData(result?.length || 0);
10140
10343
  }
10141
- return (Object.keys(this.mapper || {}).length) ?
10142
- this.mapResults(result) : result;
10344
+ return Object.keys(this.mapper || {}).length
10345
+ ? this.mapResults(result)
10346
+ : result;
10143
10347
  }
10144
10348
  /**
10145
10349
  * @description Updates pagination state based on data length.
@@ -10161,7 +10365,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10161
10365
  }
10162
10366
  else {
10163
10367
  this.pages = Math.floor(length / this.limit);
10164
- if ((this.pages * this.limit) < length)
10368
+ if (this.pages * this.limit < length)
10165
10369
  this.pages += 1;
10166
10370
  if (this.pages === 1)
10167
10371
  this.loadMoreData = false;
@@ -10195,7 +10399,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10195
10399
  }
10196
10400
  else {
10197
10401
  if (arrayValue.length === 1) {
10198
- value = item?.[value] ? item[value] : "";
10402
+ value = item?.[value] ? item[value] : '';
10199
10403
  // value = item?.[value] ? item[value] : value !== key ? value : "";
10200
10404
  if (isValidDate(value))
10201
10405
  value = `${formatDate(value)}`;
@@ -10244,18 +10448,23 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10244
10448
  // }, {}))
10245
10449
  });
10246
10450
  return data.reduce((accum, curr) => {
10247
- accum.push({ ...this.itemMapper(curr, this.mapper, props), ...{ pk: this.pk } });
10451
+ accum.push({
10452
+ ...this.itemMapper(curr, this.mapper, props),
10453
+ ...{ pk: this.pk },
10454
+ });
10248
10455
  return accum;
10249
10456
  }, []);
10250
10457
  }
10251
10458
  parseSearchValue() {
10252
10459
  if (typeof this.searchValue === Primitives.STRING)
10253
- return this.searchValue || "";
10460
+ return this.searchValue || '';
10254
10461
  const searchValue = this.searchValue;
10255
- return (searchValue?.query).map(item => `${item.index} ${item.condition} ${item.value}`).join(", ");
10462
+ return (searchValue?.query)
10463
+ .map((item) => `${item.index} ${item.condition} ${item.value}`)
10464
+ .join(', ');
10256
10465
  }
10257
10466
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10258
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", createButton: "createButton", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" }, properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "\n@if (showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n\n@if (showSearchbar) {\n <div [hidden]=\"!data?.length\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-grid-actions\">\n <div class=\"dcf-width-expand@m dcf-width-1-1\">\n @if (model && enableFilter) {\n @if (data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n }\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n </div>\n @if(createButton) {\n <div class=\"dcf-width-auto@m dcf-button-container dcf-width-1-1 dcf-flex-middle dcf-flex dcf-flex-center dcf-flex-right@m\">\n <div>\n <ion-button expand=\"block\" (click)=\"changeOperation(OperationKeys.CREATE)\">Create</ion-button>\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n@if (initialized && data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\">\n @if (item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if (loadMoreData) {\n @if (pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if (refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if (!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [route]=\"route\"\n [borders]=\"borders\"\n [icon]=\"empty.icon\"\n className=\"dcf-empty-data\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n [route]=\"route\"\n [borders]=\"borders\"\n className=\"empty-search\"\n [translatable]=\"true\"\n className=\"dcf-empty-data\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}.dcf-grid-actions{padding:var(--dcf-padding-small);padding-bottom:0}@media (max-width: 768px){.dcf-grid-actions .dcf-button-container{width:100%!important}.dcf-grid-actions .dcf-button-container *{width:calc(100% - 5px)!important;display:inline-block;margin-top:0!important;margin-bottom:var(--dcf-margin-xsmall)!important}}.dcf-grid-actions>div:only-child{width:100%}\n"], dependencies: [{ kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "multiple", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10467
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", createButton: "createButton", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", empty: "empty" }, outputs: { clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" }, properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "\n@if (showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n\n@if (showSearchbar) {\n <div [hidden]=\"!data?.length\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-grid-actions\">\n <div class=\"dcf-width-expand@m dcf-width-1-1\">\n @if (model && enableFilter) {\n @if (data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n }\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n </div>\n @if(createButton) {\n <div class=\"dcf-width-auto@m dcf-button-container dcf-width-1-1 dcf-flex-middle dcf-flex dcf-flex-center dcf-flex-right@m\">\n <div>\n <ion-button expand=\"block\" (click)=\"changeOperation(OperationKeys.CREATE)\">Create</ion-button>\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n@if (initialized && data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\">\n @if (item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if (loadMoreData) {\n @if (pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if (refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if (!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [route]=\"route\"\n [borders]=\"borders\"\n [icon]=\"empty.icon\"\n className=\"dcf-empty-data\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n [route]=\"route\"\n [borders]=\"borders\"\n className=\"empty-search\"\n [translatable]=\"true\"\n className=\"dcf-empty-data\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}.dcf-grid-actions{padding:var(--dcf-padding-small);padding-bottom:0}@media (max-width: 768px){.dcf-grid-actions .dcf-button-container{width:100%!important}.dcf-grid-actions .dcf-button-container *{width:calc(100% - 5px)!important;display:inline-block;margin-top:0!important;margin-bottom:var(--dcf-margin-xsmall)!important}}.dcf-grid-actions>div:only-child{width:100%}\n"], dependencies: [{ kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "multiple", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10259
10468
  };
10260
10469
  ListComponent = __decorate([
10261
10470
  Dynamic(),
@@ -10282,7 +10491,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
10282
10491
  SearchbarComponent,
10283
10492
  EmptyStateComponent,
10284
10493
  FilterComponent,
10285
- ComponentRendererComponent
10494
+ ComponentRendererComponent,
10286
10495
  ], host: { '[attr.id]': 'uid' }, template: "\n@if (showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n\n@if (showSearchbar) {\n <div [hidden]=\"!data?.length\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-grid-actions\">\n <div class=\"dcf-width-expand@m dcf-width-1-1\">\n @if (model && enableFilter) {\n @if (data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n }\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n </div>\n @if(createButton) {\n <div class=\"dcf-width-auto@m dcf-button-container dcf-width-1-1 dcf-flex-middle dcf-flex dcf-flex-center dcf-flex-right@m\">\n <div>\n <ion-button expand=\"block\" (click)=\"changeOperation(OperationKeys.CREATE)\">Create</ion-button>\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n@if (initialized && data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\">\n @if (item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if (loadMoreData) {\n @if (pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if (refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if (!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [route]=\"route\"\n [borders]=\"borders\"\n [icon]=\"empty.icon\"\n className=\"dcf-empty-data\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n [route]=\"route\"\n [borders]=\"borders\"\n className=\"empty-search\"\n [translatable]=\"true\"\n className=\"dcf-empty-data\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}.dcf-grid-actions{padding:var(--dcf-padding-small);padding-bottom:0}@media (max-width: 768px){.dcf-grid-actions .dcf-button-container{width:100%!important}.dcf-grid-actions .dcf-button-container *{width:calc(100% - 5px)!important;display:inline-block;margin-top:0!important;margin-bottom:var(--dcf-margin-xsmall)!important}}.dcf-grid-actions>div:only-child{width:100%}\n"] }]
10287
10496
  }], ctorParameters: () => [], propDecorators: { type: [{
10288
10497
  type: Input
@@ -10324,8 +10533,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
10324
10533
  type: Input
10325
10534
  }], empty: [{
10326
10535
  type: Input
10327
- }], refreshEvent: [{
10328
- type: Output
10329
10536
  }], clickEvent: [{
10330
10537
  type: Output
10331
10538
  }], handleClick: [{
@@ -10491,7 +10698,7 @@ let ListItemComponent = class ListItemComponent extends NgxComponentDirective {
10491
10698
  this.className += ` action`;
10492
10699
  this.windowWidth = getWindowWidth();
10493
10700
  }
10494
- ngAfterViewInit() {
10701
+ async ngAfterViewInit() {
10495
10702
  this.checkDarkMode();
10496
10703
  }
10497
10704
  /**
@@ -11391,7 +11598,7 @@ let FileUploadComponent = class FileUploadComponent extends NgxFormFieldDirectiv
11391
11598
  return xmlDoc.documentElement.innerHTML;
11392
11599
  }
11393
11600
  catch (error) {
11394
- this.logger.error(error?.message);
11601
+ this.log.error(error?.message);
11395
11602
  return undefined;
11396
11603
  }
11397
11604
  };
@@ -11705,15 +11912,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
11705
11912
  class DynamicModule {
11706
11913
  }
11707
11914
 
11708
- /**
11709
- * @module module:lib/engine/NgxEventHandler
11710
- * @description Event handler base class used by Decaf components.
11711
- * @summary Defines NgxEventHandler which standardizes event handling logic and provides
11712
- * logging support for handlers that process custom events emitted by components.
11713
- *
11714
- * @link {@link NgxEventHandler}
11715
- */
11716
- class NgxEventHandler extends LoggedClass {
11915
+ class NgxEventHandler extends DecafEventHandler {
11916
+ async refresh(args) {
11917
+ this.log.for(this.refresh).debug(`Refresh called with args: ${args}`);
11918
+ }
11717
11919
  }
11718
11920
 
11719
11921
  /**
@@ -11819,7 +12021,6 @@ class NgxPageDirective extends NgxComponentDirective {
11819
12021
  this.mediaService.colorSchemeObserver(this.component);
11820
12022
  this.currentRoute = this.router.url.replace('/', '');
11821
12023
  this.setPageTitle(this.currentRoute);
11822
- this.initialized = true;
11823
12024
  }
11824
12025
  /**
11825
12026
  * @description Ionic lifecycle hook called when the page is about to enter view.
@@ -11909,17 +12110,20 @@ class NgxModelPageDirective extends NgxPageDirective {
11909
12110
  * @default [OperationKeys.CREATE, OperationKeys.READ]
11910
12111
  * @memberOf ModelPage
11911
12112
  */
11912
- this.allowedOperations = [OperationKeys.CREATE, OperationKeys.READ];
11913
- /**
11914
- * @description Current model data loaded from the repository.
11915
- * @summary Stores the raw data object representing the current model instance retrieved
11916
- * from the repository. This property holds the actual data values for the model being
11917
- * displayed or edited, and is set to undefined when no data is available or when an
11918
- * error occurs during data loading.
11919
- * @type {KeyValue | undefined}
11920
- * @default undefined
11921
- * @memberOf NgxModelPageDirective
11922
- */
12113
+ this.allowedOperations = [
12114
+ OperationKeys.CREATE,
12115
+ OperationKeys.READ,
12116
+ ];
12117
+ /**
12118
+ * @description Current model data loaded from the repository.
12119
+ * @summary Stores the raw data object representing the current model instance retrieved
12120
+ * from the repository. This property holds the actual data values for the model being
12121
+ * displayed or edited, and is set to undefined when no data is available or when an
12122
+ * error occurs during data loading.
12123
+ * @type {KeyValue | undefined}
12124
+ * @default undefined
12125
+ * @memberOf NgxModelPageDirective
12126
+ */
11923
12127
  this.modelData = undefined;
11924
12128
  /**
11925
12129
  * @description Error message from failed operations.
@@ -11937,12 +12141,12 @@ class NgxModelPageDirective extends NgxPageDirective {
11937
12141
  // }
11938
12142
  get pageTitle() {
11939
12143
  if (!this.modelName && this.model instanceof Model)
11940
- this.modelName = this.model?.constructor?.name || "";
12144
+ this.modelName = this.model?.constructor?.name || '';
11941
12145
  if (!this.operation)
11942
12146
  return this.title ? this.title : `Listing ${this.modelName}`;
11943
- const operation = this.operation.charAt(0).toUpperCase() + this.operation.slice(1).toLowerCase();
11944
- return this.modelName ?
11945
- `${operation} ${this.modelName}` : this.title;
12147
+ const operation = this.operation.charAt(0).toUpperCase() +
12148
+ this.operation.slice(1).toLowerCase();
12149
+ return this.modelName ? `${operation} ${this.modelName}` : this.title;
11946
12150
  }
11947
12151
  /**
11948
12152
  * @description Lazy-initialized repository getter with model resolution.
@@ -11956,14 +12160,21 @@ class NgxModelPageDirective extends NgxPageDirective {
11956
12160
  * @throws {InternalError} When the model is not found in the registry
11957
12161
  */
11958
12162
  get repository() {
11959
- if (!this._repository) {
11960
- const constructor = Model.get(this.modelName);
11961
- if (!constructor)
11962
- throw new InternalError('Cannot find model. was it registered with @model?');
11963
- this._repository = Repository.forModel(constructor);
11964
- if (!this.pk)
11965
- this.pk = this._repository.pk;
11966
- this.model = new constructor();
12163
+ try {
12164
+ if (!this._repository) {
12165
+ const constructor = Model.get(this.modelName);
12166
+ if (!constructor)
12167
+ throw new InternalError('Cannot find model. was it registered with @model?');
12168
+ this._repository = Repository.forModel(constructor);
12169
+ if (!this.pk)
12170
+ this.pk = Model.pk(constructor);
12171
+ this.model = new constructor();
12172
+ }
12173
+ }
12174
+ catch (error) {
12175
+ this.log.warn(`Error getting repository for model: ${this.modelName}. ${error.message}`);
12176
+ this._repository = undefined;
12177
+ // throw new InternalError((error as Error)?.message || (error as string));
11967
12178
  }
11968
12179
  return this._repository;
11969
12180
  }
@@ -11976,7 +12187,10 @@ class NgxModelPageDirective extends NgxPageDirective {
11976
12187
  async ionViewWillEnter() {
11977
12188
  // await super.ionViewWillEnter();
11978
12189
  if (this.modelId)
11979
- this.allowedOperations = this.allowedOperations.concat([OperationKeys.UPDATE, OperationKeys.DELETE]);
12190
+ this.allowedOperations = this.allowedOperations.concat([
12191
+ OperationKeys.UPDATE,
12192
+ OperationKeys.DELETE,
12193
+ ]);
11980
12194
  this.getLocale(this.modelName);
11981
12195
  await this.refresh(this.modelId);
11982
12196
  this.initialized = true;
@@ -11999,7 +12213,7 @@ class NgxModelPageDirective extends NgxPageDirective {
11999
12213
  case OperationKeys.READ:
12000
12214
  case OperationKeys.UPDATE:
12001
12215
  case OperationKeys.DELETE:
12002
- this.model = await this.handleGet(uid || this.modelId);
12216
+ this.model = (await this.handleGet(uid || this.modelId));
12003
12217
  break;
12004
12218
  }
12005
12219
  }
@@ -12007,23 +12221,23 @@ class NgxModelPageDirective extends NgxPageDirective {
12007
12221
  if (error instanceof NotFoundError) {
12008
12222
  this.errorMessage = error.message;
12009
12223
  }
12010
- this.logger.error(error);
12224
+ this.log.error(error);
12011
12225
  }
12012
12226
  }
12013
12227
  /**
12014
12228
  * @description Generic event handler for component events.
12015
12229
  * @summary Processes incoming events from child components and routes them to appropriate
12016
12230
  * handlers based on the event name. Currently handles SUBMIT events by delegating to
12017
- * the handleSubmit method. This centralized event handling approach allows for easy
12231
+ * the submit method. This centralized event handling approach allows for easy
12018
12232
  * extension and consistent event processing.
12019
12233
  *
12020
12234
  * @param {IBaseCustomEvent} event - The event object containing event data and metadata
12021
12235
  */
12022
- async handleEvent(event) {
12236
+ async handleEvent(event, repository) {
12023
12237
  const { name } = event;
12024
12238
  switch (name) {
12025
12239
  case ComponentEventNames.SUBMIT:
12026
- await this.handleSubmit(event);
12240
+ await this.submit(event, repository);
12027
12241
  break;
12028
12242
  }
12029
12243
  }
@@ -12038,38 +12252,61 @@ class NgxModelPageDirective extends NgxPageDirective {
12038
12252
  * @param {IBaseCustomEvent} event - The submit event containing form data
12039
12253
  * @return {Promise<IModelPageCustomEvent|void>} Promise that resolves on success or throws on error
12040
12254
  */
12041
- async handleSubmit(event, redirect = false) {
12255
+ async submit(event, repository, redirect = false) {
12042
12256
  try {
12043
- const repo = this._repository;
12044
- const operation = this.operation === OperationKeys.READ ? 'delete' : this.operation.toLowerCase();
12045
- const data = this.parseData(event.data, operation);
12046
- const result = this.operation === OperationKeys.CREATE ?
12047
- await repo.create(data) : this.operation === OperationKeys.UPDATE ?
12048
- await repo.update(data) : repo.delete(data);
12049
- const message = await this.translate(`operations.${operation}.${result ? 'success' : 'error'}`, {
12050
- "0": this.pk,
12051
- "1": this.modelId || result[this.pk],
12052
- });
12053
- if (result) {
12054
- repo.refresh(this.modelName, this.operation, this.modelId);
12055
- if (redirect)
12056
- this.location.back();
12257
+ if (!repository)
12258
+ repository = this._repository;
12259
+ // const pk = this.pk || Model.pk(repository.class as Constructor<Model>);
12260
+ const operation = this.operation;
12261
+ const { data } = event;
12262
+ if (data) {
12263
+ const model = this.parseData(data || {}, operation, repository);
12264
+ let result;
12265
+ switch (operation) {
12266
+ case OperationKeys.CREATE:
12267
+ result = await (!Array.isArray(model)
12268
+ ? repository.create(model)
12269
+ : repository.createAll(model));
12270
+ break;
12271
+ case OperationKeys.UPDATE:
12272
+ result = await (!Array.isArray(model)
12273
+ ? repository.update(model)
12274
+ : repository.updateAll(model));
12275
+ break;
12276
+ case OperationKeys.DELETE:
12277
+ result = await (!Array.isArray(model)
12278
+ ? repository.delete(model)
12279
+ : repository.deleteAll(model));
12280
+ break;
12281
+ }
12282
+ const message = await this.translate(!Array.isArray(result)
12283
+ ? `operations.${operation}.${result ? 'success' : 'error'}`
12284
+ : `operations.multiple`);
12285
+ if (result) {
12286
+ // repository.refresh(this.modelName, this.operation, this.modelId as EventIds);
12287
+ if (redirect)
12288
+ this.location.back();
12289
+ }
12290
+ return {
12291
+ ...event,
12292
+ success: result ? true : false,
12293
+ message,
12294
+ };
12057
12295
  }
12058
- return {
12059
- ...event,
12060
- success: result ? true : false,
12061
- message
12062
- };
12063
12296
  }
12064
12297
  catch (error) {
12065
- this.logger.error(error);
12066
12298
  return {
12067
12299
  ...event,
12068
12300
  success: false,
12069
- message: error instanceof Error ? error.message : error
12301
+ message: error instanceof Error ? error.message : error,
12070
12302
  };
12071
12303
  }
12072
12304
  }
12305
+ async create(data, repository) {
12306
+ alert('create');
12307
+ console.log(repository);
12308
+ console.log(data);
12309
+ }
12073
12310
  /**
12074
12311
  * @description Retrieves a model instance from the repository by unique identifier.
12075
12312
  * @summary Fetches a specific model instance using the repository's read method.
@@ -12080,17 +12317,58 @@ class NgxModelPageDirective extends NgxPageDirective {
12080
12317
  * @param {string} uid - The unique identifier of the model instance to retrieve
12081
12318
  * @return {Promise<Model | undefined>} Promise resolving to the model instance or undefined
12082
12319
  */
12083
- async handleGet(uid) {
12320
+ async handleGet(uid, repository, modelName) {
12084
12321
  if (!uid) {
12085
- this.logger.info('No key passed to model page read operation, backing to last page');
12322
+ this.log.info('No key passed to model page read operation, backing to last page');
12086
12323
  this.location.back();
12087
12324
  return undefined;
12088
12325
  }
12089
- const type = Reflect.getMetadata("design:type", this.model, this.repository.pk).name;
12090
- if (!this.pk)
12091
- this.pk = this.repository.pk;
12092
- const result = await this._repository.read(([Primitives.NUMBER, Primitives.BIGINT].includes(type.toLowerCase()) ? Number(uid) : uid));
12093
- return result ?? undefined;
12326
+ if (!modelName)
12327
+ modelName = this.modelName;
12328
+ const getRepository = async (modelName, parent, model) => {
12329
+ if (this._repository)
12330
+ return this._repository;
12331
+ const constructor = Model.get(modelName);
12332
+ if (constructor) {
12333
+ const properties = Metadata.properties(constructor);
12334
+ // if (!model) model = {} as KeyValue;
12335
+ for (const prop of properties) {
12336
+ const type = Metadata.type(constructor, prop).name;
12337
+ const context = getModelAndRepository(type);
12338
+ if (!context)
12339
+ return getRepository(type, prop, model);
12340
+ const { repository } = context;
12341
+ if (modelName === this.modelName) {
12342
+ const data = await this.handleGet(uid, repository, modelName);
12343
+ this.model = Model.build({ [prop]: data }, modelName);
12344
+ }
12345
+ // else {
12346
+ // model[prop as string] = Model.build({}, type);
12347
+ // }
12348
+ }
12349
+ // (this.model as KeyValue)[parent as string] = Model.build(
12350
+ // model,
12351
+ // modelName
12352
+ // );
12353
+ }
12354
+ };
12355
+ repository = (repository ||
12356
+ (await getRepository(modelName)));
12357
+ if (!repository)
12358
+ return this.model;
12359
+ const type = Metadata.type(repository.class, Model.pk(repository.class)).name;
12360
+ try {
12361
+ const result = await (repository).read(([Primitives.NUMBER, Primitives.BIGINT].includes(type.toLowerCase())
12362
+ ? Number(uid)
12363
+ : uid));
12364
+ return result;
12365
+ }
12366
+ catch (error) {
12367
+ this.log
12368
+ .for(this.handleGet)
12369
+ .info(`Error getting model instance with id ${uid}: ${error.message}`);
12370
+ return undefined;
12371
+ }
12094
12372
  }
12095
12373
  /**
12096
12374
  * @description Parses and transforms form data for repository operations.
@@ -12103,13 +12381,22 @@ class NgxModelPageDirective extends NgxPageDirective {
12103
12381
  * @return {Model | string | number} Processed data ready for repository operations
12104
12382
  * @private
12105
12383
  */
12106
- parseData(data, operation) {
12107
- const repo = this._repository;
12384
+ parseData(data, operation, repository) {
12385
+ operation = (operation === OperationKeys.READ
12386
+ ? OperationKeys.DELETE
12387
+ : operation.toLowerCase());
12388
+ if (Array.isArray(data)) {
12389
+ data = data.map((item) => this.parseData(item, operation, repository));
12390
+ return data;
12391
+ }
12108
12392
  let uid = this.modelId;
12109
- if (repo.pk === 'id')
12110
- uid = Number(uid);
12393
+ const pk = Model.pk(repository.class);
12394
+ const type = Metadata.type(repository.class, pk).name;
12395
+ uid = [Primitives.NUMBER, Primitives.BIGINT].includes(type.toLowerCase())
12396
+ ? Number(uid)
12397
+ : uid;
12111
12398
  if (operation !== OperationKeys.DELETE)
12112
- return Model.build(this.modelId ? Object.assign(data, { [repo.pk]: uid }) : data, this.modelName);
12399
+ return Model.build(this.modelId ? Object.assign(data, { [pk]: uid }) : data, repository.class.name);
12113
12400
  return uid;
12114
12401
  }
12115
12402
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxModelPageDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
@@ -12156,5 +12443,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
12156
12443
  * Generated bundle index. Do not edit.
12157
12444
  */
12158
12445
 
12159
- export { ActionRoles, AngularEngineKeys, BaseComponentProps, CPTKN, CardComponent, ComponentEventNames, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DecafFakerRepository, DefaultFormReactiveOptions, DefaultListEmptyOptions, DefaultModalOptions, Dynamic, DynamicModule, ElementPositions, ElementSizes, EmptyStateComponent, FieldsetComponent, FileUploadComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, IconComponent, LOCALE_ROOT_TOKEN, LayoutComponent, LayoutGridGaps, ListComponent, ListComponentsTypes, ListItemComponent, ListItemPositions, LoggerLevels, ModalComponent, ModelRendererComponent, NgxComponentDirective, NgxEventHandler, NgxFormDirective, NgxFormFieldDirective, NgxFormService, NgxMediaService, NgxModelPageDirective, NgxPageDirective, NgxParentComponentDirective, NgxRenderingEngine, NgxSvgDirective, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, WindowColorSchemes, cleanSpaces, dataMapper, filterString, formatDate, generateRandomValue, getFakerData, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getNgxModalComponent, getNgxSelectOptionsModal, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, presentNgxLightBoxModal, provideDbAdapter, provideDynamicComponents, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
12446
+ export { ActionRoles, AngularEngineKeys, BaseComponentProps, CPTKN, CardComponent, ComponentEventNames, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DecafFakerRepository, DefaultFormReactiveOptions, DefaultListEmptyOptions, DefaultModalOptions, Dynamic, DynamicModule, ElementPositions, ElementSizes, EmptyStateComponent, FieldsetComponent, FileUploadComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, IconComponent, LOCALE_ROOT_TOKEN, LayoutComponent, LayoutGridGaps, ListComponent, ListComponentsTypes, ListItemComponent, ListItemPositions, LoggerLevels, ModalComponent, ModelRendererComponent, NgxComponentDirective, NgxEventHandler, NgxFormDirective, NgxFormFieldDirective, NgxFormService, NgxMediaService, NgxModelPageDirective, NgxPageDirective, NgxParentComponentDirective, NgxRenderingEngine, NgxSvgDirective, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, WindowColorSchemes, cleanSpaces, dataMapper, filterString, formatDate, generateRandomValue, getFakerData, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelAndRepository, getNgxModalComponent, getNgxSelectOptionsModal, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, presentNgxLightBoxModal, provideDbAdapter, provideDynamicComponents, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
12160
12447
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map