ng-tailwind 7.0.18 → 7.0.20

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.
@@ -70,7 +70,7 @@ export declare class NgtDropzoneComponent extends NgtControlValueAccessor implem
70
70
  ngAfterContentChecked(): void;
71
71
  ngOnInit(): void;
72
72
  ngOnDestroy(): void;
73
- imagePreview(index: any): void;
73
+ imagePreview(uploadedResourcesIndex: number): void;
74
74
  onImageClick(element: any, index?: any): void;
75
75
  onFileClick(url: string, name: string, size: number): void;
76
76
  onCloseFileViewer(): void;
@@ -1,7 +1,7 @@
1
1
  import { ChangeDetectorRef, ElementRef, EventEmitter, Injector, OnDestroy, OnInit, Renderer2, SimpleChanges, TemplateRef } from '@angular/core';
2
2
  import { AsyncValidatorFn, ControlContainer } from '@angular/forms';
3
- import { NgtControlValueAccessor } from '../../../../base/ngt-control-value-accessor';
4
3
  import { NgtStylizableDirective } from '../../../../directives/ngt-stylizable/ngt-stylizable.directive';
4
+ import { NgtControlValueAccessor } from '../../../../base/ngt-control-value-accessor';
5
5
  import { NgtHttpFindExistingResourceInterface, NgtHttpResourceService } from '../../../../services/http/ngt-http-resource.service';
6
6
  import { NgtHttpValidationService } from '../../../../services/http/ngt-http-validation.service';
7
7
  import { NgtTranslateService } from '../../../../services/http/ngt-translate.service';
@@ -103,6 +103,7 @@ export declare class NgtInputComponent extends NgtControlValueAccessor implement
103
103
  private initComponent;
104
104
  private updateValidations;
105
105
  private setupMasks;
106
+ private setupAlphanumericPasteHandler;
106
107
  private setupProperties;
107
108
  private minValueValidator;
108
109
  private multipleOfValidator;
@@ -115,9 +116,16 @@ export declare class NgtInputComponent extends NgtControlValueAccessor implement
115
116
  private searchExistingResource;
116
117
  private validatePhone;
117
118
  private uniqueValidator;
119
+ private validatorCNPJ;
120
+ private validatorNumericCNPJ;
121
+ private validatorAlphaNumericCNPJ;
122
+ private getCnpjVerificationDigit;
123
+ private getCnpjCharacterValue;
124
+ private validatorCPF;
118
125
  private getNativeValue;
119
126
  private getElementTitle;
120
127
  private removeMasks;
128
+ private normalizeDocument;
121
129
  private hasEmailServiceValidation;
122
130
  private hasPasswordValidation;
123
131
  private isDisabledByParent;
@@ -1,4 +1,4 @@
1
- import { ChangeDetectorRef, ElementRef, EventEmitter, Injector, OnDestroy, OnInit, SimpleChanges, TemplateRef } from '@angular/core';
1
+ import { ChangeDetectorRef, ElementRef, EventEmitter, Injector, OnDestroy, OnInit, SimpleChanges, TemplateRef, WritableSignal } from '@angular/core';
2
2
  import { NgtHttpService } from '../../services/http/ngt-http.service';
3
3
  import { NgtTranslateService } from '../../services/http/ngt-translate.service';
4
4
  import { NgtInputComponent } from '../forms/template-driven/ngt-input/ngt-input.component';
@@ -62,7 +62,6 @@ export declare class NgtDatatableComponent implements OnInit, OnDestroy {
62
62
  onSearch: EventEmitter<any>;
63
63
  searchModalTemplate: TemplateRef<any>;
64
64
  data: any[];
65
- loading: boolean;
66
65
  cleaningFilter: boolean;
67
66
  componentReady: boolean;
68
67
  filtersTranslated: any[];
@@ -70,12 +69,15 @@ export declare class NgtDatatableComponent implements OnInit, OnDestroy {
70
69
  columnCount: any[];
71
70
  hasSelectedAllElements: boolean;
72
71
  selectedElements: Array<NgtCheckedElement>;
72
+ readonly loadingSignal: WritableSignal<boolean>;
73
73
  filterModalStyle: NgtStylizableService;
74
74
  private searching;
75
75
  private searchTimeout;
76
76
  private subscriptions;
77
77
  private currentState;
78
78
  constructor(injector: Injector, ngtHttpService: NgtHttpService, changeDetector: ChangeDetectorRef, ngtTranslateService: NgtTranslateService);
79
+ get loading(): boolean;
80
+ set loading(value: boolean);
79
81
  ngOnInit(): void;
80
82
  ngOnDestroy(): void;
81
83
  setSearchModalTemplate(template: TemplateRef<any>): void;
@@ -2310,99 +2310,6 @@ function removeInputMask(element) {
2310
2310
  Inputmask.remove(element);
2311
2311
  }
2312
2312
 
2313
- /**
2314
- * Validates a Brazilian CNPJ (Cadastro Nacional da Pessoa Jurídica) number.
2315
- * CNPJ is a unique identifier for companies in Brazil.
2316
- *
2317
- * @param value - The CNPJ value to validate (can include formatting characters)
2318
- * @returns true if the CNPJ is valid, false otherwise
2319
- *
2320
- * @example
2321
- * validateCNPJ('11.222.333/0001-81'); // returns true or false
2322
- * validateCNPJ('11222333000181'); // returns true or false
2323
- */
2324
- function validateCNPJ(value) {
2325
- if (!value) {
2326
- return false;
2327
- }
2328
- // Validation weights for CNPJ verification digits
2329
- const weights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2330
- // Remove non-digit characters
2331
- const cleanedValue = value.replace(/[^\d]/g, '');
2332
- // Check if CNPJ has exactly 14 digits
2333
- if (cleanedValue.length !== 14) {
2334
- return false;
2335
- }
2336
- // Check if all digits are the same (invalid CNPJ)
2337
- if (/^(\d)\1{13}$/.test(cleanedValue)) {
2338
- return false;
2339
- }
2340
- // Validate first verification digit
2341
- let sum = 0;
2342
- for (let i = 0; i < 12; i++) {
2343
- sum += parseInt(cleanedValue[i]) * weights[i + 1];
2344
- }
2345
- const firstDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
2346
- if (parseInt(cleanedValue[12]) !== firstDigit) {
2347
- return false;
2348
- }
2349
- // Validate second verification digit
2350
- sum = 0;
2351
- for (let i = 0; i < 13; i++) {
2352
- sum += parseInt(cleanedValue[i]) * weights[i];
2353
- }
2354
- const secondDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
2355
- if (parseInt(cleanedValue[13]) !== secondDigit) {
2356
- return false;
2357
- }
2358
- return true;
2359
- }
2360
- /**
2361
- * Validates a Brazilian CPF (Cadastro de Pessoas Físicas) number.
2362
- * CPF is a unique identifier for individuals in Brazil.
2363
- *
2364
- * @param value - The CPF value to validate (can include formatting characters)
2365
- * @returns true if the CPF is valid, false otherwise
2366
- *
2367
- * @example
2368
- * validateCPF('123.456.789-09'); // returns true or false
2369
- * validateCPF('12345678909'); // returns true or false
2370
- */
2371
- function validateCPF(value) {
2372
- if (!value) {
2373
- return false;
2374
- }
2375
- // Remove non-digit characters
2376
- const cleanedValue = value.replace(/[^\d]/g, '');
2377
- // Check if CPF has exactly 11 digits
2378
- if (cleanedValue.length !== 11) {
2379
- return false;
2380
- }
2381
- // Check if all digits are the same (invalid CPF)
2382
- if (/^(\d)\1{10}$/.test(cleanedValue)) {
2383
- return false;
2384
- }
2385
- // Validate first verification digit
2386
- let sum = 0;
2387
- for (let i = 0; i < 9; i++) {
2388
- sum += parseInt(cleanedValue[i]) * (10 - i);
2389
- }
2390
- const firstDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
2391
- if (parseInt(cleanedValue[9]) !== firstDigit) {
2392
- return false;
2393
- }
2394
- // Validate second verification digit
2395
- sum = 0;
2396
- for (let i = 0; i < 10; i++) {
2397
- sum += parseInt(cleanedValue[i]) * (11 - i);
2398
- }
2399
- const secondDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
2400
- if (parseInt(cleanedValue[10]) !== secondDigit) {
2401
- return false;
2402
- }
2403
- return true;
2404
- }
2405
-
2406
2313
  class NgtInputComponent extends NgtControlValueAccessor {
2407
2314
  constructor(renderer, changeDetector, ngtStylizableDirective, formContainer, ngtFormComponent, ngtValidationService, ngtResourceService, ngtForm, ngtSection, ngtModal, injector, ngtTranslateService) {
2408
2315
  super();
@@ -2691,15 +2598,25 @@ class NgtInputComponent extends NgtControlValueAccessor {
2691
2598
  removeInputMask(this.element.nativeElement);
2692
2599
  return this.clearInput();
2693
2600
  }
2601
+ const cnpjMaskPattern = 'XX.XXX.XXX/XXXX-99';
2602
+ const onBeforeCnpjPaste = (pastedValue) => pastedValue.toUpperCase().replace(/[^A-Z0-9]/g, '');
2603
+ const cnpjMaskParameters = {
2604
+ mask: [cnpjMaskPattern],
2605
+ definitions: {
2606
+ X: {
2607
+ validator: '[0-9A-Za-z]',
2608
+ casing: 'upper'
2609
+ }
2610
+ },
2611
+ showMaskOnHover: false,
2612
+ onBeforePaste: onBeforeCnpjPaste
2613
+ };
2694
2614
  let masks = {
2695
2615
  [InputMaskEnum.CPF]: {
2696
2616
  mask: ['999.999.999-99'],
2697
2617
  showMaskOnHover: false
2698
2618
  },
2699
- [InputMaskEnum.CNPJ]: {
2700
- mask: ['99.999.999/9999-99'],
2701
- showMaskOnHover: false
2702
- },
2619
+ [InputMaskEnum.CNPJ]: cnpjMaskParameters,
2703
2620
  [InputMaskEnum.CUIT]: {
2704
2621
  mask: ['99-99999999-9'],
2705
2622
  clearMaskOnLostFocus: false
@@ -2709,14 +2626,16 @@ class NgtInputComponent extends NgtControlValueAccessor {
2709
2626
  clearMaskOnLostFocus: false
2710
2627
  },
2711
2628
  [InputMaskEnum.CPF_CNPJ_RUT]: {
2712
- mask: ['999.999.999-99', '999999999999', '99.999.999/9999-99'],
2713
- keepStatic: true,
2714
- showMaskOnHover: false
2629
+ mask: ['999.999.999-99', '999999999999', cnpjMaskPattern],
2630
+ definitions: cnpjMaskParameters.definitions,
2631
+ showMaskOnHover: false,
2632
+ onBeforePaste: onBeforeCnpjPaste
2715
2633
  },
2716
2634
  [InputMaskEnum.CPF_CNPJ]: {
2717
- mask: ['999.999.999-99', '99.999.999/9999-99'],
2718
- keepStatic: true,
2719
- showMaskOnHover: false
2635
+ mask: ['999.999.999-99', cnpjMaskPattern],
2636
+ definitions: cnpjMaskParameters.definitions,
2637
+ showMaskOnHover: false,
2638
+ onBeforePaste: onBeforeCnpjPaste
2720
2639
  },
2721
2640
  [InputMaskEnum.DECIMAL]: {
2722
2641
  digits: this.decimalMaskPrecision,
@@ -2768,6 +2687,39 @@ class NgtInputComponent extends NgtControlValueAccessor {
2768
2687
  else {
2769
2688
  applyInputMask(this.element.nativeElement, masks[this.mask]);
2770
2689
  }
2690
+ if (this.mask == InputMaskEnum.CPF_CNPJ || this.mask == InputMaskEnum.CPF_CNPJ_RUT) {
2691
+ this.setupAlphanumericPasteHandler();
2692
+ }
2693
+ }
2694
+ setupAlphanumericPasteHandler() {
2695
+ const handler = (event) => {
2696
+ const pastedText = event.clipboardData?.getData('text/plain') ?? '';
2697
+ const normalized = pastedText.toUpperCase().replace(/[^A-Z0-9]/g, '');
2698
+ if (normalized.length !== 14 || !/[A-Z]/.test(normalized)) {
2699
+ return;
2700
+ }
2701
+ event.preventDefault();
2702
+ event.stopImmediatePropagation();
2703
+ const formatted = `${normalized.substring(0, 2)}.${normalized.substring(2, 5)}.${normalized.substring(5, 8)}/${normalized.substring(8, 12)}-${normalized.substring(12, 14)}`;
2704
+ const input = this.element.nativeElement;
2705
+ const inputmaskInstance = input.inputmask;
2706
+ const alphaMaskOptions = {
2707
+ mask: ['XX.XXX.XXX/XXXX-99'],
2708
+ definitions: { X: { validator: '[0-9A-Za-z]', casing: 'upper' } },
2709
+ showMaskOnHover: false
2710
+ };
2711
+ if (inputmaskInstance && typeof inputmaskInstance.option === 'function') {
2712
+ inputmaskInstance.option(alphaMaskOptions);
2713
+ }
2714
+ else {
2715
+ removeInputMask(input);
2716
+ Inputmask(alphaMaskOptions).mask(input);
2717
+ }
2718
+ input.value = formatted;
2719
+ input.dispatchEvent(new Event('input', { bubbles: true }));
2720
+ input.dispatchEvent(new Event('change', { bubbles: true }));
2721
+ };
2722
+ this.element.nativeElement.addEventListener('paste', handler, true);
2771
2723
  }
2772
2724
  setupProperties() {
2773
2725
  let props = {
@@ -2844,19 +2796,20 @@ class NgtInputComponent extends NgtControlValueAccessor {
2844
2796
  if (!control.value) {
2845
2797
  return null;
2846
2798
  }
2847
- if (control.value && control.value.length <= 11) {
2848
- if (validateCPF(control.value)) {
2799
+ const normalizedDocument = this.removeMasks(control.value);
2800
+ if (normalizedDocument && normalizedDocument.length <= 11) {
2801
+ if (this.validatorCPF(normalizedDocument)) {
2849
2802
  return null;
2850
2803
  }
2851
2804
  else {
2852
2805
  return { 'cpf': true };
2853
2806
  }
2854
2807
  }
2855
- else if (control.value && control.value.length == 12) {
2808
+ else if (normalizedDocument && normalizedDocument.length == 12) {
2856
2809
  return null;
2857
2810
  }
2858
2811
  else {
2859
- if (control.value && validateCNPJ(control.value)) {
2812
+ if (normalizedDocument && this.validatorCNPJ(normalizedDocument)) {
2860
2813
  return null;
2861
2814
  }
2862
2815
  else {
@@ -2975,6 +2928,102 @@ class NgtInputComponent extends NgtControlValueAccessor {
2975
2928
  return Promise.resolve(null);
2976
2929
  };
2977
2930
  }
2931
+ validatorCNPJ(value) {
2932
+ const normalizedValue = this.normalizeDocument(value);
2933
+ if (normalizedValue.length != 14) {
2934
+ return false;
2935
+ }
2936
+ return /[A-Z]/.test(normalizedValue)
2937
+ ? this.validatorAlphaNumericCNPJ(normalizedValue)
2938
+ : this.validatorNumericCNPJ(normalizedValue);
2939
+ }
2940
+ validatorNumericCNPJ(value) {
2941
+ const b = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2942
+ if ((value = value.replace(/[^\d]/g, "")).length != 14) {
2943
+ return false;
2944
+ }
2945
+ if (/0{14}/.test(value)) {
2946
+ return false;
2947
+ }
2948
+ let n = 0;
2949
+ for (let i = 0; i < 12; i++) {
2950
+ n += Number(value[i]) * b[i + 1];
2951
+ }
2952
+ if (Number(value[12]) != (((n %= 11) < 2) ? 0 : 11 - n)) {
2953
+ return false;
2954
+ }
2955
+ n = 0;
2956
+ for (let i = 0; i <= 12; i++) {
2957
+ n += Number(value[i]) * b[i];
2958
+ }
2959
+ if (Number(value[13]) != (((n %= 11) < 2) ? 0 : 11 - n)) {
2960
+ return false;
2961
+ }
2962
+ return true;
2963
+ }
2964
+ validatorAlphaNumericCNPJ(value) {
2965
+ if (!/^[A-Z0-9]{12}[0-9]{2}$/.test(value)) {
2966
+ return false;
2967
+ }
2968
+ const firstWeights = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2969
+ const firstDigit = this.getCnpjVerificationDigit(value.substring(0, 12), firstWeights);
2970
+ if (firstDigit !== Number(value[12])) {
2971
+ return false;
2972
+ }
2973
+ const secondWeights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
2974
+ const secondDigit = this.getCnpjVerificationDigit(`${value.substring(0, 12)}${firstDigit}`, secondWeights);
2975
+ return secondDigit === Number(value[13]);
2976
+ }
2977
+ getCnpjVerificationDigit(value, weights) {
2978
+ const weightedTotal = value
2979
+ .split('')
2980
+ .reduce((total, currentValue, index) => total + (this.getCnpjCharacterValue(currentValue) * weights[index]), 0);
2981
+ const modulo = weightedTotal % 11;
2982
+ return modulo < 2 ? 0 : 11 - modulo;
2983
+ }
2984
+ getCnpjCharacterValue(value) {
2985
+ return /^[0-9]$/.test(value)
2986
+ ? Number(value)
2987
+ : value.charCodeAt(0) - 48;
2988
+ }
2989
+ validatorCPF(value) {
2990
+ let numeros, digitos, soma, i, resultado, digitos_iguais;
2991
+ digitos_iguais = 1;
2992
+ if (value.length < 11) {
2993
+ return false;
2994
+ }
2995
+ for (i = 0; i < value.length - 1; i++) {
2996
+ if (value.charAt(i) != value.charAt(i + 1)) {
2997
+ digitos_iguais = 0;
2998
+ break;
2999
+ }
3000
+ }
3001
+ if (!digitos_iguais) {
3002
+ numeros = value.substring(0, 9);
3003
+ digitos = value.substring(9);
3004
+ soma = 0;
3005
+ for (i = 10; i > 1; i--) {
3006
+ soma += numeros.charAt(10 - i) * i;
3007
+ }
3008
+ resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
3009
+ if (resultado != digitos.charAt(0)) {
3010
+ return false;
3011
+ }
3012
+ numeros = value.substring(0, 10);
3013
+ soma = 0;
3014
+ for (i = 11; i > 1; i--) {
3015
+ soma += numeros.charAt(11 - i) * i;
3016
+ }
3017
+ resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
3018
+ if (resultado != digitos.charAt(1)) {
3019
+ return false;
3020
+ }
3021
+ return true;
3022
+ }
3023
+ else {
3024
+ return false;
3025
+ }
3026
+ }
2978
3027
  getNativeValue() {
2979
3028
  return this.element.nativeElement.value;
2980
3029
  }
@@ -2988,8 +3037,10 @@ class NgtInputComponent extends NgtControlValueAccessor {
2988
3037
  .replace(',', '.');
2989
3038
  }
2990
3039
  else if (this.mask == "cnpj-cpf" || this.mask == "cpf" || this.mask == "cnpj" || this.mask == "cnpj-cpf-rut" || this.mask == "cuit") {
2991
- value = (value + "")
2992
- .replace(/[^\d]/g, '');
3040
+ value = this.normalizeDocument(value);
3041
+ if (this.mask == "cpf" || this.mask == "cuit") {
3042
+ value = value.replace(/[^\d]/g, '');
3043
+ }
2993
3044
  }
2994
3045
  else if (this.mask == InputMaskEnum.CELLPHONE
2995
3046
  || this.mask == InputMaskEnum.INTERNATIONAL_PHONE) {
@@ -3003,6 +3054,12 @@ class NgtInputComponent extends NgtControlValueAccessor {
3003
3054
  }
3004
3055
  return value;
3005
3056
  }
3057
+ normalizeDocument(value) {
3058
+ return (value || '')
3059
+ .toString()
3060
+ .toUpperCase()
3061
+ .replace(/[^A-Z0-9]/g, '');
3062
+ }
3006
3063
  hasEmailServiceValidation() {
3007
3064
  return typeof this.ngtValidationService?.emailValidation === 'function';
3008
3065
  }
@@ -4260,12 +4317,12 @@ class NgtDatatableComponent {
4260
4317
  this.onOpenSearchModal = new EventEmitter();
4261
4318
  this.onSearch = new EventEmitter();
4262
4319
  this.data = [];
4263
- this.loading = false;
4264
4320
  this.cleaningFilter = false;
4265
4321
  this.componentReady = false;
4266
4322
  this.filtersTranslated = [];
4267
4323
  this.columnCount = [];
4268
4324
  this.selectedElements = [];
4325
+ this.loadingSignal = signal(false);
4269
4326
  this.filterModalStyle = new NgtStylizableService();
4270
4327
  this.subscriptions = [];
4271
4328
  this.currentState = {
@@ -4288,6 +4345,12 @@ class NgtDatatableComponent {
4288
4345
  color: {}
4289
4346
  });
4290
4347
  }
4348
+ get loading() {
4349
+ return this.loadingSignal();
4350
+ }
4351
+ set loading(value) {
4352
+ this.loadingSignal.set(value);
4353
+ }
4291
4354
  ngOnInit() {
4292
4355
  if (this.table && this.table.nativeElement && this.table.nativeElement.rows
4293
4356
  && this.table.nativeElement.rows[0] && this.table.nativeElement.rows[0].cells) {
@@ -4613,11 +4676,11 @@ class NgtDatatableComponent {
4613
4676
  this.subscriptions = [];
4614
4677
  }
4615
4678
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgtDatatableComponent, deps: [{ token: i0.Injector }, { token: NgtHttpService }, { token: i0.ChangeDetectorRef }, { token: NgtTranslateService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
4616
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: NgtDatatableComponent, isStandalone: false, selector: "ngt-datatable", inputs: { remoteResource: "remoteResource", type: "type", filterTagBgColor: "filterTagBgColor", filterTagMargin: "filterTagMargin", paginationMargin: "paginationMargin", inputSearch: "inputSearch", searchDelay: "searchDelay", searchTermMinLength: "searchTermMinLength", searchTermOnEnter: "searchTermOnEnter", defaultFilters: "defaultFilters", filtersDescription: "filtersDescription", canSelectAllRegisters: "canSelectAllRegisters", headBgColor: "headBgColor" }, outputs: { onDataChange: "onDataChange", onClearFilter: "onClearFilter", onClearSelectedElements: "onClearSelectedElements", onSelectedElementsChange: "onSelectedElementsChange", onToogleAllCheckboxes: "onToogleAllCheckboxes", onToogleCheckbox: "onToogleCheckbox", onSelectAllRegisters: "onSelectAllRegisters", onOpenSearchModal: "onOpenSearchModal", onSearch: "onSearch" }, viewQueries: [{ propertyName: "table", first: true, predicate: ["table"], descendants: true, static: true }, { propertyName: "ngtPagination", first: true, predicate: ["ngtPagination"], descendants: true, static: true }, { propertyName: "searchModal", first: true, predicate: ["searchModal"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"w-full\">\n <div class=\"flex flex-wrap w-full\">\n <ngt-tag *ngIf=\"hasAppliedFilters()\" class=\"w-full sm:w-auto {{ filterTagMargin }}\"\n [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\" color.bg=\"bg-red-500\" (click)=\"removeFilter()\" ngt-stylizable>\n Limpar Filtros\n </ngt-tag>\n\n <ng-container *ngIf=\"hasAppliedFilters()\">\n <ng-container *ngFor=\"let filter of filtersTranslated\">\n <ngt-tag class=\"w-full sm:w-auto {{ filterTagMargin }}\" [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\"\n [color.bg]=\"filterTagBgColor\" (click)=\"removeFilter(filter.reference)\" ngt-stylizable\n [title]=\"getTitle(filter)\">\n {{ filter.translation + ': ' + getTagFilterValue(filter) }}\n </ngt-tag>\n </ng-container>\n </ng-container>\n </div>\n\n <table style=\"display: table;\" class=\"text-left w-full border-collapse table-responsive\" #table>\n <ng-content></ng-content>\n </table>\n\n <p *ngIf=\"emptyStateVisible\" class=\"mt-8 mx-auto self-center text-center text-xl\">\n {{ ngtTranslateService.ngtDatatableNoDataFound }}\n </p>\n\n <div *ngIf=\"loading\">\n <div *ngFor=\"let i of [1, 2, 3, 4]\" class=\"flex w-full mt-3\">\n <ng-container *ngIf=\"columnCount.length >= 2\">\n <ng-container *ngFor=\"let j of columnCount; let last = last\">\n <ng-container *ngIf=\"last\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n\n <ng-container *ngIf=\"!last\">\n <ngt-shining class=\"h-10 w-full mr-10\"></ngt-shining>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"columnCount.length < 2\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full mr-10 ml-10\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n </div>\n </div>\n</div>\n\n<div class=\"clearfix {{ paginationMargin }}\" [hidden]='!data || data.length == 0'>\n <ngt-pagination [pagesInterval]='4' (onPageChange)='apply($event, false)' (onPerPageChange)='apply(1, false)'\n #ngtPagination>\n </ngt-pagination>\n</div>\n\n<ngt-modal [customLayout]=\"true\" [isDisabled]=\"false\" [ngtStyle]=\"filterModalStyle\" #searchModal>\n <ng-container *ngTemplateOutlet=\"searchModalTemplate\"></ng-container>\n</ngt-modal>", styles: ["@media (max-width: 767px){.table-responsive{display:block;position:relative;width:100%}.table-responsive thead,.table-responsive tbody,.table-responsive th,.table-responsive td,.table-responsive tr{display:block}.table-responsive td,.table-responsive th{height:50px}.table-responsive thead{float:left;margin-bottom:15px}.table-responsive tbody{width:auto;position:relative;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}.table-responsive tbody tr{display:inline-block;min-width:100%}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgtShiningComponent, selector: "ngt-shining", inputs: ["shiningWidth"] }, { kind: "component", type: NgtPaginationComponent, selector: "ngt-pagination", inputs: ["pagesInterval"], outputs: ["onPageChange", "onPerPageChange"] }, { kind: "component", type: NgtModalComponent, selector: "ngt-modal", inputs: ["customLayout", "disableDefaultCloses", "ngtStyle", "isDisabled"], outputs: ["onCloseModal", "onOpenModal"] }, { kind: "component", type: NgtTagComponent, selector: "ngt-tag", inputs: ["icon"] }, { kind: "directive", type: NgtStylizableDirective, selector: "[ngt-stylizable]", inputs: ["color", "color.text", "color.bg", "color.border", "h", "w", "p", "px", "py", "pt", "pr", "pb", "pl", "m", "mx", "my", "mt", "mr", "mb", "ml", "gap", "border", "shadow", "rounded", "font", "text", "breakWords", "overflow", "position", "justifyContent", "cursor", "fontCase"] }] }); }
4679
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: NgtDatatableComponent, isStandalone: false, selector: "ngt-datatable", inputs: { remoteResource: "remoteResource", type: "type", filterTagBgColor: "filterTagBgColor", filterTagMargin: "filterTagMargin", paginationMargin: "paginationMargin", inputSearch: "inputSearch", searchDelay: "searchDelay", searchTermMinLength: "searchTermMinLength", searchTermOnEnter: "searchTermOnEnter", defaultFilters: "defaultFilters", filtersDescription: "filtersDescription", canSelectAllRegisters: "canSelectAllRegisters", headBgColor: "headBgColor" }, outputs: { onDataChange: "onDataChange", onClearFilter: "onClearFilter", onClearSelectedElements: "onClearSelectedElements", onSelectedElementsChange: "onSelectedElementsChange", onToogleAllCheckboxes: "onToogleAllCheckboxes", onToogleCheckbox: "onToogleCheckbox", onSelectAllRegisters: "onSelectAllRegisters", onOpenSearchModal: "onOpenSearchModal", onSearch: "onSearch" }, viewQueries: [{ propertyName: "table", first: true, predicate: ["table"], descendants: true, static: true }, { propertyName: "ngtPagination", first: true, predicate: ["ngtPagination"], descendants: true, static: true }, { propertyName: "searchModal", first: true, predicate: ["searchModal"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"w-full\">\n <div class=\"flex flex-wrap w-full\">\n <ngt-tag *ngIf=\"hasAppliedFilters()\" class=\"w-full sm:w-auto {{ filterTagMargin }}\"\n [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\" color.bg=\"bg-red-500\" (click)=\"removeFilter()\" ngt-stylizable>\n Limpar Filtros\n </ngt-tag>\n\n <ng-container *ngIf=\"hasAppliedFilters()\">\n <ng-container *ngFor=\"let filter of filtersTranslated\">\n <ngt-tag class=\"w-full sm:w-auto {{ filterTagMargin }}\" [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\"\n [color.bg]=\"filterTagBgColor\" (click)=\"removeFilter(filter.reference)\" ngt-stylizable\n [title]=\"getTitle(filter)\">\n {{ filter.translation + ': ' + getTagFilterValue(filter) }}\n </ngt-tag>\n </ng-container>\n </ng-container>\n </div>\n\n <table style=\"display: table;\" class=\"text-left w-full border-collapse table-responsive\" #table>\n <ng-content></ng-content>\n </table>\n\n <p *ngIf=\"emptyStateVisible\" class=\"mt-8 mx-auto self-center text-center text-xl\">\n {{ ngtTranslateService.ngtDatatableNoDataFound }}\n </p>\n\n <div *ngIf=\"loadingSignal()\">\n <div *ngFor=\"let i of [1, 2, 3, 4]\" class=\"flex w-full mt-3\">\n <ng-container *ngIf=\"columnCount.length >= 2\">\n <ng-container *ngFor=\"let j of columnCount; let last = last\">\n <ng-container *ngIf=\"last\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n\n <ng-container *ngIf=\"!last\">\n <ngt-shining class=\"h-10 w-full mr-10\"></ngt-shining>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"columnCount.length < 2\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full mr-10 ml-10\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n </div>\n </div>\n</div>\n\n<div class=\"clearfix {{ paginationMargin }}\" [hidden]='!data || data.length == 0'>\n <ngt-pagination [pagesInterval]='4' (onPageChange)='apply($event, false)' (onPerPageChange)='apply(1, false)'\n #ngtPagination>\n </ngt-pagination>\n</div>\n\n<ngt-modal [customLayout]=\"true\" [isDisabled]=\"false\" [ngtStyle]=\"filterModalStyle\" #searchModal>\n <ng-container *ngTemplateOutlet=\"searchModalTemplate\"></ng-container>\n</ngt-modal>", styles: ["@media (max-width: 767px){.table-responsive{display:block;position:relative;width:100%}.table-responsive thead,.table-responsive tbody,.table-responsive th,.table-responsive td,.table-responsive tr{display:block}.table-responsive td,.table-responsive th{height:50px}.table-responsive thead{float:left;margin-bottom:15px}.table-responsive tbody{width:auto;position:relative;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}.table-responsive tbody tr{display:inline-block;min-width:100%}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgtShiningComponent, selector: "ngt-shining", inputs: ["shiningWidth"] }, { kind: "component", type: NgtPaginationComponent, selector: "ngt-pagination", inputs: ["pagesInterval"], outputs: ["onPageChange", "onPerPageChange"] }, { kind: "component", type: NgtModalComponent, selector: "ngt-modal", inputs: ["customLayout", "disableDefaultCloses", "ngtStyle", "isDisabled"], outputs: ["onCloseModal", "onOpenModal"] }, { kind: "component", type: NgtTagComponent, selector: "ngt-tag", inputs: ["icon"] }, { kind: "directive", type: NgtStylizableDirective, selector: "[ngt-stylizable]", inputs: ["color", "color.text", "color.bg", "color.border", "h", "w", "p", "px", "py", "pt", "pr", "pb", "pl", "m", "mx", "my", "mt", "mr", "mb", "ml", "gap", "border", "shadow", "rounded", "font", "text", "breakWords", "overflow", "position", "justifyContent", "cursor", "fontCase"] }] }); }
4617
4680
  }
4618
4681
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgtDatatableComponent, decorators: [{
4619
4682
  type: Component,
4620
- args: [{ selector: 'ngt-datatable', standalone: false, template: "<div class=\"w-full\">\n <div class=\"flex flex-wrap w-full\">\n <ngt-tag *ngIf=\"hasAppliedFilters()\" class=\"w-full sm:w-auto {{ filterTagMargin }}\"\n [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\" color.bg=\"bg-red-500\" (click)=\"removeFilter()\" ngt-stylizable>\n Limpar Filtros\n </ngt-tag>\n\n <ng-container *ngIf=\"hasAppliedFilters()\">\n <ng-container *ngFor=\"let filter of filtersTranslated\">\n <ngt-tag class=\"w-full sm:w-auto {{ filterTagMargin }}\" [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\"\n [color.bg]=\"filterTagBgColor\" (click)=\"removeFilter(filter.reference)\" ngt-stylizable\n [title]=\"getTitle(filter)\">\n {{ filter.translation + ': ' + getTagFilterValue(filter) }}\n </ngt-tag>\n </ng-container>\n </ng-container>\n </div>\n\n <table style=\"display: table;\" class=\"text-left w-full border-collapse table-responsive\" #table>\n <ng-content></ng-content>\n </table>\n\n <p *ngIf=\"emptyStateVisible\" class=\"mt-8 mx-auto self-center text-center text-xl\">\n {{ ngtTranslateService.ngtDatatableNoDataFound }}\n </p>\n\n <div *ngIf=\"loading\">\n <div *ngFor=\"let i of [1, 2, 3, 4]\" class=\"flex w-full mt-3\">\n <ng-container *ngIf=\"columnCount.length >= 2\">\n <ng-container *ngFor=\"let j of columnCount; let last = last\">\n <ng-container *ngIf=\"last\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n\n <ng-container *ngIf=\"!last\">\n <ngt-shining class=\"h-10 w-full mr-10\"></ngt-shining>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"columnCount.length < 2\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full mr-10 ml-10\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n </div>\n </div>\n</div>\n\n<div class=\"clearfix {{ paginationMargin }}\" [hidden]='!data || data.length == 0'>\n <ngt-pagination [pagesInterval]='4' (onPageChange)='apply($event, false)' (onPerPageChange)='apply(1, false)'\n #ngtPagination>\n </ngt-pagination>\n</div>\n\n<ngt-modal [customLayout]=\"true\" [isDisabled]=\"false\" [ngtStyle]=\"filterModalStyle\" #searchModal>\n <ng-container *ngTemplateOutlet=\"searchModalTemplate\"></ng-container>\n</ngt-modal>", styles: ["@media (max-width: 767px){.table-responsive{display:block;position:relative;width:100%}.table-responsive thead,.table-responsive tbody,.table-responsive th,.table-responsive td,.table-responsive tr{display:block}.table-responsive td,.table-responsive th{height:50px}.table-responsive thead{float:left;margin-bottom:15px}.table-responsive tbody{width:auto;position:relative;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}.table-responsive tbody tr{display:inline-block;min-width:100%}}\n"] }]
4683
+ args: [{ selector: 'ngt-datatable', standalone: false, template: "<div class=\"w-full\">\n <div class=\"flex flex-wrap w-full\">\n <ngt-tag *ngIf=\"hasAppliedFilters()\" class=\"w-full sm:w-auto {{ filterTagMargin }}\"\n [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\" color.bg=\"bg-red-500\" (click)=\"removeFilter()\" ngt-stylizable>\n Limpar Filtros\n </ngt-tag>\n\n <ng-container *ngIf=\"hasAppliedFilters()\">\n <ng-container *ngFor=\"let filter of filtersTranslated\">\n <ngt-tag class=\"w-full sm:w-auto {{ filterTagMargin }}\" [class.sm:mr-4]=\"filterTagMargin == 'mb-4'\"\n [color.bg]=\"filterTagBgColor\" (click)=\"removeFilter(filter.reference)\" ngt-stylizable\n [title]=\"getTitle(filter)\">\n {{ filter.translation + ': ' + getTagFilterValue(filter) }}\n </ngt-tag>\n </ng-container>\n </ng-container>\n </div>\n\n <table style=\"display: table;\" class=\"text-left w-full border-collapse table-responsive\" #table>\n <ng-content></ng-content>\n </table>\n\n <p *ngIf=\"emptyStateVisible\" class=\"mt-8 mx-auto self-center text-center text-xl\">\n {{ ngtTranslateService.ngtDatatableNoDataFound }}\n </p>\n\n <div *ngIf=\"loadingSignal()\">\n <div *ngFor=\"let i of [1, 2, 3, 4]\" class=\"flex w-full mt-3\">\n <ng-container *ngIf=\"columnCount.length >= 2\">\n <ng-container *ngFor=\"let j of columnCount; let last = last\">\n <ng-container *ngIf=\"last\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n\n <ng-container *ngIf=\"!last\">\n <ngt-shining class=\"h-10 w-full mr-10\"></ngt-shining>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"columnCount.length < 2\">\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full mr-10 ml-10\"></ngt-shining>\n <ngt-shining class=\"h-10 w-full\"></ngt-shining>\n </ng-container>\n </div>\n </div>\n</div>\n\n<div class=\"clearfix {{ paginationMargin }}\" [hidden]='!data || data.length == 0'>\n <ngt-pagination [pagesInterval]='4' (onPageChange)='apply($event, false)' (onPerPageChange)='apply(1, false)'\n #ngtPagination>\n </ngt-pagination>\n</div>\n\n<ngt-modal [customLayout]=\"true\" [isDisabled]=\"false\" [ngtStyle]=\"filterModalStyle\" #searchModal>\n <ng-container *ngTemplateOutlet=\"searchModalTemplate\"></ng-container>\n</ngt-modal>", styles: ["@media (max-width: 767px){.table-responsive{display:block;position:relative;width:100%}.table-responsive thead,.table-responsive tbody,.table-responsive th,.table-responsive td,.table-responsive tr{display:block}.table-responsive td,.table-responsive th{height:50px}.table-responsive thead{float:left;margin-bottom:15px}.table-responsive tbody{width:auto;position:relative;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}.table-responsive tbody tr{display:inline-block;min-width:100%}}\n"] }]
4621
4684
  }], ctorParameters: () => [{ type: i0.Injector }, { type: NgtHttpService }, { type: i0.ChangeDetectorRef }, { type: NgtTranslateService, decorators: [{
4622
4685
  type: Optional
4623
4686
  }] }], propDecorators: { table: [{
@@ -8558,15 +8621,17 @@ class NgtDropzoneComponent extends NgtControlValueAccessor {
8558
8621
  ngOnDestroy() {
8559
8622
  this.destroySubscriptions();
8560
8623
  }
8561
- imagePreview(index) {
8624
+ imagePreview(uploadedResourcesIndex) {
8562
8625
  const images = this.uploadedResources.filter((resource) => this.isImage(resource));
8563
- const imagesDiv = document.createElement("div");
8626
+ const imagesDiv = document.createElement('div');
8564
8627
  images.forEach((image) => {
8565
- let imageElement = document.createElement("img");
8628
+ let imageElement = document.createElement('img');
8566
8629
  imageElement.src = image.file.url;
8567
8630
  imagesDiv.appendChild(imageElement);
8568
8631
  });
8569
- this.onImageClick(imagesDiv, index);
8632
+ const clickedResource = this.uploadedResources[uploadedResourcesIndex];
8633
+ const imageIndexInGallery = images.indexOf(clickedResource);
8634
+ this.onImageClick(imagesDiv, imageIndexInGallery >= 0 ? imageIndexInGallery : 0);
8570
8635
  }
8571
8636
  onImageClick(element, index) {
8572
8637
  if (!this.viewMode) {
@@ -9102,6 +9167,99 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
9102
9167
  args: [{ providedIn: null }]
9103
9168
  }] });
9104
9169
 
9170
+ /**
9171
+ * Validates a Brazilian CNPJ (Cadastro Nacional da Pessoa Jurídica) number.
9172
+ * CNPJ is a unique identifier for companies in Brazil.
9173
+ *
9174
+ * @param value - The CNPJ value to validate (can include formatting characters)
9175
+ * @returns true if the CNPJ is valid, false otherwise
9176
+ *
9177
+ * @example
9178
+ * validateCNPJ('11.222.333/0001-81'); // returns true or false
9179
+ * validateCNPJ('11222333000181'); // returns true or false
9180
+ */
9181
+ function validateCNPJ(value) {
9182
+ if (!value) {
9183
+ return false;
9184
+ }
9185
+ // Validation weights for CNPJ verification digits
9186
+ const weights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
9187
+ // Remove non-digit characters
9188
+ const cleanedValue = value.replace(/[^\d]/g, '');
9189
+ // Check if CNPJ has exactly 14 digits
9190
+ if (cleanedValue.length !== 14) {
9191
+ return false;
9192
+ }
9193
+ // Check if all digits are the same (invalid CNPJ)
9194
+ if (/^(\d)\1{13}$/.test(cleanedValue)) {
9195
+ return false;
9196
+ }
9197
+ // Validate first verification digit
9198
+ let sum = 0;
9199
+ for (let i = 0; i < 12; i++) {
9200
+ sum += parseInt(cleanedValue[i]) * weights[i + 1];
9201
+ }
9202
+ const firstDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
9203
+ if (parseInt(cleanedValue[12]) !== firstDigit) {
9204
+ return false;
9205
+ }
9206
+ // Validate second verification digit
9207
+ sum = 0;
9208
+ for (let i = 0; i < 13; i++) {
9209
+ sum += parseInt(cleanedValue[i]) * weights[i];
9210
+ }
9211
+ const secondDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
9212
+ if (parseInt(cleanedValue[13]) !== secondDigit) {
9213
+ return false;
9214
+ }
9215
+ return true;
9216
+ }
9217
+ /**
9218
+ * Validates a Brazilian CPF (Cadastro de Pessoas Físicas) number.
9219
+ * CPF is a unique identifier for individuals in Brazil.
9220
+ *
9221
+ * @param value - The CPF value to validate (can include formatting characters)
9222
+ * @returns true if the CPF is valid, false otherwise
9223
+ *
9224
+ * @example
9225
+ * validateCPF('123.456.789-09'); // returns true or false
9226
+ * validateCPF('12345678909'); // returns true or false
9227
+ */
9228
+ function validateCPF(value) {
9229
+ if (!value) {
9230
+ return false;
9231
+ }
9232
+ // Remove non-digit characters
9233
+ const cleanedValue = value.replace(/[^\d]/g, '');
9234
+ // Check if CPF has exactly 11 digits
9235
+ if (cleanedValue.length !== 11) {
9236
+ return false;
9237
+ }
9238
+ // Check if all digits are the same (invalid CPF)
9239
+ if (/^(\d)\1{10}$/.test(cleanedValue)) {
9240
+ return false;
9241
+ }
9242
+ // Validate first verification digit
9243
+ let sum = 0;
9244
+ for (let i = 0; i < 9; i++) {
9245
+ sum += parseInt(cleanedValue[i]) * (10 - i);
9246
+ }
9247
+ const firstDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
9248
+ if (parseInt(cleanedValue[9]) !== firstDigit) {
9249
+ return false;
9250
+ }
9251
+ // Validate second verification digit
9252
+ sum = 0;
9253
+ for (let i = 0; i < 10; i++) {
9254
+ sum += parseInt(cleanedValue[i]) * (11 - i);
9255
+ }
9256
+ const secondDigit = sum % 11 < 2 ? 0 : 11 - (sum % 11);
9257
+ if (parseInt(cleanedValue[10]) !== secondDigit) {
9258
+ return false;
9259
+ }
9260
+ return true;
9261
+ }
9262
+
9105
9263
  class NgtReactiveFormValidationService {
9106
9264
  getSyncValidators(config) {
9107
9265
  const validators = [];