@decaf-ts/for-angular 0.0.45 → 0.0.47

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 } 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 } 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
12
  import { Logging, LoggedClass } from '@decaf-ts/logging';
13
- import { uses, Repository, OrderDirection, Condition } from '@decaf-ts/core';
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,34 @@ 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
+ if (!repository.pk)
576
+ return undefined;
577
+ return { repository, model };
572
578
  }
573
579
  catch (error) {
574
- throw new InternalError(error?.message || error);
580
+ getLogger(getModelAndRepository).warn(error?.message || error);
581
+ return undefined;
575
582
  }
576
583
  }
577
584
  /**
@@ -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.
@@ -2169,7 +2176,9 @@ class DecafFakerRepository {
2169
2176
  }
2170
2177
  get repository() {
2171
2178
  if (!this._repository) {
2172
- const modelName = typeof this.model === 'string' ? this.model : this.model.constructor.name;
2179
+ const modelName = typeof this.model === 'string'
2180
+ ? this.model
2181
+ : this.model.constructor.name;
2173
2182
  const constructor = Model.get(modelName);
2174
2183
  if (!constructor)
2175
2184
  throw new InternalError(`Cannot find model ${modelName}. was it registered with @model?`);
@@ -2191,11 +2200,13 @@ class DecafFakerRepository {
2191
2200
  this._repository = this.repository;
2192
2201
  }
2193
2202
  async generateData(pkValues, pk, pkType) {
2194
- const limit = pkValues ? Object.values(pkValues || {}).length - 1 : this.limit;
2203
+ const limit = pkValues
2204
+ ? Object.values(pkValues || {}).length - 1
2205
+ : this.limit;
2195
2206
  if (!pk)
2196
2207
  pk = this._repository?.pk;
2197
2208
  if (!pkType)
2198
- pkType = Reflect.getMetadata("design:type", this.model, pk).name.toLowerCase();
2209
+ pkType = Metadata.type(this.repository.class, pk).name.toLowerCase();
2199
2210
  const props = Object.keys(this.model).filter((k) => {
2200
2211
  if (pkType === Primitives.STRING)
2201
2212
  return !['updatedBy', 'createdAt', 'createdBy', 'updatedAt'].includes(k);
@@ -2203,8 +2214,8 @@ class DecafFakerRepository {
2203
2214
  });
2204
2215
  const dataProps = {};
2205
2216
  for (const prop of props) {
2206
- const type = Reflect.getMetadata("design:type", this.model, prop);
2207
- switch ((type?.name || "").toLowerCase()) {
2217
+ const type = Metadata.type(this.repository.class, prop).name.toLowerCase();
2218
+ switch ((type?.name || '').toLowerCase()) {
2208
2219
  case 'string':
2209
2220
  dataProps[prop] = () => `${faker.lorem.word()} ${pk === prop ? ' - ' + faker.number.int({ min: 1, max: 200 }) : ''}`;
2210
2221
  break;
@@ -2240,8 +2251,13 @@ class DecafFakerRepository {
2240
2251
  if (values.length > 0) {
2241
2252
  const randomIndex = Math.floor(Math.random() * values.length);
2242
2253
  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;
2254
+ const value = pkType === Primitives.STRING
2255
+ ? selected
2256
+ : pkType === Primitives.NUMBER
2257
+ ? parseToNumber(selected)
2258
+ : pkType === Array.name
2259
+ ? [selected]
2260
+ : selected;
2245
2261
  item[pk] = value;
2246
2262
  }
2247
2263
  if (!iterated.includes(item[pk])) {
@@ -2258,7 +2274,8 @@ class DecafFakerRepository {
2258
2274
  return false;
2259
2275
  uids.add(item[pk]);
2260
2276
  return true;
2261
- }).filter(Boolean);
2277
+ })
2278
+ .filter(Boolean);
2262
2279
  }
2263
2280
  }
2264
2281
  function getFakerData(limit = 100, data, model) {
@@ -2267,7 +2284,7 @@ function getFakerData(limit = 100, data, model) {
2267
2284
  const item = {};
2268
2285
  for (const [key, value] of Object.entries(data)) {
2269
2286
  const val = value();
2270
- item[key] = val.constructor === Date ? formatDate(val) : val;
2287
+ item[key] = val?.constructor === Date ? formatDate(val) : val;
2271
2288
  }
2272
2289
  // if ((item as any)?.['code'])
2273
2290
  // (item as any).code = `${index}`;
@@ -2408,7 +2425,8 @@ class NgxRenderingEngine extends RenderingEngine {
2408
2425
  * @memberOf module:lib/engine/NgxRenderingEngine
2409
2426
  */
2410
2427
  fromFieldDefinition(fieldDef, vcr, injector, tpl, registryFormId = Date.now().toString(36).toUpperCase(), createComponent = true, formGroup) {
2411
- const cmp = fieldDef?.['component'] || NgxRenderingEngine.components(fieldDef.tag);
2428
+ const cmp = fieldDef?.['component'] ||
2429
+ NgxRenderingEngine.components(fieldDef.tag);
2412
2430
  const component = cmp.constructor;
2413
2431
  const componentMetadata = reflectComponentType(component);
2414
2432
  if (!componentMetadata) {
@@ -2416,7 +2434,7 @@ class NgxRenderingEngine extends RenderingEngine {
2416
2434
  }
2417
2435
  const { inputs: possibleInputs } = componentMetadata;
2418
2436
  const inputs = { ...fieldDef.props };
2419
- const unmappedKeys = Object.keys(inputs).filter(input => {
2437
+ const unmappedKeys = Object.keys(inputs).filter((input) => {
2420
2438
  const isMapped = possibleInputs.find(({ propName }) => propName === input);
2421
2439
  if (!isMapped)
2422
2440
  delete inputs[input];
@@ -2432,13 +2450,17 @@ class NgxRenderingEngine extends RenderingEngine {
2432
2450
  // const hasFormRoot = Object.values(possibleInputs).some(({propName}) => propName === AngularEngineKeys.PARENT_FORM);
2433
2451
  // if (hasFormRoot && !inputs?.[AngularEngineKeys.PARENT_FORM] && formGroup)
2434
2452
  // inputs[AngularEngineKeys.PARENT_FORM] = formGroup;
2453
+ if (operation !== OperationKeys.CREATE && hiddenOn.includes(OperationKeys.CREATE)) {
2454
+ fieldDef.props = { ...fieldDef.props, ...{ readonly: true, type: HTML5InputTypes.TEXT } };
2455
+ }
2435
2456
  const result = {
2436
2457
  component,
2437
2458
  inputs,
2438
2459
  injector,
2439
2460
  };
2440
2461
  if (fieldDef.rendererId)
2441
- result.inputs['rendererId'] = fieldDef.rendererId;
2462
+ result.inputs['rendererId'] =
2463
+ fieldDef.rendererId;
2442
2464
  // process children
2443
2465
  // generating DOM
2444
2466
  // const projectable = NgxRenderingEngine._projectable;
@@ -2446,11 +2468,12 @@ class NgxRenderingEngine extends RenderingEngine {
2446
2468
  // const template = [];
2447
2469
  const hasChildren = Object.values(possibleInputs).some(({ propName }) => propName === AngularEngineKeys.CHILDREN);
2448
2470
  const hasModel = Object.values(possibleInputs).some(({ propName }) => propName === ModelKeys.MODEL);
2449
- const componentInputs = Object.assign(inputs, (hasModel ? { model: this._model } : {}), (hasChildren ? { children: fieldDef?.['children'] || [] } : {}));
2471
+ const componentInputs = Object.assign(inputs, hasModel ? { model: this._model } : {}, hasChildren ? { children: fieldDef?.['children'] || [] } : {});
2450
2472
  if (createComponent) {
2451
2473
  vcr.clear();
2452
2474
  const componentInstance = NgxRenderingEngine.createComponent(component, componentInputs, injector, componentMetadata, vcr, []);
2453
- result.component = NgxRenderingEngine._instance = componentInstance;
2475
+ result.component = NgxRenderingEngine._instance =
2476
+ componentInstance;
2454
2477
  }
2455
2478
  if (fieldDef.children?.length) {
2456
2479
  if (!NgxRenderingEngine._parentProps && inputs?.['pages']) {
@@ -2458,8 +2481,9 @@ class NgxRenderingEngine extends RenderingEngine {
2458
2481
  // NgxRenderingEngine._projectable = false;
2459
2482
  }
2460
2483
  result.children = fieldDef.children.map((child) => {
2461
- // const hiddenOn = (child?.props?.hidden || []) as CrudOperations[];
2462
- // moved to ui decorators
2484
+ const readonly = operation === OperationKeys.UPDATE && (child?.props?.hidden || []).includes(OperationKeys.CREATE);
2485
+ // const hiddenOn = (child?.props?.hidden || []) as string[];
2486
+ // // moved to ui decorators
2463
2487
  // if (child?.children?.length) {
2464
2488
  // child.children = child.children.filter(c => {
2465
2489
  // const hiddenOn = c?.props?.hidden || [];
@@ -2468,7 +2492,15 @@ class NgxRenderingEngine extends RenderingEngine {
2468
2492
  // })
2469
2493
  // }
2470
2494
  // if (!hiddenOn?.length || !(hiddenOn as CrudOperations[]).includes(operation as CrudOperations))
2471
- NgxFormService.addControlFromProps(registryFormId, child.props, { ...inputs, ...NgxRenderingEngine._parentProps || {} });
2495
+ if (!readonly) {
2496
+ NgxFormService.addControlFromProps(registryFormId, child.props, {
2497
+ ...inputs,
2498
+ ...(NgxRenderingEngine._parentProps || {}),
2499
+ });
2500
+ }
2501
+ else {
2502
+ child.props = { ...child.props, ...{ readonly: true } };
2503
+ }
2472
2504
  return this.fromFieldDefinition(child, vcr, injector, tpl, registryFormId, false, formGroup);
2473
2505
  });
2474
2506
  }
@@ -2504,24 +2536,29 @@ class NgxRenderingEngine extends RenderingEngine {
2504
2536
  }
2505
2537
  static createHostComponent(component, props = {}, injector) {
2506
2538
  if (!injector)
2507
- injector = NgxRenderingEngine._injector || Injector.create({ providers: [], parent: Injector.NULL });
2539
+ injector =
2540
+ NgxRenderingEngine._injector ||
2541
+ Injector.create({ providers: [], parent: Injector.NULL });
2508
2542
  const envInjector = createEnvironmentInjector([], injector);
2509
2543
  let cmp = {};
2510
2544
  runInInjectionContext(envInjector, () => {
2511
2545
  const host = document.createElement('div');
2512
- component = typeof component === Primitives.STRING ? NgxRenderingEngine.components(component) : component;
2546
+ component =
2547
+ typeof component === Primitives.STRING
2548
+ ? NgxRenderingEngine.components(component)
2549
+ : component;
2513
2550
  if (!host)
2514
2551
  throw new Error('Cant create host element for component');
2515
2552
  cmp = createComponent(component, {
2516
2553
  environmentInjector: envInjector,
2517
- hostElement: host
2554
+ hostElement: host,
2518
2555
  });
2519
2556
  const metadata = reflectComponentType(component);
2520
2557
  if (!metadata)
2521
2558
  throw new InternalError(`Metadata for component ${component} not found.`);
2522
2559
  const { inputs: possibleInputs } = metadata;
2523
2560
  const inputs = { ...props };
2524
- const unmappedKeys = Object.keys(inputs).filter(input => {
2561
+ const unmappedKeys = Object.keys(inputs).filter((input) => {
2525
2562
  const isMapped = possibleInputs.find(({ propName }) => propName === input);
2526
2563
  if (!isMapped)
2527
2564
  delete inputs[input];
@@ -2607,7 +2644,8 @@ class NgxRenderingEngine extends RenderingEngine {
2607
2644
  const props = fieldDef.props;
2608
2645
  if (!NgxRenderingEngine._operation)
2609
2646
  NgxRenderingEngine._operation = props?.operation || undefined;
2610
- const isArray = (props?.pages && props?.pages >= 1 || props?.multiple === true);
2647
+ const isArray = (props?.pages && props?.pages >= 1) ||
2648
+ props?.multiple === true;
2611
2649
  const formGroup = NgxFormService.createForm(formId, isArray);
2612
2650
  result = this.fromFieldDefinition(fieldDef, vcr, injector, tpl, formId, true, formGroup);
2613
2651
  if (result.component)
@@ -2671,20 +2709,6 @@ class NgxRenderingEngine extends RenderingEngine {
2671
2709
  throw new InternalError(`No Component registered under ${selector}`);
2672
2710
  return this._components[selector];
2673
2711
  }
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
2712
  /**
2689
2713
  * @description Sets input properties on a component instance.
2690
2714
  * @summary This static utility method sets input properties on a component instance
@@ -2720,7 +2744,7 @@ class NgxRenderingEngine extends RenderingEngine {
2720
2744
  */
2721
2745
  static setInputs(component, inputs, metadata) {
2722
2746
  function parseInputValue(component, input) {
2723
- Object.keys(input).forEach(key => {
2747
+ Object.keys(input).forEach((key) => {
2724
2748
  const value = input[key];
2725
2749
  if (typeof value === 'object' && !!value)
2726
2750
  return parseInputValue(component, value);
@@ -3463,7 +3487,7 @@ catch (e) {
3463
3487
  * @implements {OnChanges}
3464
3488
  * @memberOf module:lib/engine/NgxComponentDirective
3465
3489
  */
3466
- class NgxComponentDirective extends LoggedClass {
3490
+ class NgxComponentDirective extends DecafComponent {
3467
3491
  /**
3468
3492
  * @description Constructor for NgxComponentDirective.
3469
3493
  * @summary Initializes the directive by setting up the component name, locale root,
@@ -3506,7 +3530,7 @@ class NgxComponentDirective extends LoggedClass {
3506
3530
  * @summary Defines how fields from the data model should be mapped to properties used by the component.
3507
3531
  * This allows for flexible data binding between the model and the component's display logic. Can be
3508
3532
  * provided as a static object mapping or as a function for dynamic mapping transformations.
3509
- * @type {Record<string, string> | FunctionLike}
3533
+ * @type {Record<string, string> | FunctionLike | Record<string, FunctionLike>}
3510
3534
  * @default {}
3511
3535
  * @memberOf module:lib/engine/NgxComponentDirective
3512
3536
  */
@@ -3587,7 +3611,7 @@ class NgxComponentDirective extends LoggedClass {
3587
3611
  * @type {NgxMediaService}
3588
3612
  * @memberOf module:lib/engine/NgxComponentDirective
3589
3613
  */
3590
- this.mediaService = new NgxMediaService();
3614
+ this.mediaService = inject(NgxMediaService);
3591
3615
  /**
3592
3616
  * @description Angular Renderer2 service for platform-agnostic DOM manipulation.
3593
3617
  * @summary Injected service that provides a safe, platform-agnostic way to manipulate DOM elements.
@@ -3635,7 +3659,7 @@ class NgxComponentDirective extends LoggedClass {
3635
3659
  * and other properties needed to render list items correctly. The tag property
3636
3660
  * identifies which component should be used to render each item in a list.
3637
3661
  * Additional properties can be included to customize the rendering behavior.
3638
- * @type {Record<string, unknown>}
3662
+ * @type {Record<string, FieldDefinition>}
3639
3663
  * @default {tag: ""}
3640
3664
  * @memberOf module:lib/engine/NgxComponentDirective
3641
3665
  */
@@ -3662,16 +3686,6 @@ class NgxComponentDirective extends LoggedClass {
3662
3686
  * @memberOf module:lib/engine/NgxComponentDirective
3663
3687
  */
3664
3688
  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
3689
  /**
3676
3690
  * @description Controls whether borders are displayed around the component.
3677
3691
  * @summary Boolean flag that determines if the component should be visually outlined with borders.
@@ -3681,22 +3695,14 @@ class NgxComponentDirective extends LoggedClass {
3681
3695
  * @default false
3682
3696
  */
3683
3697
  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
3698
  /**
3696
3699
  * @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.
3700
+ * @summary Injected service that provides direct access to the browser's URL and history.
3701
+ * Unlike the Router, Location allows for low-level manipulation of the browser's history stack
3702
+ * and URL path, such as programmatically navigating back or forward, or updating the URL without
3703
+ * triggering a route change. This is useful for scenarios where you need to interact with the
3704
+ * browser history or URL outside of Angular's routing system, such as closing modals, handling
3705
+ * popstate events, or supporting custom navigation logic.
3700
3706
  *
3701
3707
  * @private
3702
3708
  * @type {Location}
@@ -3715,13 +3721,14 @@ class NgxComponentDirective extends LoggedClass {
3715
3721
  * @memberOf module:lib/engine/NgxComponentDirective
3716
3722
  */
3717
3723
  this.isModalChild = false;
3724
+ this.handlers = {};
3725
+ this.events = {};
3718
3726
  this.componentName = componentName || "NgxComponentDirective";
3719
3727
  this.localeRoot = localeRoot;
3720
3728
  if (!this.localeRoot && this.componentName)
3721
3729
  this.localeRoot = this.componentName;
3722
3730
  if (this.localeRoot)
3723
3731
  this.getLocale(this.localeRoot);
3724
- this.logger = this.log;
3725
3732
  this.uid = `${this.componentName}-${generateRandomValue(8)}`;
3726
3733
  }
3727
3734
  /**
@@ -3758,7 +3765,7 @@ class NgxComponentDirective extends LoggedClass {
3758
3765
  get repository() {
3759
3766
  try {
3760
3767
  if (!this._repository) {
3761
- this._repository = getModelRepository(this.model);
3768
+ this._repository = getModelAndRepository(this.model)?.repository;
3762
3769
  if (this.model && !this.pk)
3763
3770
  this.pk =
3764
3771
  this._repository.pk || 'id';
@@ -3779,7 +3786,7 @@ class NgxComponentDirective extends LoggedClass {
3779
3786
  * @return {void}
3780
3787
  * @memberOf module:lib/engine/NgxComponentDirective
3781
3788
  */
3782
- ngOnChanges(changes) {
3789
+ async ngOnChanges(changes) {
3783
3790
  if (changes[BaseComponentProps.MODEL]) {
3784
3791
  const { currentValue } = changes[BaseComponentProps.MODEL];
3785
3792
  if (currentValue)
@@ -3788,6 +3795,26 @@ class NgxComponentDirective extends LoggedClass {
3788
3795
  if (!this.initialized)
3789
3796
  this.initialized = true;
3790
3797
  }
3798
+ if (changes[UIKeys.EVENTS]) {
3799
+ const { currentValue, previousValue } = changes[UIKeys.EVENTS];
3800
+ if (currentValue && typeof currentValue !== previousValue) {
3801
+ if (!this._repository)
3802
+ this._repository = this.repository;
3803
+ for (const key in currentValue) {
3804
+ const event = currentValue[key]();
3805
+ if (event && typeof event === 'function') {
3806
+ const clazz = new event();
3807
+ this.events[key] = clazz[key].bind(this);
3808
+ if (event[key] instanceof Promise) {
3809
+ await clazz[key].bind(this)();
3810
+ }
3811
+ else {
3812
+ clazz[key].bind(this)();
3813
+ }
3814
+ }
3815
+ }
3816
+ }
3817
+ }
3791
3818
  if (changes[BaseComponentProps.LOCALE_ROOT] || changes[BaseComponentProps.COMPONENT_NAME])
3792
3819
  this.locale = this.localeContext;
3793
3820
  if (this.enableDarkMode)
@@ -3811,21 +3838,6 @@ class NgxComponentDirective extends LoggedClass {
3811
3838
  return await firstValueFrom(this.translateService.get(phrase, (params || {})));
3812
3839
  ;
3813
3840
  }
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
3841
  checkDarkMode() {
3830
3842
  this.mediaService.isDarkMode().subscribe(isDark => {
3831
3843
  this.isDarkMode = isDark;
@@ -4093,7 +4105,7 @@ class NgxComponentDirective extends LoggedClass {
4093
4105
  return this.router.navigateByUrl(page);
4094
4106
  }
4095
4107
  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 }); }
4108
+ 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", handlers: "handlers", events: "events" }, 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 }); }
4097
4109
  }
4098
4110
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxComponentDirective, decorators: [{
4099
4111
  type: Directive,
@@ -4149,6 +4161,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4149
4161
  type: Input
4150
4162
  }], isModalChild: [{
4151
4163
  type: Input
4164
+ }], handlers: [{
4165
+ type: Input
4166
+ }], events: [{
4167
+ type: Input
4152
4168
  }] } });
4153
4169
 
4154
4170
  class NgxRenderableComponentDirective extends NgxComponentDirective {
@@ -4687,9 +4703,9 @@ class NgxFormFieldDirective extends NgxComponentDirective {
4687
4703
  * @return {void}
4688
4704
  * @public
4689
4705
  */
4690
- ngOnChanges(changes) {
4706
+ async ngOnChanges(changes) {
4691
4707
  if (!this.initialized)
4692
- super.ngOnChanges(changes);
4708
+ await super.ngOnChanges(changes);
4693
4709
  if (changes['activeFormGroupIndex'] && this.multiple &&
4694
4710
  !changes['activeFormGroupIndex'].isFirstChange() && changes['activeFormGroupIndex'].currentValue !== this.activeFormGroupIndex) {
4695
4711
  this.activeFormGroupIndex = changes['activeFormGroupIndex'].currentValue;
@@ -4811,8 +4827,39 @@ function Dynamic() {
4811
4827
  if (!metadata)
4812
4828
  throw new InternalError(`Could not find Component metadata. @Dynamic decorator must come above @Component`);
4813
4829
  NgxRenderingEngine.registerComponent(metadata.selector, original);
4814
- }, metadata(NgxRenderingEngine.key(AngularEngineKeys.DYNAMIC), true));
4830
+ }, metadata(Metadata.key(AngularEngineKeys.REFLECT, AngularEngineKeys.DYNAMIC), true));
4815
4831
  }
4832
+ // export interface UICustomEvents {
4833
+ // render: () => HandlerLike;
4834
+ // init: () => FunctionLike;
4835
+ // }
4836
+ // export function uion(event: string, handler: FunctionLike) {
4837
+ // return (target: any, propertyKey?: any) => {
4838
+ // const metadata = {
4839
+ // [event]: handler,
4840
+ // };
4841
+ // propMetadata(getUIAttributeKey(propertyKey, 'handlers'), metadata)(
4842
+ // target,
4843
+ // propertyKey
4844
+ // );
4845
+ // };
4846
+ // // return (model: unknown, property: unknown) => {
4847
+ // // const meta: UIHandlerMetadata = {
4848
+ // // [event]: handler,
4849
+ // // };
4850
+ // // return metadata(
4851
+ // // getUIAttributeKey(property as string, 'on'),
4852
+ // // meta
4853
+ // // )(model, property);
4854
+ // // };
4855
+ // }
4856
+ // export function uionrender(handler: FunctionLike) {
4857
+ // return uion("render", handler);
4858
+ // }
4859
+ // @uion(op, handler)
4860
+ // @uionrender(handler){
4861
+ // return uion("redenr", handler)
4862
+ // }
4816
4863
 
4817
4864
  /**
4818
4865
  * @module module:lib/components/model-renderer/model-renderer.component
@@ -4881,7 +4928,7 @@ class ModelRendererComponent extends NgxRenderableComponentDirective {
4881
4928
  * @description Lifecycle hook that is called when data-bound properties of a directive change
4882
4929
  * @param {SimpleChanges} changes - Object containing changes
4883
4930
  */
4884
- ngOnChanges(changes) {
4931
+ async ngOnChanges(changes) {
4885
4932
  if (changes[BaseComponentProps.MODEL]) {
4886
4933
  const { currentValue } = changes[BaseComponentProps.MODEL];
4887
4934
  this.refresh(currentValue);
@@ -4920,12 +4967,12 @@ class NgxParentComponentDirective extends NgxComponentDirective {
4920
4967
  constructor() {
4921
4968
  super(...arguments);
4922
4969
  /**
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
- */
4970
+ * @description Unique identifier for the current record.
4971
+ * @summary A unique identifier for the current record being displayed or manipulated.
4972
+ * This is typically used in conjunction with the primary key for operations on specific records.
4973
+ *
4974
+ * @type {string | number}
4975
+ */
4929
4976
  this.page = 1;
4930
4977
  /**
4931
4978
  * @description Unique identifier for the current record.
@@ -5404,6 +5451,15 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5404
5451
  * @memberOf CrudFieldComponent
5405
5452
  */
5406
5453
  this.hidden = false;
5454
+ /**
5455
+ * @description Whether the field is read-only.
5456
+ * @summary When true, the field will be rendered in a read-only state. Unlike disabled fields,
5457
+ * read-only fields are still focusable but cannot be modified by the user.
5458
+ *
5459
+ * @type {boolean}
5460
+ * @memberOf CrudFieldComponent
5461
+ */
5462
+ this.readonly = false;
5407
5463
  /**
5408
5464
  * @description Interface style for select inputs.
5409
5465
  * @summary Specifies the interface style for select inputs, such as 'alert', 'action-sheet', or 'popover'.
@@ -5561,8 +5617,11 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5561
5617
  this.options = this.options();
5562
5618
  }
5563
5619
  else {
5564
- const repo = getModelRepository(this.options?.['name']);
5565
- this.options = await repo?.select().execute();
5620
+ const repo = getModelAndRepository(this.options?.['name']);
5621
+ if (repo) {
5622
+ const { repository } = repo;
5623
+ this.options = await repository.select().execute();
5624
+ }
5566
5625
  }
5567
5626
  }
5568
5627
  }
@@ -5607,11 +5666,10 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5607
5666
  * This ensures proper initialization of read-only fields that don't require
5608
5667
  * form functionality but still need view setup.
5609
5668
  *
5610
- * @returns {void}
5669
+ * @returns {Promise<void>}
5611
5670
  * @memberOf CrudFieldComponent
5612
5671
  */
5613
- ngAfterViewInit() {
5614
- super.afterViewInit();
5672
+ async ngAfterViewInit() {
5615
5673
  if (this.type === HTML5InputTypes.RADIO && !this.value)
5616
5674
  this.setValue(this.options[0].value); // TODO: migrate to RenderingEngine
5617
5675
  }
@@ -5665,7 +5723,7 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5665
5723
  this.value = this.formControl.value;
5666
5724
  }
5667
5725
  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" }] }); }
5726
+ 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
5727
  };
5670
5728
  CrudFieldComponent = __decorate([
5671
5729
  Dynamic()
@@ -5685,7 +5743,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
5685
5743
  IonLabel,
5686
5744
  IonText,
5687
5745
  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"] }]
5746
+ ], 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
5747
  }], propDecorators: { operation: [{
5690
5748
  type: Input,
5691
5749
  args: [{ required: true }]
@@ -5934,7 +5992,7 @@ class NgxFormDirective extends NgxParentComponentDirective {
5934
5992
  this.formGroup = undefined;
5935
5993
  this.initialized = true;
5936
5994
  }
5937
- ngAfterViewInit() {
5995
+ async ngAfterViewInit() {
5938
5996
  if (this.isModalChild)
5939
5997
  this.changeDetectorRef.detectChanges();
5940
5998
  }
@@ -6108,10 +6166,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
6108
6166
  * @param {string} title - Primary title text displayed in the card header.
6109
6167
  * @param {('small'|'default'|'blank')} body - Body size preset controlling padding/typography; defaults to 'default'.
6110
6168
  * @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.
6169
+ * @param {Color} color - Ionic color token applied to the card header/title.
6112
6170
  * @param {boolean} separator - When true, renders a divider between header and body.
6113
6171
  * @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.
6172
+ * @param {string|SafeHtml} inlineContent - Inline HTML/SafeHtml to render inside the body.
6115
6173
  * @param {('top'|'bottom')} inlineContentPosition - Where to render `inlineContent` relative to the body; defaults to 'bottom'.
6116
6174
  * @return {void}
6117
6175
  * @class CardComponent
@@ -6173,7 +6231,7 @@ let CardComponent = class CardComponent extends NgxComponentDirective {
6173
6231
  /**
6174
6232
  * @description Ionic color token applied to the card.
6175
6233
  * @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}
6234
+ * @type {Color}
6177
6235
  * @default ''
6178
6236
  */
6179
6237
  this.color = '';
@@ -6215,7 +6273,6 @@ let CardComponent = class CardComponent extends NgxComponentDirective {
6215
6273
  * @return {void}
6216
6274
  */
6217
6275
  ngOnInit() {
6218
- console.log(this.componentName, this.borders);
6219
6276
  this.mediaService.isDarkMode().subscribe(isDark => {
6220
6277
  this.isDarkMode = isDark;
6221
6278
  this.mediaService.toggleClass([this.component], AngularEngineKeys.DARK_PALETTE_CLASS, this.isDarkMode);
@@ -6589,12 +6646,10 @@ let IconComponent = class IconComponent {
6589
6646
  this.type = 'image';
6590
6647
  this.isSvg = this.name.endsWith('.svg');
6591
6648
  }
6592
- this.initialized = true;
6593
- }
6594
- ngAfterViewInit() {
6595
6649
  this.mediaService.isDarkMode().subscribe(isDark => {
6596
6650
  this.isDarkMode = isDark;
6597
6651
  });
6652
+ this.initialized = true;
6598
6653
  }
6599
6654
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6600
6655
  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 +7076,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7021
7076
  * @memberOf FieldsetComponent
7022
7077
  */
7023
7078
  constructor() {
7024
- super("FieldsetComponent");
7079
+ super('FieldsetComponent');
7025
7080
  /**
7026
7081
  * @description The parent component identifier for hierarchical fieldset relationships.
7027
7082
  * @summary Specifies the parent component name that this fieldset belongs to in a hierarchical
@@ -7196,8 +7251,10 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7196
7251
  }
7197
7252
  if (!this.formGroup && this.parentForm instanceof FormArray)
7198
7253
  this.formGroup = this.parentForm;
7199
- if (!this.formGroup && this.children[0]?.['formGroup'] instanceof FormGroup)
7200
- this.formGroup = this.children[0]?.['formGroup'].parent;
7254
+ if (!this.formGroup &&
7255
+ this.children[0]?.['formGroup'] instanceof FormGroup)
7256
+ this.formGroup = this.children[0]?.['formGroup']
7257
+ .parent;
7201
7258
  if (this.formGroup && !(this.formGroup instanceof FormArray))
7202
7259
  this.formGroup = this.formGroup?.parent;
7203
7260
  }
@@ -7216,36 +7273,36 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7216
7273
  this.initialized = true;
7217
7274
  }
7218
7275
  /**
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();
7276
+ * @description Initializes the component state after view and child components are rendered.
7277
+ * @summary This lifecycle hook implements intelligent auto-state management based on the current
7278
+ * CRUD operation. For READ and DELETE operations, the fieldset automatically opens to provide
7279
+ * immediate access to information, while CREATE and UPDATE operations keep it closed to maintain
7280
+ * a clean initial interface. The method directly manipulates the DOM to ensure proper accordion
7281
+ * synchronization and triggers change detection to reflect the programmatic state changes.
7282
+ *
7283
+ * @mermaid
7284
+ * sequenceDiagram
7285
+ * participant A as Angular Lifecycle
7286
+ * participant F as FieldsetComponent
7287
+ * participant D as DOM
7288
+ * participant C as ChangeDetector
7289
+ *
7290
+ * A->>F: ngAfterViewInit()
7291
+ * alt operation is READ or DELETE
7292
+ * F->>F: Set isOpen = true
7293
+ * F->>D: Query ion-accordion-group element
7294
+ * alt accordion element exists
7295
+ * F->>D: Set value attribute to 'open'
7296
+ * end
7297
+ * end
7298
+ * F->>C: detectChanges()
7299
+ * C->>F: Update view with new state
7300
+ *
7301
+ * @returns {Promise<void>}
7302
+ * @memberOf FieldsetComponent
7303
+ */
7304
+ async ngAfterViewInit() {
7305
+ await super.ngAfterViewInit();
7249
7306
  // if (!this.collapsable)
7250
7307
  // this.isOpen = true;
7251
7308
  // if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE) {
@@ -7326,7 +7383,9 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7326
7383
  const value = formGroup.value;
7327
7384
  const hasSomeValue = this.hasValue(value);
7328
7385
  if (hasSomeValue) {
7329
- const action = this.updatingItem ? OperationKeys.UPDATE : OperationKeys.CREATE;
7386
+ const action = this.updatingItem
7387
+ ? OperationKeys.UPDATE
7388
+ : OperationKeys.CREATE;
7330
7389
  const isValid = NgxFormService.validateFields(formGroup);
7331
7390
  // must pass correct pk here
7332
7391
  const isUnique = NgxFormService.isUniqueOnGroup(formGroup, action, action === OperationKeys.UPDATE ? this.updatingItem?.index : undefined);
@@ -7336,12 +7395,15 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7336
7395
  this.isUniqueError = this.updatingItem = undefined;
7337
7396
  this.setValue();
7338
7397
  NgxFormService.addGroupToParent(formGroup.parent);
7339
- this.activeFormGroupIndex = formGroup.parent.length - 1;
7398
+ this.activeFormGroupIndex =
7399
+ formGroup.parent.length - 1;
7340
7400
  this.activePage = this.getActivePage();
7341
7401
  }
7342
7402
  else {
7343
- this.isUniqueError = typeof value === ReservedModels.OBJECT ?
7344
- value?.[this.pk] || undefined : value;
7403
+ this.isUniqueError =
7404
+ typeof value === ReservedModels.OBJECT.name.toLowerCase()
7405
+ ? value?.[this.pk] || undefined
7406
+ : value;
7345
7407
  }
7346
7408
  }
7347
7409
  }
@@ -7387,7 +7449,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7387
7449
  const formArray = this.formGroup;
7388
7450
  if (formArray.length === 1) {
7389
7451
  const currentGroup = formArray.at(0);
7390
- Object.keys(currentGroup?.controls).forEach(controlName => {
7452
+ Object.keys(currentGroup?.controls).forEach((controlName) => {
7391
7453
  currentGroup.get(controlName)?.setValue(null);
7392
7454
  });
7393
7455
  }
@@ -7430,7 +7492,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7430
7492
  // reorder visual data
7431
7493
  const itemToMove = items.splice(fromIndex, 1)[0];
7432
7494
  items.splice(toIndex, 0, itemToMove);
7433
- items.forEach((item, index) => item['index'] = index + 1);
7495
+ items.forEach((item, index) => (item['index'] = index + 1));
7434
7496
  // reorder FormArray controls
7435
7497
  const controlToMove = formArray.at(fromIndex);
7436
7498
  formArray.removeAt(fromIndex);
@@ -7514,10 +7576,13 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7514
7576
  this.accordionComponent.value = 'open';
7515
7577
  this.changeDetectorRef.detectChanges();
7516
7578
  this.timerSubscription = timer(10).subscribe(() => {
7517
- this.children = this.children.map(child => {
7579
+ this.children = this.children.map((child) => {
7518
7580
  if (!child.props)
7519
7581
  child.props = {};
7520
- child.props = Object.assign(child.props, { activeFormGroup: this.activeFormGroupIndex, multiple: this.multiple });
7582
+ child.props = Object.assign(child.props, {
7583
+ activeFormGroup: this.activeFormGroupIndex,
7584
+ multiple: this.multiple,
7585
+ });
7521
7586
  return child;
7522
7587
  });
7523
7588
  });
@@ -7538,11 +7603,11 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7538
7603
  setValue() {
7539
7604
  this.value = this.formGroup.controls.map(({ value }) => value);
7540
7605
  this.items = this.value
7541
- .filter(v => (v[this.pk] || "").trim().length)
7606
+ .filter((v) => (v[this.pk] || '').trim().length)
7542
7607
  .map((v, index) => {
7543
7608
  return {
7544
7609
  ...itemMapper(Object.assign({}, v), this.mapper),
7545
- index: index + 1
7610
+ index: index + 1,
7546
7611
  };
7547
7612
  });
7548
7613
  this.updatingItem = undefined;
@@ -7563,9 +7628,10 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
7563
7628
  this.pk = Object.keys(value)[0];
7564
7629
  if (!Object.keys(this.mapper).length)
7565
7630
  this.mapper['title'] = this.pk;
7566
- this.mapper['index'] = "index";
7631
+ this.mapper['index'] = 'index';
7567
7632
  for (const key in value) {
7568
- if (Object.keys(this.mapper).length >= 2 || Object.keys(this.mapper).length === Object.keys(value).length)
7633
+ if (Object.keys(this.mapper).length >= 2 ||
7634
+ Object.keys(this.mapper).length === Object.keys(value).length)
7569
7635
  break;
7570
7636
  if (!this.mapper['title']) {
7571
7637
  this.mapper['title'] = key;
@@ -7598,7 +7664,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
7598
7664
  IonReorderGroup,
7599
7665
  IonButton,
7600
7666
  IonIcon,
7601
- LayoutComponent
7667
+ LayoutComponent,
7602
7668
  ], 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"] }]
7603
7669
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
7604
7670
  type: ViewChild,
@@ -9936,7 +10002,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9936
10002
  // (self.data as ListItem[]) = [];
9937
10003
  if (!this.searchValue?.length && !this.searchValue) {
9938
10004
  if (!this.source && !this.data?.length) {
9939
- this.logger.info('No data and source passed to infinite list');
10005
+ this.log.info('No data and source passed to infinite list');
9940
10006
  return [];
9941
10007
  }
9942
10008
  if (this.source instanceof Function) {
@@ -10017,7 +10083,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10017
10083
  data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
10018
10084
  }
10019
10085
  catch (error) {
10020
- this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
10086
+ this.log.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
10021
10087
  }
10022
10088
  }
10023
10089
  if (data?.length) {
@@ -10127,11 +10193,11 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10127
10193
  if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
10128
10194
  const paginator = result;
10129
10195
  try {
10130
- result = paginator.page.length > 0 ? await paginator.page(this.page) : [];
10196
+ result = await paginator.page(this.page);
10131
10197
  this.getMoreData(paginator.total);
10132
10198
  }
10133
10199
  catch (error) {
10134
- this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
10200
+ this.log.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
10135
10201
  result = [];
10136
10202
  }
10137
10203
  }
@@ -10491,7 +10557,7 @@ let ListItemComponent = class ListItemComponent extends NgxComponentDirective {
10491
10557
  this.className += ` action`;
10492
10558
  this.windowWidth = getWindowWidth();
10493
10559
  }
10494
- ngAfterViewInit() {
10560
+ async ngAfterViewInit() {
10495
10561
  this.checkDarkMode();
10496
10562
  }
10497
10563
  /**
@@ -11391,7 +11457,7 @@ let FileUploadComponent = class FileUploadComponent extends NgxFormFieldDirectiv
11391
11457
  return xmlDoc.documentElement.innerHTML;
11392
11458
  }
11393
11459
  catch (error) {
11394
- this.logger.error(error?.message);
11460
+ this.log.error(error?.message);
11395
11461
  return undefined;
11396
11462
  }
11397
11463
  };
@@ -11956,14 +12022,21 @@ class NgxModelPageDirective extends NgxPageDirective {
11956
12022
  * @throws {InternalError} When the model is not found in the registry
11957
12023
  */
11958
12024
  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();
12025
+ try {
12026
+ if (!this._repository) {
12027
+ const constructor = Model.get(this.modelName);
12028
+ if (!constructor)
12029
+ throw new InternalError('Cannot find model. was it registered with @model?');
12030
+ this._repository = Repository.forModel(constructor);
12031
+ if (!this.pk)
12032
+ this.pk = this._repository.pk;
12033
+ this.model = new constructor();
12034
+ }
12035
+ }
12036
+ catch (error) {
12037
+ this.log.warn(`Error getting repository for model: ${this.modelName}. ${error.message}`);
12038
+ this._repository = undefined;
12039
+ // throw new InternalError((error as Error)?.message || (error as string));
11967
12040
  }
11968
12041
  return this._repository;
11969
12042
  }
@@ -11993,21 +12066,13 @@ class NgxModelPageDirective extends NgxPageDirective {
11993
12066
  async refresh(uid) {
11994
12067
  if (!uid)
11995
12068
  uid = this.modelId;
11996
- try {
11997
- this._repository = this.repository;
11998
- switch (this.operation) {
11999
- case OperationKeys.READ:
12000
- case OperationKeys.UPDATE:
12001
- case OperationKeys.DELETE:
12002
- this.model = await this.handleGet(uid || this.modelId);
12003
- break;
12004
- }
12005
- }
12006
- catch (error) {
12007
- if (error instanceof NotFoundError) {
12008
- this.errorMessage = error.message;
12009
- }
12010
- this.logger.error(error);
12069
+ this._repository = this.repository;
12070
+ switch (this.operation) {
12071
+ case OperationKeys.READ:
12072
+ case OperationKeys.UPDATE:
12073
+ case OperationKeys.DELETE:
12074
+ this.model = await this.handleGet(uid || this.modelId, this._repository, this.modelName);
12075
+ break;
12011
12076
  }
12012
12077
  }
12013
12078
  /**
@@ -12062,7 +12127,7 @@ class NgxModelPageDirective extends NgxPageDirective {
12062
12127
  };
12063
12128
  }
12064
12129
  catch (error) {
12065
- this.logger.error(error);
12130
+ this.log.error(error);
12066
12131
  return {
12067
12132
  ...event,
12068
12133
  success: false,
@@ -12080,17 +12145,49 @@ class NgxModelPageDirective extends NgxPageDirective {
12080
12145
  * @param {string} uid - The unique identifier of the model instance to retrieve
12081
12146
  * @return {Promise<Model | undefined>} Promise resolving to the model instance or undefined
12082
12147
  */
12083
- async handleGet(uid) {
12148
+ async handleGet(uid, repository, modelName) {
12084
12149
  if (!uid) {
12085
- this.logger.info('No key passed to model page read operation, backing to last page');
12150
+ this.log.info('No key passed to model page read operation, backing to last page');
12086
12151
  this.location.back();
12087
12152
  return undefined;
12088
12153
  }
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;
12154
+ const getRepository = async (modelName, parent, model) => {
12155
+ if (this._repository)
12156
+ return this._repository;
12157
+ const constructor = Model.get(modelName);
12158
+ if (constructor) {
12159
+ const properties = Metadata.properties(constructor);
12160
+ if (!model)
12161
+ model = {};
12162
+ for (const prop of properties) {
12163
+ const type = Metadata.type(constructor, prop).name;
12164
+ const context = getModelAndRepository(type);
12165
+ if (!context)
12166
+ return getRepository(type, prop, model);
12167
+ const { repository } = context;
12168
+ if (modelName === this.modelName) {
12169
+ const data = await this.handleGet(uid, repository, modelName);
12170
+ this.model = Model.build({ [prop]: data }, modelName);
12171
+ }
12172
+ else {
12173
+ model[prop] = Model.build({}, type);
12174
+ }
12175
+ }
12176
+ this.model[parent] = Model.build(model, modelName);
12177
+ }
12178
+ };
12179
+ repository = (repository || await getRepository(modelName));
12180
+ if (!repository)
12181
+ return this.model;
12182
+ const type = Metadata.type(repository.class, repository.pk).name;
12183
+ try {
12184
+ const result = await repository.read(([Primitives.NUMBER, Primitives.BIGINT].includes(type.toLowerCase()) ? Number(uid) : uid));
12185
+ return result;
12186
+ }
12187
+ catch (error) {
12188
+ this.log.for(this.handleGet).info(`Error getting model instance with id ${uid}: ${error.message}`);
12189
+ return undefined;
12190
+ }
12094
12191
  }
12095
12192
  /**
12096
12193
  * @description Parses and transforms form data for repository operations.
@@ -12156,5 +12253,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
12156
12253
  * Generated bundle index. Do not edit.
12157
12254
  */
12158
12255
 
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 };
12256
+ 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
12257
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map