ui-core-abv 0.9.1 → 0.9.2

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.
@@ -556,6 +556,13 @@ const DICTIONARY_EN = {
556
556
  duplicate_identifier: 'The identifier "{{identifier}}" is used more than once.',
557
557
  duplicate_identifier_title: 'Validation error',
558
558
  },
559
+ import: {
560
+ invalid_schema: 'The file does not contain a valid form configuration.',
561
+ invalid_schema_title: 'Invalid file',
562
+ confirm_overwrite: 'This will replace the form you are currently editing. Do you want to continue?',
563
+ confirm_overwrite_title: 'Load configuration',
564
+ confirm_overwrite_ok: 'Load and replace',
565
+ },
559
566
  repeater: {
560
567
  no_subfields: 'No sub-fields yet. Add one below.',
561
568
  add_subfield: 'Add sub-field',
@@ -910,6 +917,13 @@ const DICTIONARY_ES = {
910
917
  duplicate_identifier: 'El identificador "{{identifier}}" se está usando más de una vez.',
911
918
  duplicate_identifier_title: 'Error de validación',
912
919
  },
920
+ import: {
921
+ invalid_schema: 'El archivo no contiene una configuración de formulario válida.',
922
+ invalid_schema_title: 'Archivo inválido',
923
+ confirm_overwrite: 'Esto reemplazará el formulario que estás editando. ¿Deseas continuar?',
924
+ confirm_overwrite_title: 'Cargar configuración',
925
+ confirm_overwrite_ok: 'Cargar y reemplazar',
926
+ },
913
927
  repeater: {
914
928
  no_subfields: 'Sin sub-campos. Añade uno abajo.',
915
929
  add_subfield: 'Agregar sub-campo',
@@ -11091,7 +11105,7 @@ class UicUserFormbuilderComponent {
11091
11105
  'computedSource.dependsOn': fieldOptions,
11092
11106
  'externalValidation.key': this.validationSources
11093
11107
  };
11094
- });
11108
+ }, { equal: (a, b) => this.areSelectOptionsRecordsEqual(a, b) });
11095
11109
  subFieldDependencyOptions = computed(() => {
11096
11110
  const subCtx = this.editingSubField();
11097
11111
  if (!subCtx)
@@ -11125,7 +11139,7 @@ class UicUserFormbuilderComponent {
11125
11139
  'computedSource.dependsOn': fieldOptions,
11126
11140
  'externalValidation.key': this.validationSources
11127
11141
  };
11128
- });
11142
+ }, { equal: (a, b) => this.areSelectOptionsRecordsEqual(a, b) });
11129
11143
  constructor() {
11130
11144
  effect(() => {
11131
11145
  const readOnly = this.readOnly();
@@ -11303,8 +11317,88 @@ class UicUserFormbuilderComponent {
11303
11317
  });
11304
11318
  }
11305
11319
  copySchemaToClipboard() {
11306
- const schema = this.previewSchema();
11307
- navigator.clipboard.writeText(JSON.stringify(schema, null, 2));
11320
+ const exportPayload = {
11321
+ schemaVersion: 1,
11322
+ form: this.buildExportableForm()
11323
+ };
11324
+ navigator.clipboard.writeText(JSON.stringify(exportPayload, null, 2));
11325
+ }
11326
+ async importSchemaFromFile(event) {
11327
+ const input = event.target;
11328
+ const file = input.files?.[0];
11329
+ input.value = '';
11330
+ if (!file)
11331
+ return;
11332
+ const parsedForm = this.parseImportedSchema(await file.text());
11333
+ if (!parsedForm) {
11334
+ this.tinyAlertService.warning('form_builder.import.invalid_schema', {
11335
+ title: 'form_builder.import.invalid_schema_title'
11336
+ });
11337
+ return;
11338
+ }
11339
+ const hasExistingContent = this.editableBlocks().some(block => block.fields.length > 0);
11340
+ if (hasExistingContent) {
11341
+ const response = await this.tinyAlertService.warning('form_builder.import.confirm_overwrite', {
11342
+ title: 'form_builder.import.confirm_overwrite_title',
11343
+ showCancelButton: true,
11344
+ okButtonText: 'form_builder.import.confirm_overwrite_ok'
11345
+ });
11346
+ if (!response.value)
11347
+ return;
11348
+ }
11349
+ this.applyImportedForm(parsedForm);
11350
+ }
11351
+ buildExportableForm() {
11352
+ return {
11353
+ cols: this.editableCols(),
11354
+ titleFontSize: this.editableTitleFontSize() ?? undefined,
11355
+ subtitleFontSize: this.editableSubtitleFontSize() ?? undefined,
11356
+ titleMargin: this.editableTitleMargin() ?? undefined,
11357
+ subtitleMargin: this.editableSubtitleMargin() ?? undefined,
11358
+ blocks: this.editableBlocks().map(block => ({
11359
+ ...block,
11360
+ fields: block.fields.map(({ field, ...restField }) => ({
11361
+ ...restField,
11362
+ repeaterSubFields: restField.repeaterSubFields?.map(({ field: _sf, ...sfRest }) => sfRest)
11363
+ }))
11364
+ }))
11365
+ };
11366
+ }
11367
+ applyImportedForm(form) {
11368
+ this.editableCols.set(form.cols ?? 2);
11369
+ this.editableTitleFontSize.set(form.titleFontSize ?? null);
11370
+ this.editableSubtitleFontSize.set(form.subtitleFontSize ?? null);
11371
+ this.editableTitleMargin.set(form.titleMargin ?? null);
11372
+ this.editableSubtitleMargin.set(form.subtitleMargin ?? null);
11373
+ this.editableBlocks.set(this.prepareBlocksForLocalState(form.blocks ?? []));
11374
+ this.selectedField.set(null);
11375
+ this.editingSubField.set(null);
11376
+ this.focusNewFieldCode.set(null);
11377
+ this.focusNewSubFieldCode.set(null);
11378
+ }
11379
+ parseImportedSchema(raw) {
11380
+ let parsed;
11381
+ try {
11382
+ parsed = JSON.parse(raw);
11383
+ }
11384
+ catch {
11385
+ return null;
11386
+ }
11387
+ const candidate = (parsed && typeof parsed === 'object' && 'form' in parsed)
11388
+ ? parsed.form
11389
+ : parsed;
11390
+ return this.isValidEditableForm(candidate) ? candidate : null;
11391
+ }
11392
+ isValidEditableForm(value) {
11393
+ if (!value || typeof value !== 'object')
11394
+ return false;
11395
+ const form = value;
11396
+ if (typeof form.cols !== 'number' || !Array.isArray(form.blocks))
11397
+ return false;
11398
+ return form.blocks.every(block => block && typeof block === 'object' && typeof block.code === 'string' && Array.isArray(block.fields) &&
11399
+ block.fields.every(field => field && typeof field === 'object' && typeof field.code === 'string' &&
11400
+ !!field.fieldData && typeof field.fieldData === 'object' &&
11401
+ typeof field.fieldData.name === 'string' && typeof field.fieldData.type === 'string'));
11308
11402
  }
11309
11403
  submitForm() {
11310
11404
  if (this.enableNameModify()) {
@@ -11575,6 +11669,28 @@ class UicUserFormbuilderComponent {
11575
11669
  externalValidation: cleanExternalValidation
11576
11670
  };
11577
11671
  }
11672
+ areSelectOptionsRecordsEqual(a, b) {
11673
+ const aKeys = Object.keys(a);
11674
+ const bKeys = Object.keys(b);
11675
+ if (aKeys.length !== bKeys.length)
11676
+ return false;
11677
+ return aKeys.every(key => this.areSelectOptionArraysEqual(a[key], b[key]));
11678
+ }
11679
+ areSelectOptionArraysEqual(a, b) {
11680
+ if (a === b)
11681
+ return true;
11682
+ if (!a || !b || a.length !== b.length)
11683
+ return false;
11684
+ return a.every((option, index) => {
11685
+ const other = b[index];
11686
+ const current = option;
11687
+ return !!other &&
11688
+ current.id === other.id &&
11689
+ current.text === other.text &&
11690
+ current.group === other.group &&
11691
+ current.fieldType === other.fieldType;
11692
+ });
11693
+ }
11578
11694
  deepClone(value) {
11579
11695
  if (Array.isArray(value)) {
11580
11696
  return value.map(item => this.deepClone(item));
@@ -11585,7 +11701,7 @@ class UicUserFormbuilderComponent {
11585
11701
  return value;
11586
11702
  }
11587
11703
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicUserFormbuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11588
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicUserFormbuilderComponent, isStandalone: true, selector: "ui-user-formbuilder", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: false, isRequired: false, transformFunction: null }, optionSources: { classPropertyName: "optionSources", publicName: "optionSources", isSignal: false, isRequired: false, transformFunction: null }, computedSources: { classPropertyName: "computedSources", publicName: "computedSources", isSignal: false, isRequired: false, transformFunction: null }, validationSources: { classPropertyName: "validationSources", publicName: "validationSources", isSignal: false, isRequired: false, transformFunction: null }, selectOptionsResolver: { classPropertyName: "selectOptionsResolver", publicName: "selectOptionsResolver", isSignal: false, isRequired: false, transformFunction: null }, computedFieldResolver: { classPropertyName: "computedFieldResolver", publicName: "computedFieldResolver", isSignal: false, isRequired: false, transformFunction: null }, externalValidatorResolver: { classPropertyName: "externalValidatorResolver", publicName: "externalValidatorResolver", isSignal: false, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, enableNameModify: { classPropertyName: "enableNameModify", publicName: "enableNameModify", isSignal: true, isRequired: false, transformFunction: null }, editableFormInput: { classPropertyName: "editableFormInput", publicName: "editableForm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitFormRequest: "submitFormRequest" }, host: { listeners: { "document:mousemove": "onPropertiesResize($event)", "document:mouseup": "stopPropertiesResize()" } }, ngImport: i0, template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div class=\"formeditor-header-row1\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n <button class=\"header-expand-btn\" (click)=\"headerRowExpanded.set(!headerRowExpanded())\" [title]=\"headerRowExpanded() ? 'Ocultar opciones de estilo' : 'Opciones de estilo'\">\r\n <i [class]=\"headerRowExpanded() ? 'ri-arrow-up-s-line' : 'ri-settings-3-line'\"></i>\r\n </button>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (headerRowExpanded()) {\r\n <div class=\"formeditor-header-row2\">\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableTitleFontSize()\" (ngModelChange)=\"editableTitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableSubtitleFontSize()\" (ngModelChange)=\"editableSubtitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableTitleMargin()\" (ngModelChange)=\"editableTitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableSubtitleMargin()\" (ngModelChange)=\"editableSubtitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \r\n [block]=\"block\"\r\n [selectedFieldId]=\"selectedField()?.code ?? null\"\r\n [selectedSubFieldCode]=\"editingSubField()?.subField?.code ?? null\"\r\n [selectedSubFieldParentCode]=\"editingSubField()?.parentCode ?? null\"\r\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\r\n (blockChange)=\"onBlockChange(i, $event)\"\r\n (addFieldRequest)=\"addField(block.code, $event)\"\r\n (notifySelectedField)=\"selectField($event)\"\r\n (notifySelectedSubField)=\"onSelectSubField($event)\"\r\n (notifyNewSubField)=\"onNewSubField($event)\"\r\n (deleteBlock)=\"deleteBlock($event)\">\r\n </lib-block-editor>\r\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\r\n <div\r\n class=\"formeditor-properties-resize\"\r\n (mousedown)=\"startPropertiesResize($event)\">\r\n </div>\r\n <h3>Propiedades</h3>\r\n <div class=\"formeditor-properties-form\">\r\n @if (editingSubField()) {\r\n <div class=\"subfield-back-header\">\r\n <i class=\"ri-stack-line\"></i>\r\n <span>{{editingSubField()!.subField.fieldData.label || editingSubField()!.subField.fieldData.name}}</span>\r\n </div>\r\n <lib-field-editor\r\n [config]=\"editingSubField()!.subField\"\r\n [isSubField]=\"true\"\r\n [focusRequiredField]=\"focusNewSubFieldCode() === editingSubField()?.subField?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"subFieldDependencyOptions()\"\r\n (fieldChange)=\"onSubFieldChange($event)\">\r\n </lib-field-editor>\r\n } @else if (selectedField()) {\r\n <lib-field-editor \r\n [config]=\"selectedField()!\"\r\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"dependencyOptions()\"\r\n (fieldChange)=\"onFieldChange($event)\">\r\n </lib-field-editor>\r\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <div class=\"preview-label\">{{'form_builder.preview_form_label' | uicTranslate}}</div>\r\n <ui-form-wrapper \r\n [schema]=\"previewSchema()\"\r\n [selectOptionsResolver]=\"selectOptionsResolver\"\r\n [computedFieldResolver]=\"computedFieldResolver\"\r\n [externalValidatorResolver]=\"externalValidatorResolver\"\r\n [showButtons]=\"false\">\r\n </ui-form-wrapper>\r\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;border-bottom:solid 1px var(--grey-300);display:flex;flex-direction:column}.formeditor-header-row1{padding:5px 10px;align-items:center;display:flex;gap:10px}.formeditor-header-row2{display:flex;align-items:center;gap:4px;padding:4px 10px 6px;flex-wrap:wrap;border-top:solid 1px var(--grey-200);background-color:var(--grey-50)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.preview-label{background-color:var(--yellow-100);color:var(--yellow-600);padding:4px;border-radius:3px;font-size:12px}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}.subfield-back-header{display:flex;align-items:center;gap:6px;padding:0 0 10px;border-bottom:solid 1px var(--grey-200);margin-bottom:10px;color:var(--grey-500);font-size:12px}.subfield-back-header i{font-size:14px;color:var(--primary-500)}.subfield-back-header span{font-weight:600;color:var(--grey-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header-expand-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.header-expand-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.header-expand-btn i{font-size:14px}.copy-schema-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.copy-schema-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.copy-schema-btn i{font-size:14px}.schema-opt{display:inline-flex;align-items:center;gap:4px;padding:0 8px;border-left:solid 1px var(--grey-300);font-size:11px;color:var(--grey-500)}.schema-opt:first-child{border-left:none}.schema-opt span{white-space:nowrap}.schema-opt-value{font-weight:600;color:var(--grey-700);min-width:20px}.schema-opt input[type=number]{width:52px;height:22px;border:solid 1px var(--grey-300);border-radius:4px;padding:0 4px;font-size:11px;text-align:center;background:#fff;color:var(--grey-800)}.schema-opt input[type=number]:focus{outline:none;border-color:var(--primary-400)}\n"], dependencies: [{ kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "selectOptionsResolver", "computedFieldResolver", "externalValidatorResolver", "loading", "disabled", "showButtons", "fillSelects", "initialValues", "focusFieldName", "focusFieldTrigger", "fileUidResolverFn"], outputs: ["formSubmit", "formChange", "optionsSourceError"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "component", type: FieldEditorComponent, selector: "lib-field-editor", inputs: ["config", "focusRequiredField", "isSubField", "enableNameModify", "options"], outputs: ["fieldChange", "nameManuallySet"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BlockEditorComponent, selector: "lib-block-editor", inputs: ["block", "selectedFieldId", "selectedSubFieldCode", "selectedSubFieldParentCode", "visibilityParentFieldCodes"], outputs: ["blockChange", "addFieldRequest", "deleteBlock", "notifySelectedField", "notifySelectedSubField", "notifyNewSubField"] }, { kind: "component", type: UicSelectComponent, selector: "ui-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "noneText", "emptyText", "searcherEnabled", "loading", "nullable", "options"] }] });
11704
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicUserFormbuilderComponent, isStandalone: true, selector: "ui-user-formbuilder", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: false, isRequired: false, transformFunction: null }, optionSources: { classPropertyName: "optionSources", publicName: "optionSources", isSignal: false, isRequired: false, transformFunction: null }, computedSources: { classPropertyName: "computedSources", publicName: "computedSources", isSignal: false, isRequired: false, transformFunction: null }, validationSources: { classPropertyName: "validationSources", publicName: "validationSources", isSignal: false, isRequired: false, transformFunction: null }, selectOptionsResolver: { classPropertyName: "selectOptionsResolver", publicName: "selectOptionsResolver", isSignal: false, isRequired: false, transformFunction: null }, computedFieldResolver: { classPropertyName: "computedFieldResolver", publicName: "computedFieldResolver", isSignal: false, isRequired: false, transformFunction: null }, externalValidatorResolver: { classPropertyName: "externalValidatorResolver", publicName: "externalValidatorResolver", isSignal: false, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, enableNameModify: { classPropertyName: "enableNameModify", publicName: "enableNameModify", isSignal: true, isRequired: false, transformFunction: null }, editableFormInput: { classPropertyName: "editableFormInput", publicName: "editableForm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitFormRequest: "submitFormRequest" }, host: { listeners: { "document:mousemove": "onPropertiesResize($event)", "document:mouseup": "stopPropertiesResize()" } }, ngImport: i0, template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div class=\"formeditor-header-row1\">\r\n <input #importFileInput id=\"formbuilder-import-file\" aria-label=\"Cargar configuraci\u00F3n del formulario\" type=\"file\" accept=\".json,application/json\" style=\"display:none\" (change)=\"importSchemaFromFile($event)\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n <button class=\"header-expand-btn\" (click)=\"headerRowExpanded.set(!headerRowExpanded())\" [title]=\"headerRowExpanded() ? 'Ocultar opciones de estilo' : 'Opciones de estilo'\">\r\n <i [class]=\"headerRowExpanded() ? 'ri-arrow-up-s-line' : 'ri-settings-3-line'\"></i>\r\n </button>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <button class=\"copy-schema-btn\" title=\"Cargar JSON de formulario\" (click)=\"importFileInput.click()\"><i class=\"ri-upload-2-line\"></i></button>\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (headerRowExpanded()) {\r\n <div class=\"formeditor-header-row2\">\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableTitleFontSize()\" (ngModelChange)=\"editableTitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableSubtitleFontSize()\" (ngModelChange)=\"editableSubtitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableTitleMargin()\" (ngModelChange)=\"editableTitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableSubtitleMargin()\" (ngModelChange)=\"editableSubtitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \r\n [block]=\"block\"\r\n [selectedFieldId]=\"selectedField()?.code ?? null\"\r\n [selectedSubFieldCode]=\"editingSubField()?.subField?.code ?? null\"\r\n [selectedSubFieldParentCode]=\"editingSubField()?.parentCode ?? null\"\r\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\r\n (blockChange)=\"onBlockChange(i, $event)\"\r\n (addFieldRequest)=\"addField(block.code, $event)\"\r\n (notifySelectedField)=\"selectField($event)\"\r\n (notifySelectedSubField)=\"onSelectSubField($event)\"\r\n (notifyNewSubField)=\"onNewSubField($event)\"\r\n (deleteBlock)=\"deleteBlock($event)\">\r\n </lib-block-editor>\r\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\r\n <div\r\n class=\"formeditor-properties-resize\"\r\n (mousedown)=\"startPropertiesResize($event)\">\r\n </div>\r\n <h3>Propiedades</h3>\r\n <div class=\"formeditor-properties-form\">\r\n @if (editingSubField()) {\r\n <div class=\"subfield-back-header\">\r\n <i class=\"ri-stack-line\"></i>\r\n <span>{{editingSubField()!.subField.fieldData.label || editingSubField()!.subField.fieldData.name}}</span>\r\n </div>\r\n <lib-field-editor\r\n [config]=\"editingSubField()!.subField\"\r\n [isSubField]=\"true\"\r\n [focusRequiredField]=\"focusNewSubFieldCode() === editingSubField()?.subField?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"subFieldDependencyOptions()\"\r\n (fieldChange)=\"onSubFieldChange($event)\">\r\n </lib-field-editor>\r\n } @else if (selectedField()) {\r\n <lib-field-editor \r\n [config]=\"selectedField()!\"\r\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"dependencyOptions()\"\r\n (fieldChange)=\"onFieldChange($event)\">\r\n </lib-field-editor>\r\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <div class=\"preview-label\">{{'form_builder.preview_form_label' | uicTranslate}}</div>\r\n <ui-form-wrapper \r\n [schema]=\"previewSchema()\"\r\n [selectOptionsResolver]=\"selectOptionsResolver\"\r\n [computedFieldResolver]=\"computedFieldResolver\"\r\n [externalValidatorResolver]=\"externalValidatorResolver\"\r\n [showButtons]=\"false\">\r\n </ui-form-wrapper>\r\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;border-bottom:solid 1px var(--grey-300);display:flex;flex-direction:column}.formeditor-header-row1{padding:5px 10px;align-items:center;display:flex;gap:10px}.formeditor-header-row2{display:flex;align-items:center;gap:4px;padding:4px 10px 6px;flex-wrap:wrap;border-top:solid 1px var(--grey-200);background-color:var(--grey-50)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.preview-label{background-color:var(--yellow-100);color:var(--yellow-600);padding:4px;border-radius:3px;font-size:12px}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}.subfield-back-header{display:flex;align-items:center;gap:6px;padding:0 0 10px;border-bottom:solid 1px var(--grey-200);margin-bottom:10px;color:var(--grey-500);font-size:12px}.subfield-back-header i{font-size:14px;color:var(--primary-500)}.subfield-back-header span{font-weight:600;color:var(--grey-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header-expand-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.header-expand-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.header-expand-btn i{font-size:14px}.copy-schema-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.copy-schema-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.copy-schema-btn i{font-size:14px}.schema-opt{display:inline-flex;align-items:center;gap:4px;padding:0 8px;border-left:solid 1px var(--grey-300);font-size:11px;color:var(--grey-500)}.schema-opt:first-child{border-left:none}.schema-opt span{white-space:nowrap}.schema-opt-value{font-weight:600;color:var(--grey-700);min-width:20px}.schema-opt input[type=number]{width:52px;height:22px;border:solid 1px var(--grey-300);border-radius:4px;padding:0 4px;font-size:11px;text-align:center;background:#fff;color:var(--grey-800)}.schema-opt input[type=number]:focus{outline:none;border-color:var(--primary-400)}\n"], dependencies: [{ kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "selectOptionsResolver", "computedFieldResolver", "externalValidatorResolver", "loading", "disabled", "showButtons", "fillSelects", "initialValues", "focusFieldName", "focusFieldTrigger", "fileUidResolverFn"], outputs: ["formSubmit", "formChange", "optionsSourceError"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "component", type: FieldEditorComponent, selector: "lib-field-editor", inputs: ["config", "focusRequiredField", "isSubField", "enableNameModify", "options"], outputs: ["fieldChange", "nameManuallySet"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BlockEditorComponent, selector: "lib-block-editor", inputs: ["block", "selectedFieldId", "selectedSubFieldCode", "selectedSubFieldParentCode", "visibilityParentFieldCodes"], outputs: ["blockChange", "addFieldRequest", "deleteBlock", "notifySelectedField", "notifySelectedSubField", "notifyNewSubField"] }, { kind: "component", type: UicSelectComponent, selector: "ui-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "noneText", "emptyText", "searcherEnabled", "loading", "nullable", "options"] }] });
11589
11705
  }
11590
11706
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicUserFormbuilderComponent, decorators: [{
11591
11707
  type: Component,
@@ -11597,7 +11713,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
11597
11713
  FormsModule,
11598
11714
  BlockEditorComponent,
11599
11715
  UicSelectComponent
11600
- ], template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div class=\"formeditor-header-row1\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n <button class=\"header-expand-btn\" (click)=\"headerRowExpanded.set(!headerRowExpanded())\" [title]=\"headerRowExpanded() ? 'Ocultar opciones de estilo' : 'Opciones de estilo'\">\r\n <i [class]=\"headerRowExpanded() ? 'ri-arrow-up-s-line' : 'ri-settings-3-line'\"></i>\r\n </button>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (headerRowExpanded()) {\r\n <div class=\"formeditor-header-row2\">\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableTitleFontSize()\" (ngModelChange)=\"editableTitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableSubtitleFontSize()\" (ngModelChange)=\"editableSubtitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableTitleMargin()\" (ngModelChange)=\"editableTitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableSubtitleMargin()\" (ngModelChange)=\"editableSubtitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \r\n [block]=\"block\"\r\n [selectedFieldId]=\"selectedField()?.code ?? null\"\r\n [selectedSubFieldCode]=\"editingSubField()?.subField?.code ?? null\"\r\n [selectedSubFieldParentCode]=\"editingSubField()?.parentCode ?? null\"\r\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\r\n (blockChange)=\"onBlockChange(i, $event)\"\r\n (addFieldRequest)=\"addField(block.code, $event)\"\r\n (notifySelectedField)=\"selectField($event)\"\r\n (notifySelectedSubField)=\"onSelectSubField($event)\"\r\n (notifyNewSubField)=\"onNewSubField($event)\"\r\n (deleteBlock)=\"deleteBlock($event)\">\r\n </lib-block-editor>\r\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\r\n <div\r\n class=\"formeditor-properties-resize\"\r\n (mousedown)=\"startPropertiesResize($event)\">\r\n </div>\r\n <h3>Propiedades</h3>\r\n <div class=\"formeditor-properties-form\">\r\n @if (editingSubField()) {\r\n <div class=\"subfield-back-header\">\r\n <i class=\"ri-stack-line\"></i>\r\n <span>{{editingSubField()!.subField.fieldData.label || editingSubField()!.subField.fieldData.name}}</span>\r\n </div>\r\n <lib-field-editor\r\n [config]=\"editingSubField()!.subField\"\r\n [isSubField]=\"true\"\r\n [focusRequiredField]=\"focusNewSubFieldCode() === editingSubField()?.subField?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"subFieldDependencyOptions()\"\r\n (fieldChange)=\"onSubFieldChange($event)\">\r\n </lib-field-editor>\r\n } @else if (selectedField()) {\r\n <lib-field-editor \r\n [config]=\"selectedField()!\"\r\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"dependencyOptions()\"\r\n (fieldChange)=\"onFieldChange($event)\">\r\n </lib-field-editor>\r\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <div class=\"preview-label\">{{'form_builder.preview_form_label' | uicTranslate}}</div>\r\n <ui-form-wrapper \r\n [schema]=\"previewSchema()\"\r\n [selectOptionsResolver]=\"selectOptionsResolver\"\r\n [computedFieldResolver]=\"computedFieldResolver\"\r\n [externalValidatorResolver]=\"externalValidatorResolver\"\r\n [showButtons]=\"false\">\r\n </ui-form-wrapper>\r\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;border-bottom:solid 1px var(--grey-300);display:flex;flex-direction:column}.formeditor-header-row1{padding:5px 10px;align-items:center;display:flex;gap:10px}.formeditor-header-row2{display:flex;align-items:center;gap:4px;padding:4px 10px 6px;flex-wrap:wrap;border-top:solid 1px var(--grey-200);background-color:var(--grey-50)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.preview-label{background-color:var(--yellow-100);color:var(--yellow-600);padding:4px;border-radius:3px;font-size:12px}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}.subfield-back-header{display:flex;align-items:center;gap:6px;padding:0 0 10px;border-bottom:solid 1px var(--grey-200);margin-bottom:10px;color:var(--grey-500);font-size:12px}.subfield-back-header i{font-size:14px;color:var(--primary-500)}.subfield-back-header span{font-weight:600;color:var(--grey-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header-expand-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.header-expand-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.header-expand-btn i{font-size:14px}.copy-schema-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.copy-schema-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.copy-schema-btn i{font-size:14px}.schema-opt{display:inline-flex;align-items:center;gap:4px;padding:0 8px;border-left:solid 1px var(--grey-300);font-size:11px;color:var(--grey-500)}.schema-opt:first-child{border-left:none}.schema-opt span{white-space:nowrap}.schema-opt-value{font-weight:600;color:var(--grey-700);min-width:20px}.schema-opt input[type=number]{width:52px;height:22px;border:solid 1px var(--grey-300);border-radius:4px;padding:0 4px;font-size:11px;text-align:center;background:#fff;color:var(--grey-800)}.schema-opt input[type=number]:focus{outline:none;border-color:var(--primary-400)}\n"] }]
11716
+ ], template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div class=\"formeditor-header-row1\">\r\n <input #importFileInput id=\"formbuilder-import-file\" aria-label=\"Cargar configuraci\u00F3n del formulario\" type=\"file\" accept=\".json,application/json\" style=\"display:none\" (change)=\"importSchemaFromFile($event)\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n <button class=\"header-expand-btn\" (click)=\"headerRowExpanded.set(!headerRowExpanded())\" [title]=\"headerRowExpanded() ? 'Ocultar opciones de estilo' : 'Opciones de estilo'\">\r\n <i [class]=\"headerRowExpanded() ? 'ri-arrow-up-s-line' : 'ri-settings-3-line'\"></i>\r\n </button>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <button class=\"copy-schema-btn\" title=\"Cargar JSON de formulario\" (click)=\"importFileInput.click()\"><i class=\"ri-upload-2-line\"></i></button>\r\n <button class=\"copy-schema-btn\" title=\"Copiar JSON del formulario\" (click)=\"copySchemaToClipboard()\"><i class=\"ri-file-copy-line\"></i></button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (headerRowExpanded()) {\r\n <div class=\"formeditor-header-row2\">\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableTitleFontSize()\" (ngModelChange)=\"editableTitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_font_size' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleFontSize() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"8\" max=\"72\" [ngModel]=\"editableSubtitleFontSize()\" (ngModelChange)=\"editableSubtitleFontSize.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.title_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableTitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableTitleMargin()\" (ngModelChange)=\"editableTitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n <div class=\"schema-opt\">\r\n <span>{{'form_builder.schema.subtitle_margin' | uicTranslate}}</span>\r\n @if (isReadOnly()) {\r\n <span class=\"schema-opt-value\">{{editableSubtitleMargin() ?? '\u2014'}}</span>\r\n } @else {\r\n <input type=\"number\" min=\"0\" [ngModel]=\"editableSubtitleMargin()\" (ngModelChange)=\"editableSubtitleMargin.set($event || null)\" placeholder=\"\u2014\">\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \r\n [block]=\"block\"\r\n [selectedFieldId]=\"selectedField()?.code ?? null\"\r\n [selectedSubFieldCode]=\"editingSubField()?.subField?.code ?? null\"\r\n [selectedSubFieldParentCode]=\"editingSubField()?.parentCode ?? null\"\r\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\r\n (blockChange)=\"onBlockChange(i, $event)\"\r\n (addFieldRequest)=\"addField(block.code, $event)\"\r\n (notifySelectedField)=\"selectField($event)\"\r\n (notifySelectedSubField)=\"onSelectSubField($event)\"\r\n (notifyNewSubField)=\"onNewSubField($event)\"\r\n (deleteBlock)=\"deleteBlock($event)\">\r\n </lib-block-editor>\r\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\r\n <div\r\n class=\"formeditor-properties-resize\"\r\n (mousedown)=\"startPropertiesResize($event)\">\r\n </div>\r\n <h3>Propiedades</h3>\r\n <div class=\"formeditor-properties-form\">\r\n @if (editingSubField()) {\r\n <div class=\"subfield-back-header\">\r\n <i class=\"ri-stack-line\"></i>\r\n <span>{{editingSubField()!.subField.fieldData.label || editingSubField()!.subField.fieldData.name}}</span>\r\n </div>\r\n <lib-field-editor\r\n [config]=\"editingSubField()!.subField\"\r\n [isSubField]=\"true\"\r\n [focusRequiredField]=\"focusNewSubFieldCode() === editingSubField()?.subField?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"subFieldDependencyOptions()\"\r\n (fieldChange)=\"onSubFieldChange($event)\">\r\n </lib-field-editor>\r\n } @else if (selectedField()) {\r\n <lib-field-editor \r\n [config]=\"selectedField()!\"\r\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\r\n [enableNameModify]=\"enableNameModify()\"\r\n [options]=\"dependencyOptions()\"\r\n (fieldChange)=\"onFieldChange($event)\">\r\n </lib-field-editor>\r\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <div class=\"preview-label\">{{'form_builder.preview_form_label' | uicTranslate}}</div>\r\n <ui-form-wrapper \r\n [schema]=\"previewSchema()\"\r\n [selectOptionsResolver]=\"selectOptionsResolver\"\r\n [computedFieldResolver]=\"computedFieldResolver\"\r\n [externalValidatorResolver]=\"externalValidatorResolver\"\r\n [showButtons]=\"false\">\r\n </ui-form-wrapper>\r\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;border-bottom:solid 1px var(--grey-300);display:flex;flex-direction:column}.formeditor-header-row1{padding:5px 10px;align-items:center;display:flex;gap:10px}.formeditor-header-row2{display:flex;align-items:center;gap:4px;padding:4px 10px 6px;flex-wrap:wrap;border-top:solid 1px var(--grey-200);background-color:var(--grey-50)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.preview-label{background-color:var(--yellow-100);color:var(--yellow-600);padding:4px;border-radius:3px;font-size:12px}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}.subfield-back-header{display:flex;align-items:center;gap:6px;padding:0 0 10px;border-bottom:solid 1px var(--grey-200);margin-bottom:10px;color:var(--grey-500);font-size:12px}.subfield-back-header i{font-size:14px;color:var(--primary-500)}.subfield-back-header span{font-weight:600;color:var(--grey-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header-expand-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.header-expand-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.header-expand-btn i{font-size:14px}.copy-schema-btn{background:none;border:solid 1px var(--grey-300);border-radius:4px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--grey-500);flex-shrink:0}.copy-schema-btn:hover{background-color:var(--grey-100);color:var(--grey-700)}.copy-schema-btn i{font-size:14px}.schema-opt{display:inline-flex;align-items:center;gap:4px;padding:0 8px;border-left:solid 1px var(--grey-300);font-size:11px;color:var(--grey-500)}.schema-opt:first-child{border-left:none}.schema-opt span{white-space:nowrap}.schema-opt-value{font-weight:600;color:var(--grey-700);min-width:20px}.schema-opt input[type=number]{width:52px;height:22px;border:solid 1px var(--grey-300);border-radius:4px;padding:0 4px;font-size:11px;text-align:center;background:#fff;color:var(--grey-800)}.schema-opt input[type=number]:focus{outline:none;border-color:var(--primary-400)}\n"] }]
11601
11717
  }], ctorParameters: () => [], propDecorators: { disabled: [{
11602
11718
  type: Input
11603
11719
  }], formTitle: [{