valtech-components 4.0.983 → 4.0.984

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 @@ import fixWebmDuration from 'fix-webm-duration';
70
70
  * Current version of valtech-components.
71
71
  * This is automatically updated during the publish process.
72
72
  */
73
- const VERSION = '4.0.983';
73
+ const VERSION = '4.0.984';
74
74
 
75
75
  function evaluateValtechAccess(rule, context, features = {}, visitedFeatures = new Set()) {
76
76
  if (rule == null)
@@ -39596,6 +39596,13 @@ class FieldSchemaEditorComponent {
39596
39596
  constructor() {
39597
39597
  this.props = { allowedTypes: ['TEXT'] };
39598
39598
  this.save = new EventEmitter();
39599
+ /**
39600
+ * Emite en cada tecla, sin validar. Existe porque el consumer necesita el
39601
+ * borrador en vivo: si solo tuviera `save`, lo escrito acá no existiría para
39602
+ * él hasta que alguien toque su botón — y lo escrito ES la intención del
39603
+ * usuario, no un borrador que haya que confirmar.
39604
+ */
39605
+ this.changed = new EventEmitter();
39599
39606
  this.i18n = inject(I18nService);
39600
39607
  this.formSchemas = inject(FormSchemaBuilderService);
39601
39608
  this.labelControl = new FormControl('', { nonNullable: true });
@@ -39619,6 +39626,11 @@ class FieldSchemaEditorComponent {
39619
39626
  type: InputType.SELECT,
39620
39627
  state: this.state(),
39621
39628
  placeholder: this.t('typeLabel'),
39629
+ // action-sheet y no el popover default de Ionic: el popover se ancla al
39630
+ // campo, y con el campo cerca del borde inferior y un catálogo largo
39631
+ // Ionic lo recorta arriba Y abajo — quedaban tipos imposibles de elegir.
39632
+ // La hoja usa el alto completo y scrollea sola.
39633
+ selectInterface: 'action-sheet',
39622
39634
  options: this.allowedTypes().map((type, order) => ({ id: type, name: this.typeLabel(type), order })),
39623
39635
  };
39624
39636
  });
@@ -39640,11 +39652,18 @@ class FieldSchemaEditorComponent {
39640
39652
  if (!this.i18n.hasNamespace(NAMESPACE$2)) {
39641
39653
  this.i18n.registerDefaults(NAMESPACE$2, FIELD_SCHEMA_EDITOR_I18N);
39642
39654
  }
39643
- this.typeControl.valueChanges.subscribe(value => this.currentType.set(value || 'TEXT'));
39655
+ this.typeControl.valueChanges.subscribe(value => {
39656
+ this.currentType.set(value || 'TEXT');
39657
+ this.emitChange();
39658
+ });
39644
39659
  this.labelControl.valueChanges.subscribe(value => {
39645
39660
  if (!this.nameLocked)
39646
39661
  this.name = this.formSchemas.toToken(value || '');
39662
+ this.emitChange();
39647
39663
  });
39664
+ this.placeholderControl.valueChanges.subscribe(() => this.emitChange());
39665
+ this.hintControl.valueChanges.subscribe(() => this.emitChange());
39666
+ this.requiredControl.valueChanges.subscribe(() => this.emitChange());
39648
39667
  }
39649
39668
  ngOnInit() {
39650
39669
  const initial = this.props.field;
@@ -39682,6 +39701,16 @@ class FieldSchemaEditorComponent {
39682
39701
  typeLabel(type) {
39683
39702
  return this.props.typeLabels?.[type] || this.t(`type${type}`);
39684
39703
  }
39704
+ setOptions(options) {
39705
+ this.options.set(options);
39706
+ this.emitChange();
39707
+ }
39708
+ emitChange() {
39709
+ // Antes de ngOnInit no hay id: emitir ahí daría un campo sin identidad, que
39710
+ // el consumer no sabría a qué fila aplicar.
39711
+ if (this.fieldId)
39712
+ this.changed.emit(this.value());
39713
+ }
39685
39714
  selectPreset(preset) {
39686
39715
  this.selectedPresetId.set(preset.id);
39687
39716
  const value = preset.field;
@@ -39695,6 +39724,7 @@ class FieldSchemaEditorComponent {
39695
39724
  this.requiredControl.setValue(!!value.required);
39696
39725
  this.typeControl.setValue(this.coerceType(value.type));
39697
39726
  this.options.set(value.options ?? []);
39727
+ this.emitChange();
39698
39728
  }
39699
39729
  /**
39700
39730
  * Valida y emite. Público a propósito: lo llama el consumer desde el botón
@@ -39742,7 +39772,7 @@ class FieldSchemaEditorComponent {
39742
39772
  return allowed.includes(type) ? type : allowed[0];
39743
39773
  }
39744
39774
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldSchemaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39745
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldSchemaEditorComponent, isStandalone: true, selector: "val-field-schema-editor", inputs: { props: "props" }, outputs: { save: "save" }, ngImport: i0, template: `
39775
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldSchemaEditorComponent, isStandalone: true, selector: "val-field-schema-editor", inputs: { props: "props" }, outputs: { save: "save", changed: "changed" }, ngImport: i0, template: `
39746
39776
  <div class="field-schema-editor">
39747
39777
  @if (showPresets()) {
39748
39778
  <section class="field-schema-editor__presets">
@@ -39795,7 +39825,7 @@ class FieldSchemaEditorComponent {
39795
39825
  />
39796
39826
 
39797
39827
  @if (needsOptions()) {
39798
- <val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="options.set($event)" />
39828
+ <val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="setOptions($event)" />
39799
39829
  }
39800
39830
 
39801
39831
  @if (validationError()) {
@@ -39868,7 +39898,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39868
39898
  />
39869
39899
 
39870
39900
  @if (needsOptions()) {
39871
- <val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="options.set($event)" />
39901
+ <val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="setOptions($event)" />
39872
39902
  }
39873
39903
 
39874
39904
  @if (validationError()) {
@@ -39880,6 +39910,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39880
39910
  type: Input
39881
39911
  }], save: [{
39882
39912
  type: Output
39913
+ }], changed: [{
39914
+ type: Output
39883
39915
  }] } });
39884
39916
 
39885
39917
  class RequestFormBuilderService extends FormSchemaBuilderService {
@@ -40110,6 +40142,20 @@ class SurveyBuilderComponent {
40110
40142
  return next;
40111
40143
  });
40112
40144
  }
40145
+ /**
40146
+ * Guarda lo que se está escribiendo, sin cerrar el editor ni validar.
40147
+ *
40148
+ * Sin esto, lo tipeado solo existía dentro del editor hasta que alguien
40149
+ * tocaba "Listo": la fila seguía diciendo "Pregunta sin texto" y, peor,
40150
+ * "Guardar encuesta" fallaba con "todas las preguntas necesitan texto" sobre
40151
+ * una pregunta que en pantalla claramente tenía texto. Tocar "Listo" era un
40152
+ * paso obligatorio que no se veía por ningún lado.
40153
+ */
40154
+ draftQuestion(field) {
40155
+ this.questions.update(rows => rows.map(r => (r.id === field.id ? { ...r, ...field } : r)));
40156
+ if (this.validationError())
40157
+ this.validationError.set('');
40158
+ }
40113
40159
  applyQuestion(field) {
40114
40160
  this.questions.update(rows => rows.map(r => r.id === field.id
40115
40161
  ? {
@@ -40249,7 +40295,12 @@ class SurveyBuilderComponent {
40249
40295
 
40250
40296
  @if (editingId() === row.id) {
40251
40297
  <div class="survey-builder__row-editor">
40252
- <val-field-schema-editor #editor [props]="editorProps(row)" (save)="applyQuestion($event)" />
40298
+ <val-field-schema-editor
40299
+ #editor
40300
+ [props]="editorProps(row)"
40301
+ (changed)="draftQuestion($event)"
40302
+ (save)="applyQuestion($event)"
40303
+ />
40253
40304
  <val-button
40254
40305
  [props]="{
40255
40306
  token: 'q-done-' + row.id,
@@ -40303,7 +40354,7 @@ class SurveyBuilderComponent {
40303
40354
  (onClick)="save()"
40304
40355
  />
40305
40356
  </div>
40306
- `, isInline: true, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-builder__questions{display:flex;flex-direction:column;gap:12px}.survey-builder__questions-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.survey-builder__empty{margin:0;font-size:.875rem;color:var(--ion-color-medium, #92949c)}.survey-builder__row{display:flex;flex-direction:column;gap:12px;padding:12px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));border-radius:var(--val-radius-md, 12px);background:var(--ion-card-background, var(--ion-background-color, #fff))}.survey-builder__row-head{display:flex;flex-direction:column;gap:8px}.survey-builder__row-text{display:flex;flex-direction:column;gap:2px;min-width:0}.survey-builder__row-text strong{color:var(--ion-text-color, #000);font-size:.9375rem}.survey-builder__row-text span{color:var(--ion-color-medium, #92949c);font-size:.8125rem}.survey-builder__row-actions{display:flex;gap:4px;flex-wrap:wrap}.survey-builder__row-editor{display:flex;flex-direction:column;gap:12px;padding-top:12px;border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .1))}.survey-builder__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}@media (min-width: 576px){.survey-builder__row-head{flex-direction:row;align-items:flex-start;justify-content:space-between}.survey-builder__row-text{flex:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: FieldSchemaEditorComponent, selector: "val-field-schema-editor", inputs: ["props"], outputs: ["save"] }] }); }
40357
+ `, isInline: true, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-builder__questions{display:flex;flex-direction:column;gap:12px}.survey-builder__questions-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.survey-builder__empty{margin:0;font-size:.875rem;color:var(--ion-color-medium, #92949c)}.survey-builder__row{display:flex;flex-direction:column;gap:12px;padding:12px;border:1px solid var(--ion-border-color, rgba(0, 0, 0, .1));border-radius:var(--val-radius-md, 12px);background:var(--ion-card-background, var(--ion-background-color, #fff))}.survey-builder__row-head{display:flex;flex-direction:column;gap:8px}.survey-builder__row-text{display:flex;flex-direction:column;gap:2px;min-width:0}.survey-builder__row-text strong{color:var(--ion-text-color, #000);font-size:.9375rem}.survey-builder__row-text span{color:var(--ion-color-medium, #92949c);font-size:.8125rem}.survey-builder__row-actions{display:flex;gap:4px;flex-wrap:wrap}.survey-builder__row-editor{display:flex;flex-direction:column;gap:12px;padding-top:12px;border-top:1px solid var(--ion-border-color, rgba(0, 0, 0, .1))}.survey-builder__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}@media (min-width: 576px){.survey-builder__row-head{flex-direction:row;align-items:flex-start;justify-content:space-between}.survey-builder__row-text{flex:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: FieldSchemaEditorComponent, selector: "val-field-schema-editor", inputs: ["props"], outputs: ["save", "changed"] }] }); }
40307
40358
  }
40308
40359
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyBuilderComponent, decorators: [{
40309
40360
  type: Component,
@@ -40363,7 +40414,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
40363
40414
 
40364
40415
  @if (editingId() === row.id) {
40365
40416
  <div class="survey-builder__row-editor">
40366
- <val-field-schema-editor #editor [props]="editorProps(row)" (save)="applyQuestion($event)" />
40417
+ <val-field-schema-editor
40418
+ #editor
40419
+ [props]="editorProps(row)"
40420
+ (changed)="draftQuestion($event)"
40421
+ (save)="applyQuestion($event)"
40422
+ />
40367
40423
  <val-button
40368
40424
  [props]="{
40369
40425
  token: 'q-done-' + row.id,