@solcre-org/core-ui 2.12.38 → 2.12.40

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.
@@ -2154,6 +2154,8 @@ class SelectFieldComponent extends BaseFieldComponent {
2154
2154
  selectionChange = output();
2155
2155
  isInitialized = signal(false);
2156
2156
  hasValue = signal(false);
2157
+ userHasInteracted = signal(false);
2158
+ lastDynamicValue = undefined;
2157
2159
  computedValue = computed(() => {
2158
2160
  const value = this.value();
2159
2161
  if (this.field().multiple && !Array.isArray(value)) {
@@ -2207,17 +2209,13 @@ class SelectFieldComponent extends BaseFieldComponent {
2207
2209
  const formValue = this.formValue();
2208
2210
  if ('dynamicValue' in fieldCfg && typeof fieldCfg.dynamicValue === 'function' && formValue) {
2209
2211
  const newValue = fieldCfg.dynamicValue(formValue);
2210
- const currentValue = this.formControl().value;
2211
- if (newValue !== null && newValue !== undefined && newValue !== currentValue) {
2212
- setTimeout(() => {
2213
- this.formControl().setValue(newValue, { emitEvent: true });
2214
- this.valueChange.emit(newValue);
2215
- }, 0);
2216
- }
2212
+ this.scheduleDynamicValue(newValue);
2217
2213
  }
2218
2214
  });
2219
2215
  }
2220
2216
  ngOnInit() {
2217
+ this.userHasInteracted.set(false);
2218
+ this.lastDynamicValue = undefined;
2221
2219
  super.ngOnInit();
2222
2220
  const currentInitialValue = this.formControl().value;
2223
2221
  if (!this.field().multiple && typeof currentInitialValue === 'string' && currentInitialValue.trim() === '') {
@@ -2241,12 +2239,7 @@ class SelectFieldComponent extends BaseFieldComponent {
2241
2239
  const formValue = this.formValue();
2242
2240
  if ('dynamicValue' in fieldCfg && typeof fieldCfg.dynamicValue === 'function' && formValue) {
2243
2241
  const newValue = fieldCfg.dynamicValue(formValue);
2244
- const currentValue = this.formControl().value;
2245
- if (newValue !== null && newValue !== undefined && newValue !== currentValue) {
2246
- this.formControl().setValue(newValue, { emitEvent: true });
2247
- this.valueChange.emit(newValue);
2248
- this.hasValue.set(true);
2249
- }
2242
+ this.scheduleDynamicValue(newValue);
2250
2243
  }
2251
2244
  const finalValue = this.formControl().value;
2252
2245
  if (finalValue !== null && finalValue !== undefined && finalValue !== '') {
@@ -2298,6 +2291,12 @@ class SelectFieldComponent extends BaseFieldComponent {
2298
2291
  finalValue !== '' &&
2299
2292
  (!Array.isArray(finalValue) || finalValue.length > 0);
2300
2293
  this.hasValue.set(hasValidValue);
2294
+ if (this.formControl().dirty && !this.userHasInteracted()) {
2295
+ this.userHasInteracted.set(true);
2296
+ }
2297
+ if (!this.areValuesEqual(finalValue, this.lastDynamicValue)) {
2298
+ this.lastDynamicValue = undefined;
2299
+ }
2301
2300
  const fieldConfig = this.field();
2302
2301
  if (fieldConfig.onSelectionChange && this.formValue()) {
2303
2302
  try {
@@ -2344,6 +2343,72 @@ class SelectFieldComponent extends BaseFieldComponent {
2344
2343
  onBlurInput() {
2345
2344
  this.onBlur();
2346
2345
  }
2346
+ scheduleDynamicValue(newValue, delay = 0) {
2347
+ const control = this.formControl();
2348
+ if (!control)
2349
+ return;
2350
+ const currentValue = control.value;
2351
+ if (!this.shouldApplyDynamicValue(newValue, currentValue)) {
2352
+ if (!this.userHasInteracted() && this.areValuesEqual(newValue, currentValue)) {
2353
+ this.lastDynamicValue = this.cloneValue(newValue);
2354
+ }
2355
+ return;
2356
+ }
2357
+ setTimeout(() => {
2358
+ const ctrl = this.formControl();
2359
+ if (!ctrl)
2360
+ return;
2361
+ const latestValue = ctrl.value;
2362
+ if (!this.shouldApplyDynamicValue(newValue, latestValue)) {
2363
+ if (!this.userHasInteracted() && this.areValuesEqual(newValue, latestValue)) {
2364
+ this.lastDynamicValue = this.cloneValue(newValue);
2365
+ }
2366
+ return;
2367
+ }
2368
+ ctrl.setValue(newValue, { emitEvent: true });
2369
+ ctrl.markAsPristine();
2370
+ this.lastDynamicValue = this.cloneValue(newValue);
2371
+ this.hasValue.set(this.hasMeaningfulValue(newValue));
2372
+ }, delay);
2373
+ }
2374
+ shouldApplyDynamicValue(newValue, currentValue) {
2375
+ if (newValue === undefined || newValue === null)
2376
+ return false;
2377
+ if (this.userHasInteracted())
2378
+ return false;
2379
+ const hasCurrentValue = this.hasMeaningfulValue(currentValue);
2380
+ const currentMatchesLastDynamic = this.areValuesEqual(currentValue, this.lastDynamicValue);
2381
+ if (hasCurrentValue && !currentMatchesLastDynamic) {
2382
+ return false;
2383
+ }
2384
+ return !this.areValuesEqual(newValue, currentValue);
2385
+ }
2386
+ hasMeaningfulValue(value) {
2387
+ if (value === null || value === undefined) {
2388
+ return false;
2389
+ }
2390
+ if (Array.isArray(value)) {
2391
+ return value.length > 0;
2392
+ }
2393
+ if (typeof value === 'string') {
2394
+ return value.trim() !== '';
2395
+ }
2396
+ return true;
2397
+ }
2398
+ areValuesEqual(a, b) {
2399
+ if (Array.isArray(a) && Array.isArray(b)) {
2400
+ if (a.length !== b.length)
2401
+ return false;
2402
+ return a.every((item, index) => item === b[index]);
2403
+ }
2404
+ return a === b;
2405
+ }
2406
+ cloneValue(value) {
2407
+ if (Array.isArray(value)) {
2408
+ return [...value];
2409
+ }
2410
+ return value;
2411
+ }
2347
2412
  onSelectChange(value) {
2348
2413
  const hasValidValue = value !== null &&
2349
2414
  value !== undefined &&
@@ -3639,6 +3704,9 @@ class MultiEntryFieldComponent {
3639
3704
  ModalMode = ModalMode;
3640
3705
  entries = signal([]);
3641
3706
  fieldValues = signal([]);
3707
+ isSyncingFromInput = signal(false);
3708
+ lastInputSignature = null;
3709
+ lastEmittedSignature = null;
3642
3710
  config = computed(() => this.field().multiEntryConfig || {});
3643
3711
  allowMultiple = computed(() => this.config().allowMultipleEntries || false);
3644
3712
  maxEntries = computed(() => this.config().maxEntries || 10);
@@ -3685,38 +3753,54 @@ class MultiEntryFieldComponent {
3685
3753
  this.initializeEntries(this.value());
3686
3754
  }
3687
3755
  initializeEntries(inputValue) {
3688
- if (!inputValue) {
3689
- const initialEntries = Array(this.minEntries()).fill(null).map((_, index) => ({
3690
- id: this.generateEntryId(),
3691
- value: null
3692
- }));
3693
- this.entries.set(initialEntries);
3694
- this.fieldValues.set(Array(this.minEntries()).fill(null));
3756
+ const signature = this.serializeValue(inputValue);
3757
+ const currentEntriesCount = this.entries().length;
3758
+ const requiresMinEntriesUpdate = currentEntriesCount < this.minEntries();
3759
+ if (this.lastInputSignature === signature && currentEntriesCount > 0 && !requiresMinEntriesUpdate) {
3695
3760
  return;
3696
3761
  }
3697
- let parsedValues = [];
3698
- if (Array.isArray(inputValue)) {
3699
- parsedValues = inputValue;
3700
- }
3701
- else if (typeof inputValue === 'string') {
3702
- const separator = this.config().customSeparator || ',';
3703
- parsedValues = inputValue.split(separator).map(v => v.trim()).filter(v => v !== '');
3704
- }
3705
- else {
3706
- parsedValues = [inputValue];
3762
+ this.isSyncingFromInput.set(true);
3763
+ try {
3764
+ let newEntries = [];
3765
+ if (!inputValue) {
3766
+ newEntries = Array.from({ length: this.minEntries() }, () => ({
3767
+ id: this.generateEntryId(),
3768
+ value: null
3769
+ }));
3770
+ }
3771
+ else {
3772
+ let parsedValues = [];
3773
+ if (Array.isArray(inputValue)) {
3774
+ parsedValues = inputValue;
3775
+ }
3776
+ else if (typeof inputValue === 'string') {
3777
+ const separator = this.config().customSeparator || ',';
3778
+ parsedValues = inputValue
3779
+ .split(separator)
3780
+ .map(v => v.trim())
3781
+ .filter(v => v !== '');
3782
+ }
3783
+ else {
3784
+ parsedValues = [inputValue];
3785
+ }
3786
+ newEntries = parsedValues.map(value => ({
3787
+ id: this.generateEntryId(),
3788
+ value
3789
+ }));
3790
+ while (newEntries.length < this.minEntries()) {
3791
+ newEntries.push({
3792
+ id: this.generateEntryId(),
3793
+ value: null
3794
+ });
3795
+ }
3796
+ }
3797
+ this.entries.set(newEntries);
3798
+ this.fieldValues.set(newEntries.map(entry => entry.value));
3799
+ this.lastInputSignature = signature;
3707
3800
  }
3708
- const newEntries = parsedValues.map((value, index) => ({
3709
- id: this.generateEntryId(),
3710
- value: value
3711
- }));
3712
- while (newEntries.length < this.minEntries()) {
3713
- newEntries.push({
3714
- id: this.generateEntryId(),
3715
- value: null
3716
- });
3801
+ finally {
3802
+ this.isSyncingFromInput.set(false);
3717
3803
  }
3718
- this.entries.set(newEntries);
3719
- this.fieldValues.set(newEntries.map(entry => entry.value));
3720
3804
  }
3721
3805
  generateEntryId() {
3722
3806
  return `entry_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
@@ -3797,6 +3881,15 @@ class MultiEntryFieldComponent {
3797
3881
  default:
3798
3882
  formattedValue = nonEmptyValues;
3799
3883
  }
3884
+ const signature = this.serializeValue(formattedValue);
3885
+ if (this.isSyncingFromInput()) {
3886
+ this.lastEmittedSignature = signature;
3887
+ return;
3888
+ }
3889
+ if (this.lastEmittedSignature === signature) {
3890
+ return;
3891
+ }
3892
+ this.lastEmittedSignature = signature;
3800
3893
  this.valueChange.emit(formattedValue);
3801
3894
  }
3802
3895
  createFieldConfigForEntry(index) {
@@ -3825,6 +3918,14 @@ class MultiEntryFieldComponent {
3825
3918
  shouldShowRemoveButton(index) {
3826
3919
  return this.shouldShowActions(index) && this.canRemove();
3827
3920
  }
3921
+ serializeValue(value) {
3922
+ try {
3923
+ return JSON.stringify(value ?? null);
3924
+ }
3925
+ catch {
3926
+ return String(value);
3927
+ }
3928
+ }
3828
3929
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MultiEntryFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3829
3930
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: MultiEntryFieldComponent, isStandalone: true, selector: "core-multi-entry-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: true, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, rowData: { classPropertyName: "rowData", publicName: "rowData", isSignal: true, isRequired: false, transformFunction: null }, formValue: { classPropertyName: "formValue", publicName: "formValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", onBlurEvent: "onBlurEvent", onEnterEvent: "onEnterEvent" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-entry-group\">\n @for (entry of entries(); track entry.id; let index = $index) {\n <div class=\"c-entry-item\">\n <!-- Campo din\u00E1mico para cada entrada -->\n <div\n coreDynamicField\n [field]=\"createFieldConfigForEntry(index)\"\n [value]=\"entry.value\"\n [mode]=\"mode()\"\n [errors]=\"errors()\"\n [rowData]=\"rowData()\"\n [formValue]=\"formValue()\"\n (valueChange)=\"onFieldValueChange($event, index)\"\n (onBlurEvent)=\"onFieldBlur($event)\"\n (onEnterEvent)=\"onFieldEnter($event)\">\n </div>\n\n <!-- Botones de acci\u00F3n (agregar/eliminar) -->\n @if (shouldShowActions(index)) {\n <div class=\"c-entry-actions\">\n @if (shouldShowAddButton(index)) {\n <button \n type=\"button\"\n class=\"c-entry-action c-entry-action--add\"\n (click)=\"addEntry()\"\n [disabled]=\"isDisabled()\"\n [title]=\"addLabel() | translate\"\n [attr.aria-label]=\"addLabel() | translate\">\n <span class=\"icon-counter-up\"></span>\n {{ addLabel() | translate }}\n </button>\n }\n \n @if (shouldShowRemoveButton(index)) {\n <button \n type=\"button\"\n class=\"c-entry-action c-entry-action--remove\"\n (click)=\"removeEntry(index)\"\n [disabled]=\"isDisabled()\"\n [title]=\"removeLabel() | translate\"\n [attr.aria-label]=\"removeLabel() | translate\">\n <span class=\"icon-counter-down\"></span>\n {{ removeLabel() | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n <!-- Errores del campo principal -->\n @if (errors().length > 0) {\n <core-field-errors [errors]=\"errors()\"></core-field-errors>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "directive", type: DynamicFieldDirective, selector: "[coreDynamicField]", inputs: ["field", "value", "mode", "errors", "rowData", "formValue"], outputs: ["valueChange", "onBlurEvent", "onEnterEvent", "selectionChange"] }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }] });
3830
3931
  }
@@ -5502,8 +5603,10 @@ class GenericModalComponent {
5502
5603
  this.allFields().forEach(field => {
5503
5604
  const fieldKey = field.key;
5504
5605
  const payloadKey = (field.keyToPayload ?? field.key);
5505
- if ('dynamicValue' in field && typeof field.dynamicValue === 'function') {
5506
- const dynamicVal = field.dynamicValue(newInstance);
5606
+ const modeConfig = field.modes?.[this.mode()];
5607
+ const dynamicValueFn = (modeConfig?.dynamicValue ?? field.dynamicValue);
5608
+ if (typeof dynamicValueFn === 'function') {
5609
+ const dynamicVal = dynamicValueFn(newInstance);
5507
5610
  if (dynamicVal !== undefined && dynamicVal !== null) {
5508
5611
  newInstance[payloadKey] = dynamicVal;
5509
5612
  const control = this.form().get(fieldKey);
@@ -13290,11 +13393,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
13290
13393
  // Este archivo es generado automáticamente por scripts/update-version.js
13291
13394
  // No edites manualmente este archivo
13292
13395
  const VERSION = {
13293
- full: '2.12.38',
13396
+ full: '2.12.40',
13294
13397
  major: 2,
13295
13398
  minor: 12,
13296
- patch: 38,
13297
- timestamp: '2025-09-17T14:27:53.302Z',
13399
+ patch: 40,
13400
+ timestamp: '2025-09-17T15:45:09.933Z',
13298
13401
  buildDate: '17/9/2025'
13299
13402
  };
13300
13403