valtech-components 4.0.982 → 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.
- package/esm2022/lib/components/atoms/button/button.component.mjs +3 -1
- package/esm2022/lib/components/organisms/field-schema-editor/field-schema-editor.component.mjs +364 -0
- package/esm2022/lib/components/organisms/field-schema-editor/field-schema-editor.i18n.mjs +71 -0
- package/esm2022/lib/components/organisms/field-schema-editor/types.mjs +2 -0
- package/esm2022/lib/components/organisms/survey-builder/survey-builder.component.mjs +289 -136
- package/esm2022/lib/components/organisms/survey-builder/survey-builder.i18n.mjs +19 -7
- package/esm2022/lib/components/organisms/survey-builder/types.mjs +31 -2
- package/esm2022/lib/components/organisms/survey-response/survey-response.component.mjs +294 -26
- package/esm2022/lib/components/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/valtech-components.mjs +1108 -231
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/article/article.component.d.ts +1 -0
- package/lib/components/organisms/field-schema-editor/field-schema-editor.component.d.ts +99 -0
- package/lib/components/organisms/field-schema-editor/field-schema-editor.i18n.d.ts +2 -0
- package/lib/components/organisms/field-schema-editor/types.d.ts +60 -0
- package/lib/components/organisms/survey-builder/survey-builder.component.d.ts +36 -14
- package/lib/components/organisms/survey-builder/types.d.ts +23 -5
- package/lib/components/organisms/survey-response/survey-response.component.d.ts +42 -1
- package/lib/components/types.d.ts +6 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -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.
|
|
73
|
+
const VERSION = '4.0.984';
|
|
74
74
|
|
|
75
75
|
function evaluateValtechAccess(rule, context, features = {}, visitedFeatures = new Set()) {
|
|
76
76
|
if (rule == null)
|
|
@@ -12998,6 +12998,7 @@ class ButtonComponent {
|
|
|
12998
12998
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ButtonComponent, isStandalone: true, selector: "val-button", inputs: { preset: "preset", props: "props" }, outputs: { onClick: "onClick" }, usesOnChanges: true, ngImport: i0, template: `
|
|
12999
12999
|
<ion-button
|
|
13000
13000
|
[attr.data-testid]="resolvedProps.token"
|
|
13001
|
+
[attr.aria-label]="resolvedProps.ariaLabel || null"
|
|
13001
13002
|
[type]="resolvedProps.type"
|
|
13002
13003
|
[color]="resolvedProps.color"
|
|
13003
13004
|
[expand]="resolvedProps.expand"
|
|
@@ -13027,6 +13028,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
13027
13028
|
args: [{ selector: 'val-button', standalone: true, imports: [CommonModule, RouterLink, IonButton, IonIcon, IonSpinner, IonText], template: `
|
|
13028
13029
|
<ion-button
|
|
13029
13030
|
[attr.data-testid]="resolvedProps.token"
|
|
13031
|
+
[attr.aria-label]="resolvedProps.ariaLabel || null"
|
|
13030
13032
|
[type]="resolvedProps.type"
|
|
13031
13033
|
[color]="resolvedProps.color"
|
|
13032
13034
|
[expand]="resolvedProps.expand"
|
|
@@ -38614,6 +38616,66 @@ const REQUEST_STATUSES = [
|
|
|
38614
38616
|
*/
|
|
38615
38617
|
const FIELD_TYPE_EMOJI_RATING = 'EMOJI_RATING';
|
|
38616
38618
|
|
|
38619
|
+
/**
|
|
38620
|
+
* Primitivo de campo de formulario: label (estilo val-form) + contenido proyectado.
|
|
38621
|
+
*
|
|
38622
|
+
* Usar cuando necesitás un campo fuera de val-form pero con el mismo estilo:
|
|
38623
|
+
* image-picker, date-picker, selectores custom, chips, etc.
|
|
38624
|
+
*
|
|
38625
|
+
* NOTA: para ion-input / ion-textarea NO usar ng-content projection — el Shadow DOM
|
|
38626
|
+
* de Ionic no responde al grid del host. Usá en cambio un `<div class="pf-field">`
|
|
38627
|
+
* plano en el template con `<p class="pf-label">` + ion-input directo.
|
|
38628
|
+
*
|
|
38629
|
+
* ```html
|
|
38630
|
+
* <val-form-field label="Imagen">
|
|
38631
|
+
* <app-image-picker ... />
|
|
38632
|
+
* </val-form-field>
|
|
38633
|
+
*
|
|
38634
|
+
* <!-- Para ion-input: NO val-form-field, usar div plano -->
|
|
38635
|
+
* <div class="pf-field">
|
|
38636
|
+
* <p class="pf-label">Nombre</p>
|
|
38637
|
+
* <ion-input fill="outline" ... />
|
|
38638
|
+
* </div>
|
|
38639
|
+
* ```
|
|
38640
|
+
*
|
|
38641
|
+
* El label usa el mismo val-title que val-form (size=small, color=dark, bold=false).
|
|
38642
|
+
* El spacing entre campos se controla con --val-form-field-gap (default 0.5rem).
|
|
38643
|
+
* El padding horizontal se hereda vía --val-form-field-padding (default 0).
|
|
38644
|
+
* Setearlo en el contenedor padre para consistencia sin override en cada campo:
|
|
38645
|
+
* `.my-card { --val-form-field-padding: 0 16px; }`
|
|
38646
|
+
*/
|
|
38647
|
+
class FormFieldComponent {
|
|
38648
|
+
constructor() {
|
|
38649
|
+
this.label = input('');
|
|
38650
|
+
this.titleProps = computed(() => ({
|
|
38651
|
+
content: this.label(),
|
|
38652
|
+
size: 'small',
|
|
38653
|
+
color: 'dark',
|
|
38654
|
+
bold: false,
|
|
38655
|
+
}));
|
|
38656
|
+
}
|
|
38657
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38658
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FormFieldComponent, isStandalone: true, selector: "val-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
38659
|
+
@if (label()) {
|
|
38660
|
+
<div class="vff-label">
|
|
38661
|
+
<val-title [props]="titleProps()" />
|
|
38662
|
+
</div>
|
|
38663
|
+
}
|
|
38664
|
+
<ng-content />
|
|
38665
|
+
`, isInline: true, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"], dependencies: [{ kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
38666
|
+
}
|
|
38667
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
38668
|
+
type: Component,
|
|
38669
|
+
args: [{ selector: 'val-form-field', standalone: true, imports: [TitleComponent], template: `
|
|
38670
|
+
@if (label()) {
|
|
38671
|
+
<div class="vff-label">
|
|
38672
|
+
<val-title [props]="titleProps()" />
|
|
38673
|
+
</div>
|
|
38674
|
+
}
|
|
38675
|
+
<ng-content />
|
|
38676
|
+
`, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"] }]
|
|
38677
|
+
}] });
|
|
38678
|
+
|
|
38617
38679
|
const SURVEY_RESPONSE_I18N = {
|
|
38618
38680
|
es: {
|
|
38619
38681
|
nameLabel: 'Tu nombre',
|
|
@@ -38653,7 +38715,9 @@ const SURVEY_RESPONSE_I18N = {
|
|
|
38653
38715
|
},
|
|
38654
38716
|
};
|
|
38655
38717
|
|
|
38656
|
-
const NAMESPACE$
|
|
38718
|
+
const NAMESPACE$3 = 'SurveyResponse';
|
|
38719
|
+
/** Tipos cuya respuesta es un booleano, no un texto. */
|
|
38720
|
+
const BOOLEAN_TYPES = ['CHECK', 'TOGGLE'];
|
|
38657
38721
|
/**
|
|
38658
38722
|
* val-survey-response
|
|
38659
38723
|
*
|
|
@@ -38683,14 +38747,22 @@ class SurveyResponseComponent {
|
|
|
38683
38747
|
this.requests = inject(RequestService);
|
|
38684
38748
|
this.errors = inject(ValtechErrorService);
|
|
38685
38749
|
this.emojiType = FIELD_TYPE_EMOJI_RATING;
|
|
38750
|
+
this.selectType = InputType.SELECT;
|
|
38686
38751
|
this.loading = signal(true);
|
|
38687
38752
|
this.loadError = signal(false);
|
|
38688
38753
|
this.sent = signal(false);
|
|
38689
38754
|
this.sending = signal(false);
|
|
38690
38755
|
this.typeConfig = signal(null);
|
|
38756
|
+
this.multiSelectError = signal(false);
|
|
38691
38757
|
this.nameControl = new FormControl('', { nonNullable: true });
|
|
38692
38758
|
this.emailControl = new FormControl('', { nonNullable: true });
|
|
38693
38759
|
this.form = new FormGroup({});
|
|
38760
|
+
/**
|
|
38761
|
+
* Una casilla por opción de cada pregunta MULTI_SELECT, indexada
|
|
38762
|
+
* `"<pregunta>::<opcion>"`. Viven fuera del `form` porque el valor que viaja
|
|
38763
|
+
* al backend es UNA lista por pregunta, no N booleanos: se arma al enviar.
|
|
38764
|
+
*/
|
|
38765
|
+
this.multiControls = new Map();
|
|
38694
38766
|
/** Preguntas ordenadas — el template las recorre en este orden. */
|
|
38695
38767
|
this.questions = computed(() => {
|
|
38696
38768
|
const cfg = this.typeConfig();
|
|
@@ -38715,8 +38787,8 @@ class SurveyResponseComponent {
|
|
|
38715
38787
|
this.i18n.lang();
|
|
38716
38788
|
return { variant: 'error', title: this.t('loginRequiredTitle'), description: this.t('loginRequiredBody') };
|
|
38717
38789
|
});
|
|
38718
|
-
if (!this.i18n.hasNamespace(NAMESPACE$
|
|
38719
|
-
this.i18n.registerDefaults(NAMESPACE$
|
|
38790
|
+
if (!this.i18n.hasNamespace(NAMESPACE$3)) {
|
|
38791
|
+
this.i18n.registerDefaults(NAMESPACE$3, SURVEY_RESPONSE_I18N);
|
|
38720
38792
|
}
|
|
38721
38793
|
}
|
|
38722
38794
|
async ngOnInit() {
|
|
@@ -38735,6 +38807,19 @@ class SurveyResponseComponent {
|
|
|
38735
38807
|
buildForm(cfg) {
|
|
38736
38808
|
const group = {};
|
|
38737
38809
|
for (const q of [...cfg.fieldSchema].sort((a, b) => a.order - b.order)) {
|
|
38810
|
+
if (q.type === 'MULTI_SELECT') {
|
|
38811
|
+
for (const opt of q.options ?? []) {
|
|
38812
|
+
this.multiControls.set(`${q.name}::${opt.id}`, new FormControl(false, { nonNullable: true }));
|
|
38813
|
+
}
|
|
38814
|
+
continue;
|
|
38815
|
+
}
|
|
38816
|
+
if (BOOLEAN_TYPES.includes(q.type)) {
|
|
38817
|
+
// Sin `required`: un booleano SIEMPRE tiene valor. Exigirlo obligaría a
|
|
38818
|
+
// marcarlo, que es otra cosa que responder — y dejaría el envío
|
|
38819
|
+
// bloqueado sin que se vea por qué.
|
|
38820
|
+
group[q.name] = new FormControl(false, { nonNullable: true });
|
|
38821
|
+
continue;
|
|
38822
|
+
}
|
|
38738
38823
|
group[q.name] = new FormControl({ value: '', disabled: false }, q.required ? [Validators.required] : []);
|
|
38739
38824
|
}
|
|
38740
38825
|
this.form = new FormGroup(group);
|
|
@@ -38752,6 +38837,74 @@ class SurveyResponseComponent {
|
|
|
38752
38837
|
questionControl(name) {
|
|
38753
38838
|
return this.form.get(name);
|
|
38754
38839
|
}
|
|
38840
|
+
booleanControl(name) {
|
|
38841
|
+
return this.form.get(name);
|
|
38842
|
+
}
|
|
38843
|
+
optionControl(name, optionId) {
|
|
38844
|
+
const key = `${name}::${optionId}`;
|
|
38845
|
+
let control = this.multiControls.get(key);
|
|
38846
|
+
if (!control) {
|
|
38847
|
+
control = new FormControl(false, { nonNullable: true });
|
|
38848
|
+
this.multiControls.set(key, control);
|
|
38849
|
+
}
|
|
38850
|
+
return control;
|
|
38851
|
+
}
|
|
38852
|
+
/** Opciones tal como las escribió quien creó la encuesta — no se traducen. */
|
|
38853
|
+
optionsOf(q) {
|
|
38854
|
+
return [...(q.options ?? [])]
|
|
38855
|
+
.map((o, index) => ({ id: o.id, name: o.name, order: o.order ?? index }))
|
|
38856
|
+
.sort((a, b) => a.order - b.order);
|
|
38857
|
+
}
|
|
38858
|
+
/**
|
|
38859
|
+
* `val-radio-input` pide un `InputMetadata` completo (no `Partial`), así que
|
|
38860
|
+
* se arma acá en vez de en el template.
|
|
38861
|
+
*/
|
|
38862
|
+
radioProps(q) {
|
|
38863
|
+
return {
|
|
38864
|
+
token: q.name,
|
|
38865
|
+
name: q.name,
|
|
38866
|
+
label: '',
|
|
38867
|
+
hint: '',
|
|
38868
|
+
placeholder: '',
|
|
38869
|
+
type: InputType.RADIO,
|
|
38870
|
+
order: q.order,
|
|
38871
|
+
validators: [],
|
|
38872
|
+
errors: {},
|
|
38873
|
+
state: ComponentStates.ENABLED,
|
|
38874
|
+
control: this.questionControl(q.name),
|
|
38875
|
+
options: this.optionsOf(q),
|
|
38876
|
+
};
|
|
38877
|
+
}
|
|
38878
|
+
placeholderOf(q) {
|
|
38879
|
+
return q.placeholderText || q.placeholder || '';
|
|
38880
|
+
}
|
|
38881
|
+
hintOf(q) {
|
|
38882
|
+
return q.hintText || q.hint || '';
|
|
38883
|
+
}
|
|
38884
|
+
/**
|
|
38885
|
+
* Tipo del `<input>` para las preguntas que se responden escribiendo. Nada de
|
|
38886
|
+
* `parseInputType` de `FormSchemaBuilderService`: ese mapea al enum de
|
|
38887
|
+
* `val-form`, y acá no hay `val-form` de por medio (ver el comentario de
|
|
38888
|
+
* clase). Un tipo desconocido cae a texto, que siempre se puede responder.
|
|
38889
|
+
*/
|
|
38890
|
+
inputTypeOf(type) {
|
|
38891
|
+
switch (type) {
|
|
38892
|
+
case 'EMAIL':
|
|
38893
|
+
return 'email';
|
|
38894
|
+
case 'NUMBER':
|
|
38895
|
+
return 'number';
|
|
38896
|
+
case 'PHONE':
|
|
38897
|
+
return 'tel';
|
|
38898
|
+
default:
|
|
38899
|
+
return 'text';
|
|
38900
|
+
}
|
|
38901
|
+
}
|
|
38902
|
+
/** Las opciones marcadas de una pregunta MULTI_SELECT, en el orden del schema. */
|
|
38903
|
+
selectedOptions(q) {
|
|
38904
|
+
return this.optionsOf(q)
|
|
38905
|
+
.filter(opt => this.multiControls.get(`${q.name}::${opt.id}`)?.value)
|
|
38906
|
+
.map(opt => opt.id);
|
|
38907
|
+
}
|
|
38755
38908
|
questionLabel(q) {
|
|
38756
38909
|
// Texto del CLIENTE (regla #4): quien creó la encuesta escribió el
|
|
38757
38910
|
// enunciado tal cual, no se traduce.
|
|
@@ -38773,8 +38926,20 @@ class SurveyResponseComponent {
|
|
|
38773
38926
|
const cfg = this.typeConfig();
|
|
38774
38927
|
if (!cfg)
|
|
38775
38928
|
return;
|
|
38929
|
+
// MULTI_SELECT no vive en el FormGroup, así que `form.invalid` no lo cubre:
|
|
38930
|
+
// una obligatoria sin nada marcado hay que frenarla acá o se envía vacía.
|
|
38931
|
+
const multiRequired = this.questions().filter(q => q.type === 'MULTI_SELECT' && q.required);
|
|
38932
|
+
if (multiRequired.some(q => !this.selectedOptions(q).length)) {
|
|
38933
|
+
this.multiSelectError.set(true);
|
|
38934
|
+
return;
|
|
38935
|
+
}
|
|
38936
|
+
this.multiSelectError.set(false);
|
|
38776
38937
|
this.sending.set(true);
|
|
38777
|
-
const fields = this.form.getRawValue();
|
|
38938
|
+
const fields = { ...this.form.getRawValue() };
|
|
38939
|
+
for (const q of this.questions()) {
|
|
38940
|
+
if (q.type === 'MULTI_SELECT')
|
|
38941
|
+
fields[q.name] = this.selectedOptions(q);
|
|
38942
|
+
}
|
|
38778
38943
|
const payload = {
|
|
38779
38944
|
type: cfg.typeId,
|
|
38780
38945
|
title: cfg.label,
|
|
@@ -38797,12 +38962,12 @@ class SurveyResponseComponent {
|
|
|
38797
38962
|
this.errors.handle(err, {
|
|
38798
38963
|
context: 'surveyResponse.submit',
|
|
38799
38964
|
fallbackKey: 'sendError',
|
|
38800
|
-
i18nNamespace: NAMESPACE$
|
|
38965
|
+
i18nNamespace: NAMESPACE$3,
|
|
38801
38966
|
});
|
|
38802
38967
|
}
|
|
38803
38968
|
}
|
|
38804
38969
|
t(key) {
|
|
38805
|
-
return this.i18n.t(key, NAMESPACE$
|
|
38970
|
+
return this.i18n.t(key, NAMESPACE$3);
|
|
38806
38971
|
}
|
|
38807
38972
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyResponseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38808
38973
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SurveyResponseComponent, isStandalone: true, selector: "val-survey-response", inputs: { props: "props" }, outputs: { submitted: "submitted" }, ngImport: i0, template: `
|
|
@@ -38839,21 +39004,97 @@ class SurveyResponseComponent {
|
|
|
38839
39004
|
|
|
38840
39005
|
@for (q of questions(); track q.name) {
|
|
38841
39006
|
<div class="survey-response__question">
|
|
38842
|
-
@
|
|
38843
|
-
|
|
38844
|
-
|
|
38845
|
-
|
|
38846
|
-
|
|
38847
|
-
|
|
38848
|
-
|
|
38849
|
-
|
|
38850
|
-
|
|
38851
|
-
|
|
38852
|
-
|
|
39007
|
+
@switch (q.type) {
|
|
39008
|
+
@case (emojiType) {
|
|
39009
|
+
<val-emoji-rating [props]="{ control: questionControl(q.name), label: questionLabel(q) }" />
|
|
39010
|
+
}
|
|
39011
|
+
@case ('TEXTAREA') {
|
|
39012
|
+
<val-textarea-input
|
|
39013
|
+
[props]="{
|
|
39014
|
+
control: questionControl(q.name),
|
|
39015
|
+
label: questionLabel(q),
|
|
39016
|
+
hint: hintOf(q),
|
|
39017
|
+
placeholder: placeholderOf(q),
|
|
39018
|
+
autoGrow: true,
|
|
39019
|
+
}"
|
|
39020
|
+
/>
|
|
39021
|
+
}
|
|
39022
|
+
@case ('SELECT') {
|
|
39023
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39024
|
+
<val-select-input
|
|
39025
|
+
[props]="{
|
|
39026
|
+
control: questionControl(q.name),
|
|
39027
|
+
type: selectType,
|
|
39028
|
+
placeholder: placeholderOf(q),
|
|
39029
|
+
options: optionsOf(q),
|
|
39030
|
+
}"
|
|
39031
|
+
/>
|
|
39032
|
+
</val-form-field>
|
|
39033
|
+
@if (hintOf(q)) {
|
|
39034
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39035
|
+
}
|
|
39036
|
+
}
|
|
39037
|
+
@case ('RADIO') {
|
|
39038
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39039
|
+
<val-radio-input [props]="radioProps(q)" />
|
|
39040
|
+
</val-form-field>
|
|
39041
|
+
@if (hintOf(q)) {
|
|
39042
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39043
|
+
}
|
|
39044
|
+
}
|
|
39045
|
+
@case ('MULTI_SELECT') {
|
|
39046
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39047
|
+
<div class="survey-response__options">
|
|
39048
|
+
@for (opt of optionsOf(q); track opt.id) {
|
|
39049
|
+
<val-check-input
|
|
39050
|
+
[props]="{ control: optionControl(q.name, opt.id), label: opt.name, labelPlacement: 'end' }"
|
|
39051
|
+
/>
|
|
39052
|
+
}
|
|
39053
|
+
</div>
|
|
39054
|
+
</val-form-field>
|
|
39055
|
+
@if (hintOf(q)) {
|
|
39056
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39057
|
+
}
|
|
39058
|
+
}
|
|
39059
|
+
@case ('CHECK') {
|
|
39060
|
+
<val-check-input
|
|
39061
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), labelPlacement: 'end' }"
|
|
39062
|
+
/>
|
|
39063
|
+
}
|
|
39064
|
+
@case ('TOGGLE') {
|
|
39065
|
+
<val-toggle-input
|
|
39066
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), justify: 'space-between' }"
|
|
39067
|
+
/>
|
|
39068
|
+
}
|
|
39069
|
+
@case ('DATE') {
|
|
39070
|
+
<val-date-picker
|
|
39071
|
+
[props]="{
|
|
39072
|
+
control: questionControl(q.name),
|
|
39073
|
+
label: questionLabel(q),
|
|
39074
|
+
hint: hintOf(q),
|
|
39075
|
+
placeholder: placeholderOf(q),
|
|
39076
|
+
}"
|
|
39077
|
+
/>
|
|
39078
|
+
}
|
|
39079
|
+
@default {
|
|
39080
|
+
<val-text-input
|
|
39081
|
+
[props]="{
|
|
39082
|
+
control: questionControl(q.name),
|
|
39083
|
+
label: questionLabel(q),
|
|
39084
|
+
hint: hintOf(q),
|
|
39085
|
+
placeholder: placeholderOf(q),
|
|
39086
|
+
inputType: inputTypeOf(q.type),
|
|
39087
|
+
}"
|
|
39088
|
+
/>
|
|
39089
|
+
}
|
|
38853
39090
|
}
|
|
38854
39091
|
</div>
|
|
38855
39092
|
}
|
|
38856
39093
|
|
|
39094
|
+
@if (multiSelectError()) {
|
|
39095
|
+
<p class="survey-response__error">{{ t('required') }}</p>
|
|
39096
|
+
}
|
|
39097
|
+
|
|
38857
39098
|
<val-button
|
|
38858
39099
|
[props]="{
|
|
38859
39100
|
token: 'survey-response-submit',
|
|
@@ -38872,7 +39113,7 @@ class SurveyResponseComponent {
|
|
|
38872
39113
|
}
|
|
38873
39114
|
}
|
|
38874
39115
|
}
|
|
38875
|
-
`, isInline: true, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__loading{min-height:120px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: EmojiRatingComponent, selector: "val-emoji-rating", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }] }); }
|
|
39116
|
+
`, isInline: true, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__options{display:flex;flex-direction:column;gap:4px}.survey-response__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}.survey-response__hint{display:block;margin-top:4px;font-size:.8125rem;color:var(--ion-color-medium, #92949c)}.survey-response__loading{min-height:120px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: RadioInputComponent, selector: "val-radio-input", inputs: ["props"] }, { kind: "component", type: CheckInputComponent, selector: "val-check-input", inputs: ["preset", "props"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: DatePickerComponent, selector: "val-date-picker", inputs: ["props"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: EmojiRatingComponent, selector: "val-emoji-rating", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }] }); }
|
|
38876
39117
|
}
|
|
38877
39118
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyResponseComponent, decorators: [{
|
|
38878
39119
|
type: Component,
|
|
@@ -38883,6 +39124,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
38883
39124
|
TitleComponent,
|
|
38884
39125
|
TextInputComponent,
|
|
38885
39126
|
TextareaInputComponent,
|
|
39127
|
+
SearchSelectorComponent,
|
|
39128
|
+
RadioInputComponent,
|
|
39129
|
+
CheckInputComponent,
|
|
39130
|
+
ToggleInputComponent,
|
|
39131
|
+
DatePickerComponent,
|
|
39132
|
+
FormFieldComponent,
|
|
38886
39133
|
EmojiRatingComponent,
|
|
38887
39134
|
ButtonComponent,
|
|
38888
39135
|
EmptyStateComponent,
|
|
@@ -38920,21 +39167,97 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
38920
39167
|
|
|
38921
39168
|
@for (q of questions(); track q.name) {
|
|
38922
39169
|
<div class="survey-response__question">
|
|
38923
|
-
@
|
|
38924
|
-
|
|
38925
|
-
|
|
38926
|
-
|
|
38927
|
-
|
|
38928
|
-
|
|
38929
|
-
|
|
38930
|
-
|
|
38931
|
-
|
|
38932
|
-
|
|
38933
|
-
|
|
39170
|
+
@switch (q.type) {
|
|
39171
|
+
@case (emojiType) {
|
|
39172
|
+
<val-emoji-rating [props]="{ control: questionControl(q.name), label: questionLabel(q) }" />
|
|
39173
|
+
}
|
|
39174
|
+
@case ('TEXTAREA') {
|
|
39175
|
+
<val-textarea-input
|
|
39176
|
+
[props]="{
|
|
39177
|
+
control: questionControl(q.name),
|
|
39178
|
+
label: questionLabel(q),
|
|
39179
|
+
hint: hintOf(q),
|
|
39180
|
+
placeholder: placeholderOf(q),
|
|
39181
|
+
autoGrow: true,
|
|
39182
|
+
}"
|
|
39183
|
+
/>
|
|
39184
|
+
}
|
|
39185
|
+
@case ('SELECT') {
|
|
39186
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39187
|
+
<val-select-input
|
|
39188
|
+
[props]="{
|
|
39189
|
+
control: questionControl(q.name),
|
|
39190
|
+
type: selectType,
|
|
39191
|
+
placeholder: placeholderOf(q),
|
|
39192
|
+
options: optionsOf(q),
|
|
39193
|
+
}"
|
|
39194
|
+
/>
|
|
39195
|
+
</val-form-field>
|
|
39196
|
+
@if (hintOf(q)) {
|
|
39197
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39198
|
+
}
|
|
39199
|
+
}
|
|
39200
|
+
@case ('RADIO') {
|
|
39201
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39202
|
+
<val-radio-input [props]="radioProps(q)" />
|
|
39203
|
+
</val-form-field>
|
|
39204
|
+
@if (hintOf(q)) {
|
|
39205
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39206
|
+
}
|
|
39207
|
+
}
|
|
39208
|
+
@case ('MULTI_SELECT') {
|
|
39209
|
+
<val-form-field [label]="questionLabel(q)">
|
|
39210
|
+
<div class="survey-response__options">
|
|
39211
|
+
@for (opt of optionsOf(q); track opt.id) {
|
|
39212
|
+
<val-check-input
|
|
39213
|
+
[props]="{ control: optionControl(q.name, opt.id), label: opt.name, labelPlacement: 'end' }"
|
|
39214
|
+
/>
|
|
39215
|
+
}
|
|
39216
|
+
</div>
|
|
39217
|
+
</val-form-field>
|
|
39218
|
+
@if (hintOf(q)) {
|
|
39219
|
+
<span class="survey-response__hint">{{ hintOf(q) }}</span>
|
|
39220
|
+
}
|
|
39221
|
+
}
|
|
39222
|
+
@case ('CHECK') {
|
|
39223
|
+
<val-check-input
|
|
39224
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), labelPlacement: 'end' }"
|
|
39225
|
+
/>
|
|
39226
|
+
}
|
|
39227
|
+
@case ('TOGGLE') {
|
|
39228
|
+
<val-toggle-input
|
|
39229
|
+
[props]="{ control: booleanControl(q.name), label: questionLabel(q), justify: 'space-between' }"
|
|
39230
|
+
/>
|
|
39231
|
+
}
|
|
39232
|
+
@case ('DATE') {
|
|
39233
|
+
<val-date-picker
|
|
39234
|
+
[props]="{
|
|
39235
|
+
control: questionControl(q.name),
|
|
39236
|
+
label: questionLabel(q),
|
|
39237
|
+
hint: hintOf(q),
|
|
39238
|
+
placeholder: placeholderOf(q),
|
|
39239
|
+
}"
|
|
39240
|
+
/>
|
|
39241
|
+
}
|
|
39242
|
+
@default {
|
|
39243
|
+
<val-text-input
|
|
39244
|
+
[props]="{
|
|
39245
|
+
control: questionControl(q.name),
|
|
39246
|
+
label: questionLabel(q),
|
|
39247
|
+
hint: hintOf(q),
|
|
39248
|
+
placeholder: placeholderOf(q),
|
|
39249
|
+
inputType: inputTypeOf(q.type),
|
|
39250
|
+
}"
|
|
39251
|
+
/>
|
|
39252
|
+
}
|
|
38934
39253
|
}
|
|
38935
39254
|
</div>
|
|
38936
39255
|
}
|
|
38937
39256
|
|
|
39257
|
+
@if (multiSelectError()) {
|
|
39258
|
+
<p class="survey-response__error">{{ t('required') }}</p>
|
|
39259
|
+
}
|
|
39260
|
+
|
|
38938
39261
|
<val-button
|
|
38939
39262
|
[props]="{
|
|
38940
39263
|
token: 'survey-response-submit',
|
|
@@ -38953,7 +39276,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
38953
39276
|
}
|
|
38954
39277
|
}
|
|
38955
39278
|
}
|
|
38956
|
-
`, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__loading{min-height:120px}\n"] }]
|
|
39279
|
+
`, styles: [":host{display:block}.survey-response{display:flex;flex-direction:column;gap:16px}.survey-response__question{display:block}.survey-response__options{display:flex;flex-direction:column;gap:4px}.survey-response__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}.survey-response__hint{display:block;margin-top:4px;font-size:.8125rem;color:var(--ion-color-medium, #92949c)}.survey-response__loading{min-height:120px}\n"] }]
|
|
38957
39280
|
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
38958
39281
|
type: Input
|
|
38959
39282
|
}], submitted: [{
|
|
@@ -39170,6 +39493,427 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39170
39493
|
args: [{ providedIn: 'root' }]
|
|
39171
39494
|
}] });
|
|
39172
39495
|
|
|
39496
|
+
const FIELD_SCHEMA_EDITOR_I18N = {
|
|
39497
|
+
es: {
|
|
39498
|
+
presetsTitle: 'Empieza desde',
|
|
39499
|
+
labelLabel: 'Texto del campo',
|
|
39500
|
+
labelPlaceholder: 'Escribe lo que verá quien responde',
|
|
39501
|
+
typeLabel: 'Tipo de campo',
|
|
39502
|
+
placeholderLabel: 'Texto de ayuda dentro del campo',
|
|
39503
|
+
hintLabel: 'Nota bajo el campo',
|
|
39504
|
+
requiredLabel: 'Obligatorio',
|
|
39505
|
+
optionsTitle: 'Opciones',
|
|
39506
|
+
optionsHint: 'Estas son las alternativas que puede elegir quien responde.',
|
|
39507
|
+
optionsAdd: 'Agregar opción',
|
|
39508
|
+
optionsList: 'Opciones',
|
|
39509
|
+
optionsPlaceholder: 'Escribe una opción',
|
|
39510
|
+
optionsEmpty: 'Todavía no hay opciones.',
|
|
39511
|
+
optionsRemove: 'Quitar opción',
|
|
39512
|
+
optionsReorder: 'Reordenar opción',
|
|
39513
|
+
errorIncomplete: 'Ponle un texto al campo y elige su tipo.',
|
|
39514
|
+
errorOptionsRequired: 'Este tipo de campo necesita al menos una opción.',
|
|
39515
|
+
typeTEXT: 'Texto corto',
|
|
39516
|
+
typeTEXTAREA: 'Texto largo',
|
|
39517
|
+
typeEMAIL: 'Correo',
|
|
39518
|
+
typePHONE: 'Teléfono',
|
|
39519
|
+
typeNUMBER: 'Número',
|
|
39520
|
+
typeDATE: 'Fecha',
|
|
39521
|
+
typeSELECT: 'Lista desplegable',
|
|
39522
|
+
typeRADIO: 'Una sola opción',
|
|
39523
|
+
typeMULTI_SELECT: 'Varias opciones',
|
|
39524
|
+
typeCHECK: 'Casilla',
|
|
39525
|
+
typeTOGGLE: 'Sí o no',
|
|
39526
|
+
typeCURRENCY: 'Monto',
|
|
39527
|
+
typeATTACHMENT: 'Archivo adjunto',
|
|
39528
|
+
typeFILE: 'Archivo',
|
|
39529
|
+
typeEMOJI_RATING: 'Calificación con emoji',
|
|
39530
|
+
},
|
|
39531
|
+
en: {
|
|
39532
|
+
presetsTitle: 'Start from',
|
|
39533
|
+
labelLabel: 'Field text',
|
|
39534
|
+
labelPlaceholder: 'Write what the person will see',
|
|
39535
|
+
typeLabel: 'Field type',
|
|
39536
|
+
placeholderLabel: 'Helper text inside the field',
|
|
39537
|
+
hintLabel: 'Note below the field',
|
|
39538
|
+
requiredLabel: 'Required',
|
|
39539
|
+
optionsTitle: 'Options',
|
|
39540
|
+
optionsHint: 'These are the choices the person can pick.',
|
|
39541
|
+
optionsAdd: 'Add option',
|
|
39542
|
+
optionsList: 'Options',
|
|
39543
|
+
optionsPlaceholder: 'Write an option',
|
|
39544
|
+
optionsEmpty: 'No options yet.',
|
|
39545
|
+
optionsRemove: 'Remove option',
|
|
39546
|
+
optionsReorder: 'Reorder option',
|
|
39547
|
+
errorIncomplete: 'Give the field a text and pick its type.',
|
|
39548
|
+
errorOptionsRequired: 'This field type needs at least one option.',
|
|
39549
|
+
typeTEXT: 'Short text',
|
|
39550
|
+
typeTEXTAREA: 'Long text',
|
|
39551
|
+
typeEMAIL: 'Email',
|
|
39552
|
+
typePHONE: 'Phone',
|
|
39553
|
+
typeNUMBER: 'Number',
|
|
39554
|
+
typeDATE: 'Date',
|
|
39555
|
+
typeSELECT: 'Dropdown',
|
|
39556
|
+
typeRADIO: 'Single choice',
|
|
39557
|
+
typeMULTI_SELECT: 'Multiple choice',
|
|
39558
|
+
typeCHECK: 'Checkbox',
|
|
39559
|
+
typeTOGGLE: 'Yes or no',
|
|
39560
|
+
typeCURRENCY: 'Amount',
|
|
39561
|
+
typeATTACHMENT: 'Attachment',
|
|
39562
|
+
typeFILE: 'File',
|
|
39563
|
+
typeEMOJI_RATING: 'Emoji rating',
|
|
39564
|
+
},
|
|
39565
|
+
};
|
|
39566
|
+
|
|
39567
|
+
const NAMESPACE$2 = 'FieldSchemaEditor';
|
|
39568
|
+
/**
|
|
39569
|
+
* Tipos cuyo valor sale de una lista cerrada que define quien arma el
|
|
39570
|
+
* formulario — sin al menos una opción, el campo no se puede responder.
|
|
39571
|
+
* Espejo de `fieldRequiresOptions` que vivía duplicado en bingo.
|
|
39572
|
+
*/
|
|
39573
|
+
const FIELD_TYPES_WITH_OPTIONS = ['SELECT', 'RADIO', 'MULTI_SELECT'];
|
|
39574
|
+
let fieldUid = 0;
|
|
39575
|
+
/**
|
|
39576
|
+
* val-field-schema-editor
|
|
39577
|
+
*
|
|
39578
|
+
* Edita UN campo de un formulario dinámico: texto, tipo, placeholder, nota,
|
|
39579
|
+
* obligatoriedad y opciones. Es la pieza que faltaba en la lib — hasta ahora
|
|
39580
|
+
* el único editor de campos con este nivel vivía dentro de bingo
|
|
39581
|
+
* (`checkout-field-modal.component.ts`), invisible para el resto del factory,
|
|
39582
|
+
* y `val-survey-builder` había terminado con una versión pobre de lo mismo
|
|
39583
|
+
* (dos tipos fijos, sin placeholder ni opciones).
|
|
39584
|
+
*
|
|
39585
|
+
* Es agnóstico de dominio a propósito:
|
|
39586
|
+
* - el **catálogo de tipos** (`allowedTypes`) lo decide el consumer, porque es
|
|
39587
|
+
* él quien sabe qué sabe renderizar su formulario;
|
|
39588
|
+
* - los **presets** los pasa el consumer, porque "correo del comprador" es de
|
|
39589
|
+
* checkout y no significa nada en una encuesta.
|
|
39590
|
+
*
|
|
39591
|
+
* No trae cáscara de modal: el consumer lo envuelve en `val-modal-layout` (o
|
|
39592
|
+
* en lo que quiera) y dispara `submit()` desde su propio botón, igual que hace
|
|
39593
|
+
* `survey-create-modal` con `val-survey-builder`.
|
|
39594
|
+
*/
|
|
39595
|
+
class FieldSchemaEditorComponent {
|
|
39596
|
+
constructor() {
|
|
39597
|
+
this.props = { allowedTypes: ['TEXT'] };
|
|
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();
|
|
39606
|
+
this.i18n = inject(I18nService);
|
|
39607
|
+
this.formSchemas = inject(FormSchemaBuilderService);
|
|
39608
|
+
this.labelControl = new FormControl('', { nonNullable: true });
|
|
39609
|
+
this.placeholderControl = new FormControl('', { nonNullable: true });
|
|
39610
|
+
this.hintControl = new FormControl('', { nonNullable: true });
|
|
39611
|
+
this.requiredControl = new FormControl(true, { nonNullable: true });
|
|
39612
|
+
this.typeControl = new FormControl('TEXT', { nonNullable: true });
|
|
39613
|
+
this.options = signal([]);
|
|
39614
|
+
this.validationError = signal('');
|
|
39615
|
+
this.selectedPresetId = signal('');
|
|
39616
|
+
/** Se refresca con cada cambio de tipo — `needsOptions` no puede leer el control directo. */
|
|
39617
|
+
this.currentType = signal('TEXT');
|
|
39618
|
+
/** Una vez que se toca el token a mano (o se edita un campo ya guardado) deja de derivarse del label. */
|
|
39619
|
+
this.nameLocked = false;
|
|
39620
|
+
this.name = '';
|
|
39621
|
+
this.fieldId = '';
|
|
39622
|
+
this.typeSelectProps = computed(() => {
|
|
39623
|
+
this.i18n.lang();
|
|
39624
|
+
return {
|
|
39625
|
+
control: this.typeControl,
|
|
39626
|
+
type: InputType.SELECT,
|
|
39627
|
+
state: this.state(),
|
|
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',
|
|
39634
|
+
options: this.allowedTypes().map((type, order) => ({ id: type, name: this.typeLabel(type), order })),
|
|
39635
|
+
};
|
|
39636
|
+
});
|
|
39637
|
+
this.optionsEditorProps = computed(() => {
|
|
39638
|
+
this.i18n.lang();
|
|
39639
|
+
return {
|
|
39640
|
+
title: this.t('optionsTitle'),
|
|
39641
|
+
hint: this.t('optionsHint'),
|
|
39642
|
+
addLabel: this.t('optionsAdd'),
|
|
39643
|
+
optionsLabel: this.t('optionsList'),
|
|
39644
|
+
placeholder: this.t('optionsPlaceholder'),
|
|
39645
|
+
emptyText: this.t('optionsEmpty'),
|
|
39646
|
+
removeOptionLabel: this.t('optionsRemove'),
|
|
39647
|
+
reorderOptionLabel: this.t('optionsReorder'),
|
|
39648
|
+
state: this.state(),
|
|
39649
|
+
options: this.options(),
|
|
39650
|
+
};
|
|
39651
|
+
});
|
|
39652
|
+
if (!this.i18n.hasNamespace(NAMESPACE$2)) {
|
|
39653
|
+
this.i18n.registerDefaults(NAMESPACE$2, FIELD_SCHEMA_EDITOR_I18N);
|
|
39654
|
+
}
|
|
39655
|
+
this.typeControl.valueChanges.subscribe(value => {
|
|
39656
|
+
this.currentType.set(value || 'TEXT');
|
|
39657
|
+
this.emitChange();
|
|
39658
|
+
});
|
|
39659
|
+
this.labelControl.valueChanges.subscribe(value => {
|
|
39660
|
+
if (!this.nameLocked)
|
|
39661
|
+
this.name = this.formSchemas.toToken(value || '');
|
|
39662
|
+
this.emitChange();
|
|
39663
|
+
});
|
|
39664
|
+
this.placeholderControl.valueChanges.subscribe(() => this.emitChange());
|
|
39665
|
+
this.hintControl.valueChanges.subscribe(() => this.emitChange());
|
|
39666
|
+
this.requiredControl.valueChanges.subscribe(() => this.emitChange());
|
|
39667
|
+
}
|
|
39668
|
+
ngOnInit() {
|
|
39669
|
+
const initial = this.props.field;
|
|
39670
|
+
if (initial) {
|
|
39671
|
+
this.fieldId = initial.id;
|
|
39672
|
+
this.nameLocked = true;
|
|
39673
|
+
this.name = initial.name;
|
|
39674
|
+
this.labelControl.setValue(initial.label ?? '');
|
|
39675
|
+
this.placeholderControl.setValue(initial.placeholderText ?? '');
|
|
39676
|
+
this.hintControl.setValue(initial.hintText ?? '');
|
|
39677
|
+
this.requiredControl.setValue(!!initial.required);
|
|
39678
|
+
this.typeControl.setValue(this.coerceType(initial.type));
|
|
39679
|
+
this.options.set(initial.options ?? []);
|
|
39680
|
+
return;
|
|
39681
|
+
}
|
|
39682
|
+
this.fieldId = `field-${++fieldUid}`;
|
|
39683
|
+
this.typeControl.setValue(this.coerceType(this.typeControl.value));
|
|
39684
|
+
const first = this.props.presets?.[0];
|
|
39685
|
+
if (first)
|
|
39686
|
+
this.selectPreset(first);
|
|
39687
|
+
}
|
|
39688
|
+
t(key) {
|
|
39689
|
+
this.i18n.lang();
|
|
39690
|
+
return this.i18n.t(key, NAMESPACE$2);
|
|
39691
|
+
}
|
|
39692
|
+
state() {
|
|
39693
|
+
return this.props.state ?? ComponentStates.ENABLED;
|
|
39694
|
+
}
|
|
39695
|
+
showPresets() {
|
|
39696
|
+
return this.props.mode !== 'edit' && !!this.props.presets?.length;
|
|
39697
|
+
}
|
|
39698
|
+
needsOptions() {
|
|
39699
|
+
return FIELD_TYPES_WITH_OPTIONS.includes(this.currentType());
|
|
39700
|
+
}
|
|
39701
|
+
typeLabel(type) {
|
|
39702
|
+
return this.props.typeLabels?.[type] || this.t(`type${type}`);
|
|
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
|
+
}
|
|
39714
|
+
selectPreset(preset) {
|
|
39715
|
+
this.selectedPresetId.set(preset.id);
|
|
39716
|
+
const value = preset.field;
|
|
39717
|
+
// El preset fija el token: "correo del comprador" tiene que llamarse
|
|
39718
|
+
// `email` aunque después le cambien el texto visible.
|
|
39719
|
+
this.nameLocked = !!value.name;
|
|
39720
|
+
this.name = value.name || this.formSchemas.toToken(value.label || '');
|
|
39721
|
+
this.labelControl.setValue(value.label ?? '');
|
|
39722
|
+
this.placeholderControl.setValue(value.placeholderText ?? '');
|
|
39723
|
+
this.hintControl.setValue(value.hintText ?? '');
|
|
39724
|
+
this.requiredControl.setValue(!!value.required);
|
|
39725
|
+
this.typeControl.setValue(this.coerceType(value.type));
|
|
39726
|
+
this.options.set(value.options ?? []);
|
|
39727
|
+
this.emitChange();
|
|
39728
|
+
}
|
|
39729
|
+
/**
|
|
39730
|
+
* Valida y emite. Público a propósito: lo llama el consumer desde el botón
|
|
39731
|
+
* de su propia cáscara (modal, página o acordeón).
|
|
39732
|
+
*/
|
|
39733
|
+
submit() {
|
|
39734
|
+
const field = this.value();
|
|
39735
|
+
if (!field.label || !field.name || !field.type) {
|
|
39736
|
+
this.validationError.set(this.t('errorIncomplete'));
|
|
39737
|
+
return false;
|
|
39738
|
+
}
|
|
39739
|
+
if (this.needsOptions() && !(field.options?.length ?? 0)) {
|
|
39740
|
+
this.validationError.set(this.t('errorOptionsRequired'));
|
|
39741
|
+
return false;
|
|
39742
|
+
}
|
|
39743
|
+
this.validationError.set('');
|
|
39744
|
+
this.save.emit(field);
|
|
39745
|
+
return true;
|
|
39746
|
+
}
|
|
39747
|
+
/** El campo tal como está en pantalla, sin validar. */
|
|
39748
|
+
value() {
|
|
39749
|
+
const label = (this.labelControl.value || '').trim();
|
|
39750
|
+
return {
|
|
39751
|
+
id: this.fieldId,
|
|
39752
|
+
name: this.formSchemas.toToken(this.name || label),
|
|
39753
|
+
label,
|
|
39754
|
+
placeholderText: (this.placeholderControl.value || '').trim(),
|
|
39755
|
+
hintText: (this.hintControl.value || '').trim(),
|
|
39756
|
+
type: this.coerceType(this.typeControl.value),
|
|
39757
|
+
required: this.requiredControl.value,
|
|
39758
|
+
options: this.needsOptions() ? this.options().map((option, index) => ({ ...option, order: index })) : undefined,
|
|
39759
|
+
};
|
|
39760
|
+
}
|
|
39761
|
+
allowedTypes() {
|
|
39762
|
+
return this.props.allowedTypes?.length ? this.props.allowedTypes : ['TEXT'];
|
|
39763
|
+
}
|
|
39764
|
+
/**
|
|
39765
|
+
* Un tipo fuera del catálogo del consumer cae al primero permitido. Pasa al
|
|
39766
|
+
* editar un campo guardado con un tipo que la app ya no ofrece (bingo lo
|
|
39767
|
+
* hacía con ATTACHMENT cuando el medio de pago no lo admite): sin esto, el
|
|
39768
|
+
* select queda en un valor que no está en su lista y se ve vacío.
|
|
39769
|
+
*/
|
|
39770
|
+
coerceType(type) {
|
|
39771
|
+
const allowed = this.allowedTypes();
|
|
39772
|
+
return allowed.includes(type) ? type : allowed[0];
|
|
39773
|
+
}
|
|
39774
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldSchemaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
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: `
|
|
39776
|
+
<div class="field-schema-editor">
|
|
39777
|
+
@if (showPresets()) {
|
|
39778
|
+
<section class="field-schema-editor__presets">
|
|
39779
|
+
<span class="field-schema-editor__section-label">{{ props.presetsTitle || t('presetsTitle') }}</span>
|
|
39780
|
+
<div class="field-schema-editor__preset-grid">
|
|
39781
|
+
@for (preset of props.presets; track preset.id) {
|
|
39782
|
+
<button
|
|
39783
|
+
type="button"
|
|
39784
|
+
class="field-schema-editor__preset"
|
|
39785
|
+
[class.field-schema-editor__preset--selected]="selectedPresetId() === preset.id"
|
|
39786
|
+
(click)="selectPreset(preset)"
|
|
39787
|
+
>
|
|
39788
|
+
<strong>{{ preset.label }}</strong>
|
|
39789
|
+
@if (preset.description) {
|
|
39790
|
+
<span>{{ preset.description }}</span>
|
|
39791
|
+
}
|
|
39792
|
+
</button>
|
|
39793
|
+
}
|
|
39794
|
+
</div>
|
|
39795
|
+
</section>
|
|
39796
|
+
}
|
|
39797
|
+
|
|
39798
|
+
<val-form-field [label]="t('labelLabel')">
|
|
39799
|
+
<val-text-input [props]="{ control: labelControl, placeholder: t('labelPlaceholder'), state: state() }" />
|
|
39800
|
+
</val-form-field>
|
|
39801
|
+
|
|
39802
|
+
<val-form-field [label]="t('typeLabel')">
|
|
39803
|
+
<val-select-input [props]="typeSelectProps()" />
|
|
39804
|
+
</val-form-field>
|
|
39805
|
+
|
|
39806
|
+
@if (props.showPlaceholder !== false) {
|
|
39807
|
+
<val-form-field [label]="t('placeholderLabel')">
|
|
39808
|
+
<val-textarea-input [props]="{ control: placeholderControl, autoGrow: true, state: state() }" />
|
|
39809
|
+
</val-form-field>
|
|
39810
|
+
}
|
|
39811
|
+
|
|
39812
|
+
@if (props.showHint !== false) {
|
|
39813
|
+
<val-form-field [label]="t('hintLabel')">
|
|
39814
|
+
<val-textarea-input [props]="{ control: hintControl, autoGrow: true, state: state() }" />
|
|
39815
|
+
</val-form-field>
|
|
39816
|
+
}
|
|
39817
|
+
|
|
39818
|
+
<val-toggle-input
|
|
39819
|
+
[props]="{
|
|
39820
|
+
control: requiredControl,
|
|
39821
|
+
label: t('requiredLabel'),
|
|
39822
|
+
justify: 'space-between',
|
|
39823
|
+
state: state(),
|
|
39824
|
+
}"
|
|
39825
|
+
/>
|
|
39826
|
+
|
|
39827
|
+
@if (needsOptions()) {
|
|
39828
|
+
<val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="setOptions($event)" />
|
|
39829
|
+
}
|
|
39830
|
+
|
|
39831
|
+
@if (validationError()) {
|
|
39832
|
+
<p class="field-schema-editor__error">{{ validationError() }}</p>
|
|
39833
|
+
}
|
|
39834
|
+
</div>
|
|
39835
|
+
`, isInline: true, styles: [":host{display:block}.field-schema-editor{display:flex;flex-direction:column;gap:12px}.field-schema-editor__presets{display:flex;flex-direction:column;gap:8px}.field-schema-editor__section-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px}.field-schema-editor__preset{min-height:80px;padding:12px;border:1px solid var(--val-border-color, 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));color:var(--ion-text-color);text-align:left;cursor:pointer}.field-schema-editor__preset strong,.field-schema-editor__preset span{display:block}.field-schema-editor__preset span{margin-top:4px;font-size:.8125rem;line-height:1.3;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset--selected{border-color:var(--ion-color-primary);box-shadow:0 0 0 2px rgba(var(--ion-color-primary-rgb, 255, 0, 178),.14)}.field-schema-editor__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FormFieldComponent, selector: "val-form-field", inputs: ["label"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: FieldOptionsEditorComponent, selector: "val-field-options-editor", inputs: ["props"], outputs: ["optionsChange"] }] }); }
|
|
39836
|
+
}
|
|
39837
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldSchemaEditorComponent, decorators: [{
|
|
39838
|
+
type: Component,
|
|
39839
|
+
args: [{ selector: 'val-field-schema-editor', standalone: true, imports: [
|
|
39840
|
+
CommonModule,
|
|
39841
|
+
ReactiveFormsModule,
|
|
39842
|
+
FormFieldComponent,
|
|
39843
|
+
TextInputComponent,
|
|
39844
|
+
TextareaInputComponent,
|
|
39845
|
+
SearchSelectorComponent,
|
|
39846
|
+
ToggleInputComponent,
|
|
39847
|
+
FieldOptionsEditorComponent,
|
|
39848
|
+
], template: `
|
|
39849
|
+
<div class="field-schema-editor">
|
|
39850
|
+
@if (showPresets()) {
|
|
39851
|
+
<section class="field-schema-editor__presets">
|
|
39852
|
+
<span class="field-schema-editor__section-label">{{ props.presetsTitle || t('presetsTitle') }}</span>
|
|
39853
|
+
<div class="field-schema-editor__preset-grid">
|
|
39854
|
+
@for (preset of props.presets; track preset.id) {
|
|
39855
|
+
<button
|
|
39856
|
+
type="button"
|
|
39857
|
+
class="field-schema-editor__preset"
|
|
39858
|
+
[class.field-schema-editor__preset--selected]="selectedPresetId() === preset.id"
|
|
39859
|
+
(click)="selectPreset(preset)"
|
|
39860
|
+
>
|
|
39861
|
+
<strong>{{ preset.label }}</strong>
|
|
39862
|
+
@if (preset.description) {
|
|
39863
|
+
<span>{{ preset.description }}</span>
|
|
39864
|
+
}
|
|
39865
|
+
</button>
|
|
39866
|
+
}
|
|
39867
|
+
</div>
|
|
39868
|
+
</section>
|
|
39869
|
+
}
|
|
39870
|
+
|
|
39871
|
+
<val-form-field [label]="t('labelLabel')">
|
|
39872
|
+
<val-text-input [props]="{ control: labelControl, placeholder: t('labelPlaceholder'), state: state() }" />
|
|
39873
|
+
</val-form-field>
|
|
39874
|
+
|
|
39875
|
+
<val-form-field [label]="t('typeLabel')">
|
|
39876
|
+
<val-select-input [props]="typeSelectProps()" />
|
|
39877
|
+
</val-form-field>
|
|
39878
|
+
|
|
39879
|
+
@if (props.showPlaceholder !== false) {
|
|
39880
|
+
<val-form-field [label]="t('placeholderLabel')">
|
|
39881
|
+
<val-textarea-input [props]="{ control: placeholderControl, autoGrow: true, state: state() }" />
|
|
39882
|
+
</val-form-field>
|
|
39883
|
+
}
|
|
39884
|
+
|
|
39885
|
+
@if (props.showHint !== false) {
|
|
39886
|
+
<val-form-field [label]="t('hintLabel')">
|
|
39887
|
+
<val-textarea-input [props]="{ control: hintControl, autoGrow: true, state: state() }" />
|
|
39888
|
+
</val-form-field>
|
|
39889
|
+
}
|
|
39890
|
+
|
|
39891
|
+
<val-toggle-input
|
|
39892
|
+
[props]="{
|
|
39893
|
+
control: requiredControl,
|
|
39894
|
+
label: t('requiredLabel'),
|
|
39895
|
+
justify: 'space-between',
|
|
39896
|
+
state: state(),
|
|
39897
|
+
}"
|
|
39898
|
+
/>
|
|
39899
|
+
|
|
39900
|
+
@if (needsOptions()) {
|
|
39901
|
+
<val-field-options-editor [props]="optionsEditorProps()" (optionsChange)="setOptions($event)" />
|
|
39902
|
+
}
|
|
39903
|
+
|
|
39904
|
+
@if (validationError()) {
|
|
39905
|
+
<p class="field-schema-editor__error">{{ validationError() }}</p>
|
|
39906
|
+
}
|
|
39907
|
+
</div>
|
|
39908
|
+
`, styles: [":host{display:block}.field-schema-editor{display:flex;flex-direction:column;gap:12px}.field-schema-editor__presets{display:flex;flex-direction:column;gap:8px}.field-schema-editor__section-label{font-size:.8125rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px}.field-schema-editor__preset{min-height:80px;padding:12px;border:1px solid var(--val-border-color, 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));color:var(--ion-text-color);text-align:left;cursor:pointer}.field-schema-editor__preset strong,.field-schema-editor__preset span{display:block}.field-schema-editor__preset span{margin-top:4px;font-size:.8125rem;line-height:1.3;color:var(--ion-color-medium, #92949c)}.field-schema-editor__preset--selected{border-color:var(--ion-color-primary);box-shadow:0 0 0 2px rgba(var(--ion-color-primary-rgb, 255, 0, 178),.14)}.field-schema-editor__error{margin:0;color:var(--ion-color-danger);font-size:.875rem;font-weight:700}\n"] }]
|
|
39909
|
+
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
39910
|
+
type: Input
|
|
39911
|
+
}], save: [{
|
|
39912
|
+
type: Output
|
|
39913
|
+
}], changed: [{
|
|
39914
|
+
type: Output
|
|
39915
|
+
}] } });
|
|
39916
|
+
|
|
39173
39917
|
class RequestFormBuilderService extends FormSchemaBuilderService {
|
|
39174
39918
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestFormBuilderService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39175
39919
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestFormBuilderService, providedIn: 'root' }); }
|
|
@@ -39179,6 +39923,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39179
39923
|
args: [{ providedIn: 'root' }]
|
|
39180
39924
|
}] });
|
|
39181
39925
|
|
|
39926
|
+
/**
|
|
39927
|
+
* Tipos de pregunta que ofrece una encuesta.
|
|
39928
|
+
*
|
|
39929
|
+
* El corte no es estético: **todo tipo que esta lista ofrezca, `val-survey-response`
|
|
39930
|
+
* tiene que saber renderizarlo**, o la encuesta se guarda bien y se responde mal
|
|
39931
|
+
* (un rating dibujado como caja de texto). Ampliar acá obliga a ampliar el
|
|
39932
|
+
* renderer en la misma entrega.
|
|
39933
|
+
*
|
|
39934
|
+
* Los seis primeros son de respuesta cerrada — `closedAnswerTypes` en
|
|
39935
|
+
* `backend/go/services/request/aggregate.go` los cuenta por valor en el
|
|
39936
|
+
* dashboard. Los seis últimos son abiertos: el dashboard lista sus respuestas.
|
|
39937
|
+
*
|
|
39938
|
+
* `FILE`/`ATTACHMENT` quedan deliberadamente fuera: una encuesta es pública y
|
|
39939
|
+
* anónima por default, y aceptar subidas ahí es superficie de abuso sin un caso
|
|
39940
|
+
* de uso que lo pida.
|
|
39941
|
+
*/
|
|
39942
|
+
const SURVEY_QUESTION_TYPES = [
|
|
39943
|
+
'EMOJI_RATING',
|
|
39944
|
+
'SELECT',
|
|
39945
|
+
'RADIO',
|
|
39946
|
+
'MULTI_SELECT',
|
|
39947
|
+
'CHECK',
|
|
39948
|
+
'TOGGLE',
|
|
39949
|
+
'TEXT',
|
|
39950
|
+
'TEXTAREA',
|
|
39951
|
+
'NUMBER',
|
|
39952
|
+
'DATE',
|
|
39953
|
+
'EMAIL',
|
|
39954
|
+
'PHONE',
|
|
39955
|
+
];
|
|
39956
|
+
|
|
39182
39957
|
const SURVEY_BUILDER_I18N = {
|
|
39183
39958
|
es: {
|
|
39184
39959
|
titleLabel: 'Título',
|
|
@@ -39187,10 +39962,16 @@ const SURVEY_BUILDER_I18N = {
|
|
|
39187
39962
|
subtitlePlaceholder: 'Ej: Ayúdanos a mejorar respondiendo estas preguntas',
|
|
39188
39963
|
questionsLabel: 'Preguntas',
|
|
39189
39964
|
questionLabelPlaceholder: 'Escribe la pregunta',
|
|
39190
|
-
typeEmoji: 'Emoji',
|
|
39191
|
-
typeText: 'Texto libre',
|
|
39192
39965
|
addQuestion: 'Agregar pregunta',
|
|
39193
|
-
removeQuestion: 'Quitar',
|
|
39966
|
+
removeQuestion: 'Quitar pregunta',
|
|
39967
|
+
editQuestion: 'Editar pregunta',
|
|
39968
|
+
duplicateQuestion: 'Duplicar pregunta',
|
|
39969
|
+
moveUp: 'Subir pregunta',
|
|
39970
|
+
moveDown: 'Bajar pregunta',
|
|
39971
|
+
doneEditing: 'Listo',
|
|
39972
|
+
untitledQuestion: 'Pregunta sin texto',
|
|
39973
|
+
requiredTag: 'Obligatoria',
|
|
39974
|
+
missingOptions: 'Hay preguntas de opciones sin ninguna opción cargada.',
|
|
39194
39975
|
save: 'Guardar encuesta',
|
|
39195
39976
|
noTitle: 'Ponle un título a la encuesta',
|
|
39196
39977
|
noQuestions: 'Agrega al menos una pregunta',
|
|
@@ -39205,10 +39986,16 @@ const SURVEY_BUILDER_I18N = {
|
|
|
39205
39986
|
subtitlePlaceholder: 'E.g: Help us improve by answering these questions',
|
|
39206
39987
|
questionsLabel: 'Questions',
|
|
39207
39988
|
questionLabelPlaceholder: 'Write the question',
|
|
39208
|
-
typeEmoji: 'Emoji',
|
|
39209
|
-
typeText: 'Free text',
|
|
39210
39989
|
addQuestion: 'Add question',
|
|
39211
|
-
removeQuestion: 'Remove',
|
|
39990
|
+
removeQuestion: 'Remove question',
|
|
39991
|
+
editQuestion: 'Edit question',
|
|
39992
|
+
duplicateQuestion: 'Duplicate question',
|
|
39993
|
+
moveUp: 'Move question up',
|
|
39994
|
+
moveDown: 'Move question down',
|
|
39995
|
+
doneEditing: 'Done',
|
|
39996
|
+
untitledQuestion: 'Question with no text',
|
|
39997
|
+
requiredTag: 'Required',
|
|
39998
|
+
missingOptions: 'Some choice questions have no options set.',
|
|
39212
39999
|
save: 'Save survey',
|
|
39213
40000
|
noTitle: 'Give the survey a title',
|
|
39214
40001
|
noQuestions: 'Add at least one question',
|
|
@@ -39219,6 +40006,7 @@ const SURVEY_BUILDER_I18N = {
|
|
|
39219
40006
|
};
|
|
39220
40007
|
|
|
39221
40008
|
const NAMESPACE$1 = 'SurveyBuilder';
|
|
40009
|
+
const EDITOR_NAMESPACE = 'FieldSchemaEditor';
|
|
39222
40010
|
const DEFAULT_TYPE_PREFIX = 'survey';
|
|
39223
40011
|
let rowUid = 0;
|
|
39224
40012
|
/**
|
|
@@ -39229,11 +40017,14 @@ let rowUid = 0;
|
|
|
39229
40017
|
* true` (cada respuesta se agrega, no se revisa una por una) y el `EntityRef`
|
|
39230
40018
|
* que le pasa el consumer (ej. el evento de bingo dueño de la encuesta).
|
|
39231
40019
|
*
|
|
39232
|
-
*
|
|
39233
|
-
*
|
|
39234
|
-
*
|
|
39235
|
-
*
|
|
39236
|
-
*
|
|
40020
|
+
* Cada pregunta se edita con `val-field-schema-editor`, el mismo editor que usa
|
|
40021
|
+
* el checkout de bingo — de ahí que una pregunta tenga tipo, placeholder, nota
|
|
40022
|
+
* y opciones, no solo texto. La v1 de este componente tenía su propio editor
|
|
40023
|
+
* pobre (dos tipos, sin opciones); la Fase 5 del ADR-092 lo reemplazó por el
|
|
40024
|
+
* organism compartido en vez de mejorarlo por duplicado.
|
|
40025
|
+
*
|
|
40026
|
+
* El catálogo que ofrece sale de `SURVEY_QUESTION_TYPES` — acotado a lo que
|
|
40027
|
+
* `val-survey-response` sabe renderizar, no a lo que el editor sabe editar.
|
|
39237
40028
|
*/
|
|
39238
40029
|
class SurveyBuilderComponent {
|
|
39239
40030
|
constructor() {
|
|
@@ -39243,15 +40034,21 @@ class SurveyBuilderComponent {
|
|
|
39243
40034
|
this.requests = inject(RequestService);
|
|
39244
40035
|
this.formBuilder = inject(RequestFormBuilderService);
|
|
39245
40036
|
this.errors = inject(ValtechErrorService);
|
|
39246
|
-
this.emojiType = FIELD_TYPE_EMOJI_RATING;
|
|
39247
40037
|
this.titleControl = new FormControl('', { nonNullable: true });
|
|
39248
40038
|
this.subtitleControl = new FormControl('', { nonNullable: true });
|
|
39249
40039
|
this.questions = signal([]);
|
|
40040
|
+
this.editingId = signal('');
|
|
40041
|
+
this.validationError = signal('');
|
|
39250
40042
|
this.saving = signal(false);
|
|
39251
|
-
this.rowControls = new Map();
|
|
39252
40043
|
if (!this.i18n.hasNamespace(NAMESPACE$1)) {
|
|
39253
40044
|
this.i18n.registerDefaults(NAMESPACE$1, SURVEY_BUILDER_I18N);
|
|
39254
40045
|
}
|
|
40046
|
+
// El nombre del tipo de cada pregunta se muestra en la fila colapsada, que
|
|
40047
|
+
// dibuja este componente y no el editor — si nadie montó un editor todavía,
|
|
40048
|
+
// el namespace no existiría y la fila mostraría la clave cruda.
|
|
40049
|
+
if (!this.i18n.hasNamespace(EDITOR_NAMESPACE)) {
|
|
40050
|
+
this.i18n.registerDefaults(EDITOR_NAMESPACE, FIELD_SCHEMA_EDITOR_I18N);
|
|
40051
|
+
}
|
|
39255
40052
|
}
|
|
39256
40053
|
async ngOnInit() {
|
|
39257
40054
|
if (!this.props.typeId)
|
|
@@ -39270,53 +40067,143 @@ class SurveyBuilderComponent {
|
|
|
39270
40067
|
});
|
|
39271
40068
|
}
|
|
39272
40069
|
}
|
|
39273
|
-
|
|
39274
|
-
|
|
39275
|
-
this.
|
|
40070
|
+
t(key) {
|
|
40071
|
+
this.i18n.lang();
|
|
40072
|
+
return this.i18n.t(key, NAMESPACE$1);
|
|
40073
|
+
}
|
|
40074
|
+
typeLabel(type) {
|
|
40075
|
+
this.i18n.lang();
|
|
40076
|
+
return this.i18n.t(`type${type}`, EDITOR_NAMESPACE);
|
|
40077
|
+
}
|
|
40078
|
+
questionTypes() {
|
|
40079
|
+
return this.props.questionTypes?.length ? this.props.questionTypes : SURVEY_QUESTION_TYPES;
|
|
40080
|
+
}
|
|
40081
|
+
editorProps(row) {
|
|
40082
|
+
return { mode: 'edit', field: row, allowedTypes: this.questionTypes() };
|
|
40083
|
+
}
|
|
40084
|
+
iconAction(token, icon, label, disabled = false, color = 'dark') {
|
|
39276
40085
|
return {
|
|
39277
|
-
|
|
39278
|
-
|
|
39279
|
-
|
|
39280
|
-
|
|
40086
|
+
token,
|
|
40087
|
+
text: '',
|
|
40088
|
+
ariaLabel: label,
|
|
40089
|
+
color,
|
|
40090
|
+
fill: 'clear',
|
|
40091
|
+
shape: 'round',
|
|
40092
|
+
size: 'small',
|
|
40093
|
+
type: 'button',
|
|
40094
|
+
state: disabled ? ComponentStates.DISABLED : ComponentStates.ENABLED,
|
|
40095
|
+
icon: { name: icon, slot: 'icon-only' },
|
|
39281
40096
|
};
|
|
39282
40097
|
}
|
|
39283
|
-
rowLabelControl(row) {
|
|
39284
|
-
let control = this.rowControls.get(row.id);
|
|
39285
|
-
if (!control) {
|
|
39286
|
-
control = new FormControl(row.label, { nonNullable: true });
|
|
39287
|
-
this.rowControls.set(row.id, control);
|
|
39288
|
-
}
|
|
39289
|
-
return control;
|
|
39290
|
-
}
|
|
39291
40098
|
addQuestion() {
|
|
39292
|
-
const
|
|
39293
|
-
|
|
39294
|
-
|
|
40099
|
+
const row = {
|
|
40100
|
+
id: `row-${rowUid++}`,
|
|
40101
|
+
name: '',
|
|
40102
|
+
label: '',
|
|
40103
|
+
placeholderText: '',
|
|
40104
|
+
hintText: '',
|
|
40105
|
+
type: this.questionTypes()[0],
|
|
40106
|
+
required: true,
|
|
40107
|
+
};
|
|
40108
|
+
this.questions.update(rows => [...rows, row]);
|
|
40109
|
+
// Una pregunta recién agregada está vacía: abrirla es el único paso
|
|
40110
|
+
// siguiente posible, y dejarla cerrada la haría ver como una fila rota.
|
|
40111
|
+
this.editingId.set(row.id);
|
|
40112
|
+
}
|
|
40113
|
+
toggleEdit(row) {
|
|
40114
|
+
this.editingId.update(current => (current === row.id ? '' : row.id));
|
|
39295
40115
|
}
|
|
39296
40116
|
removeQuestion(row) {
|
|
39297
|
-
this.rowControls.delete(row.id);
|
|
39298
40117
|
this.questions.update(rows => rows.filter(r => r.id !== row.id));
|
|
40118
|
+
if (this.editingId() === row.id)
|
|
40119
|
+
this.editingId.set('');
|
|
40120
|
+
}
|
|
40121
|
+
duplicate(row) {
|
|
40122
|
+
const copy = {
|
|
40123
|
+
...row,
|
|
40124
|
+
id: `row-${rowUid++}`,
|
|
40125
|
+
// Sin token propio la copia pisaría las respuestas del original: dos
|
|
40126
|
+
// campos con el mismo `name` son el mismo campo para el backend.
|
|
40127
|
+
name: this.formBuilder.uniqueFieldName(row.name || row.label, this.questions()),
|
|
40128
|
+
options: row.options ? row.options.map(o => ({ ...o })) : undefined,
|
|
40129
|
+
};
|
|
40130
|
+
this.questions.update(rows => {
|
|
40131
|
+
const index = rows.findIndex(r => r.id === row.id);
|
|
40132
|
+
return [...rows.slice(0, index + 1), copy, ...rows.slice(index + 1)];
|
|
40133
|
+
});
|
|
40134
|
+
}
|
|
40135
|
+
move(index, delta) {
|
|
40136
|
+
const target = index + delta;
|
|
40137
|
+
this.questions.update(rows => {
|
|
40138
|
+
if (target < 0 || target >= rows.length)
|
|
40139
|
+
return rows;
|
|
40140
|
+
const next = [...rows];
|
|
40141
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
40142
|
+
return next;
|
|
40143
|
+
});
|
|
39299
40144
|
}
|
|
39300
|
-
|
|
39301
|
-
|
|
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
|
+
}
|
|
40159
|
+
applyQuestion(field) {
|
|
40160
|
+
this.questions.update(rows => rows.map(r => r.id === field.id
|
|
40161
|
+
? {
|
|
40162
|
+
...field,
|
|
40163
|
+
name: this.formBuilder.uniqueFieldName(field.name || field.label, rows.filter(o => o.id !== r.id)),
|
|
40164
|
+
}
|
|
40165
|
+
: r));
|
|
40166
|
+
this.editingId.set('');
|
|
40167
|
+
this.validationError.set('');
|
|
39302
40168
|
}
|
|
39303
40169
|
async save() {
|
|
39304
40170
|
if (this.saving())
|
|
39305
40171
|
return;
|
|
40172
|
+
this.validationError.set('');
|
|
39306
40173
|
const title = this.titleControl.value.trim();
|
|
39307
40174
|
if (!title) {
|
|
39308
40175
|
this.titleControl.markAsTouched();
|
|
40176
|
+
this.validationError.set(this.t('noTitle'));
|
|
39309
40177
|
return;
|
|
39310
40178
|
}
|
|
39311
40179
|
const rows = this.questions();
|
|
39312
|
-
|
|
39313
|
-
|
|
40180
|
+
if (!rows.length) {
|
|
40181
|
+
this.validationError.set(this.t('noQuestions'));
|
|
40182
|
+
return;
|
|
40183
|
+
}
|
|
40184
|
+
if (rows.some(r => !r.label.trim())) {
|
|
40185
|
+
this.validationError.set(this.t('emptyQuestionLabel'));
|
|
40186
|
+
return;
|
|
40187
|
+
}
|
|
40188
|
+
// El editor ya lo valida al cerrar cada pregunta, pero una pregunta abierta
|
|
40189
|
+
// (o cargada de una encuesta vieja) puede llegar acá sin opciones.
|
|
40190
|
+
if (rows.some(r => FIELD_TYPES_WITH_OPTIONS.includes(r.type) && !r.options?.length)) {
|
|
40191
|
+
this.validationError.set(this.t('missingOptions'));
|
|
39314
40192
|
return;
|
|
40193
|
+
}
|
|
39315
40194
|
this.saving.set(true);
|
|
39316
40195
|
const fieldSchema = [];
|
|
39317
40196
|
rows.forEach((row, index) => {
|
|
39318
|
-
const name = this.formBuilder.uniqueFieldName(
|
|
39319
|
-
fieldSchema.push(this.formBuilder.createFieldSchema({
|
|
40197
|
+
const name = this.formBuilder.uniqueFieldName(row.name || row.label, fieldSchema);
|
|
40198
|
+
fieldSchema.push(this.formBuilder.createFieldSchema({
|
|
40199
|
+
name,
|
|
40200
|
+
label: row.label.trim(),
|
|
40201
|
+
type: row.type,
|
|
40202
|
+
required: row.required,
|
|
40203
|
+
placeholderText: row.placeholderText,
|
|
40204
|
+
hintText: row.hintText,
|
|
40205
|
+
options: row.options,
|
|
40206
|
+
}, index));
|
|
39320
40207
|
});
|
|
39321
40208
|
const typeId = this.props.typeId ?? `${this.props.typePrefix ?? DEFAULT_TYPE_PREFIX}:${this.formBuilder.toToken(title)}`;
|
|
39322
40209
|
const subtitle = this.subtitleControl.value.trim();
|
|
@@ -39346,68 +40233,89 @@ class SurveyBuilderComponent {
|
|
|
39346
40233
|
});
|
|
39347
40234
|
}
|
|
39348
40235
|
}
|
|
39349
|
-
|
|
39350
|
-
return
|
|
40236
|
+
rowFromField(f) {
|
|
40237
|
+
return {
|
|
40238
|
+
id: `row-${rowUid++}`,
|
|
40239
|
+
name: f.name,
|
|
40240
|
+
label: f.label ?? '',
|
|
40241
|
+
placeholderText: f.placeholderText ?? '',
|
|
40242
|
+
hintText: f.hintText ?? '',
|
|
40243
|
+
type: f.type,
|
|
40244
|
+
required: !!f.required,
|
|
40245
|
+
options: f.options,
|
|
40246
|
+
};
|
|
39351
40247
|
}
|
|
39352
40248
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39353
40249
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SurveyBuilderComponent, isStandalone: true, selector: "val-survey-builder", inputs: { props: "props" }, outputs: { saved: "saved" }, ngImport: i0, template: `
|
|
39354
40250
|
<div class="survey-builder">
|
|
39355
|
-
<
|
|
39356
|
-
<val-title [props]="{ content: t('titleLabel'), size: 'small', color: 'dark', bold: false }" />
|
|
40251
|
+
<val-form-field [label]="t('titleLabel')">
|
|
39357
40252
|
<val-text-input [props]="{ control: titleControl, placeholder: t('titlePlaceholder') }" />
|
|
39358
|
-
</
|
|
39359
|
-
<
|
|
39360
|
-
<val-title [props]="{ content: t('subtitleLabel'), size: 'small', color: 'dark', bold: false }" />
|
|
40253
|
+
</val-form-field>
|
|
40254
|
+
<val-form-field [label]="t('subtitleLabel')">
|
|
39361
40255
|
<val-text-input [props]="{ control: subtitleControl, placeholder: t('subtitlePlaceholder') }" />
|
|
39362
|
-
</
|
|
40256
|
+
</val-form-field>
|
|
39363
40257
|
|
|
39364
40258
|
<div class="survey-builder__questions">
|
|
39365
40259
|
<span class="survey-builder__questions-label">{{ t('questionsLabel') }}</span>
|
|
39366
40260
|
|
|
39367
|
-
@
|
|
40261
|
+
@if (!questions().length) {
|
|
40262
|
+
<p class="survey-builder__empty">{{ t('noQuestions') }}</p>
|
|
40263
|
+
}
|
|
40264
|
+
|
|
40265
|
+
@for (row of questions(); track row.id; let i = $index; let first = $first; let last = $last) {
|
|
39368
40266
|
<div class="survey-builder__row">
|
|
39369
|
-
<
|
|
39370
|
-
|
|
39371
|
-
|
|
39372
|
-
|
|
39373
|
-
|
|
39374
|
-
|
|
39375
|
-
|
|
39376
|
-
|
|
39377
|
-
|
|
39378
|
-
|
|
39379
|
-
|
|
39380
|
-
|
|
39381
|
-
|
|
39382
|
-
|
|
39383
|
-
|
|
39384
|
-
|
|
39385
|
-
|
|
39386
|
-
|
|
39387
|
-
|
|
39388
|
-
|
|
39389
|
-
|
|
39390
|
-
|
|
39391
|
-
|
|
39392
|
-
|
|
39393
|
-
|
|
39394
|
-
|
|
39395
|
-
|
|
39396
|
-
/>
|
|
39397
|
-
<val-button
|
|
39398
|
-
[props]="{
|
|
39399
|
-
token: 'q-remove-' + row.id,
|
|
39400
|
-
text: t('removeQuestion'),
|
|
39401
|
-
color: 'danger',
|
|
39402
|
-
fill: 'clear',
|
|
39403
|
-
shape: 'round',
|
|
39404
|
-
size: 'small',
|
|
39405
|
-
type: 'button',
|
|
39406
|
-
state: 'ENABLED',
|
|
39407
|
-
}"
|
|
39408
|
-
(onClick)="removeQuestion(row)"
|
|
39409
|
-
/>
|
|
40267
|
+
<div class="survey-builder__row-head">
|
|
40268
|
+
<div class="survey-builder__row-text">
|
|
40269
|
+
<strong>{{ row.label || t('untitledQuestion') }}</strong>
|
|
40270
|
+
<span>{{ typeLabel(row.type) }}{{ row.required ? ' · ' + t('requiredTag') : '' }}</span>
|
|
40271
|
+
</div>
|
|
40272
|
+
<div class="survey-builder__row-actions">
|
|
40273
|
+
<val-button
|
|
40274
|
+
[props]="iconAction('q-up-' + row.id, 'arrow-up-outline', t('moveUp'), first)"
|
|
40275
|
+
(onClick)="move(i, -1)"
|
|
40276
|
+
/>
|
|
40277
|
+
<val-button
|
|
40278
|
+
[props]="iconAction('q-down-' + row.id, 'arrow-down-outline', t('moveDown'), last)"
|
|
40279
|
+
(onClick)="move(i, 1)"
|
|
40280
|
+
/>
|
|
40281
|
+
<val-button
|
|
40282
|
+
[props]="iconAction('q-copy-' + row.id, 'copy-outline', t('duplicateQuestion'))"
|
|
40283
|
+
(onClick)="duplicate(row)"
|
|
40284
|
+
/>
|
|
40285
|
+
<val-button
|
|
40286
|
+
[props]="iconAction('q-edit-' + row.id, 'create-outline', t('editQuestion'))"
|
|
40287
|
+
(onClick)="toggleEdit(row)"
|
|
40288
|
+
/>
|
|
40289
|
+
<val-button
|
|
40290
|
+
[props]="iconAction('q-remove-' + row.id, 'trash-outline', t('removeQuestion'), false, 'danger')"
|
|
40291
|
+
(onClick)="removeQuestion(row)"
|
|
40292
|
+
/>
|
|
40293
|
+
</div>
|
|
39410
40294
|
</div>
|
|
40295
|
+
|
|
40296
|
+
@if (editingId() === row.id) {
|
|
40297
|
+
<div class="survey-builder__row-editor">
|
|
40298
|
+
<val-field-schema-editor
|
|
40299
|
+
#editor
|
|
40300
|
+
[props]="editorProps(row)"
|
|
40301
|
+
(changed)="draftQuestion($event)"
|
|
40302
|
+
(save)="applyQuestion($event)"
|
|
40303
|
+
/>
|
|
40304
|
+
<val-button
|
|
40305
|
+
[props]="{
|
|
40306
|
+
token: 'q-done-' + row.id,
|
|
40307
|
+
text: t('doneEditing'),
|
|
40308
|
+
color: 'dark',
|
|
40309
|
+
fill: 'solid',
|
|
40310
|
+
shape: 'round',
|
|
40311
|
+
size: 'default',
|
|
40312
|
+
type: 'button',
|
|
40313
|
+
state: 'ENABLED',
|
|
40314
|
+
}"
|
|
40315
|
+
(onClick)="editor.submit()"
|
|
40316
|
+
/>
|
|
40317
|
+
</div>
|
|
40318
|
+
}
|
|
39411
40319
|
</div>
|
|
39412
40320
|
}
|
|
39413
40321
|
|
|
@@ -39427,6 +40335,10 @@ class SurveyBuilderComponent {
|
|
|
39427
40335
|
/>
|
|
39428
40336
|
</div>
|
|
39429
40337
|
|
|
40338
|
+
@if (validationError()) {
|
|
40339
|
+
<p class="survey-builder__error">{{ validationError() }}</p>
|
|
40340
|
+
}
|
|
40341
|
+
|
|
39430
40342
|
<val-button
|
|
39431
40343
|
[props]="{
|
|
39432
40344
|
token: 'survey-builder-save',
|
|
@@ -39434,6 +40346,7 @@ class SurveyBuilderComponent {
|
|
|
39434
40346
|
color: 'dark',
|
|
39435
40347
|
fill: 'solid',
|
|
39436
40348
|
shape: 'round',
|
|
40349
|
+
size: 'large',
|
|
39437
40350
|
expand: 'block',
|
|
39438
40351
|
type: 'button',
|
|
39439
40352
|
state: saving() ? 'WORKING' : 'ENABLED',
|
|
@@ -39441,68 +40354,87 @@ class SurveyBuilderComponent {
|
|
|
39441
40354
|
(onClick)="save()"
|
|
39442
40355
|
/>
|
|
39443
40356
|
</div>
|
|
39444
|
-
`, isInline: true, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-
|
|
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"] }] }); }
|
|
39445
40358
|
}
|
|
39446
40359
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SurveyBuilderComponent, decorators: [{
|
|
39447
40360
|
type: Component,
|
|
39448
|
-
args: [{ selector: 'val-survey-builder', standalone: true, imports: [
|
|
40361
|
+
args: [{ selector: 'val-survey-builder', standalone: true, imports: [
|
|
40362
|
+
CommonModule,
|
|
40363
|
+
ReactiveFormsModule,
|
|
40364
|
+
TextInputComponent,
|
|
40365
|
+
ButtonComponent,
|
|
40366
|
+
FormFieldComponent,
|
|
40367
|
+
FieldSchemaEditorComponent,
|
|
40368
|
+
], template: `
|
|
39449
40369
|
<div class="survey-builder">
|
|
39450
|
-
<
|
|
39451
|
-
<val-title [props]="{ content: t('titleLabel'), size: 'small', color: 'dark', bold: false }" />
|
|
40370
|
+
<val-form-field [label]="t('titleLabel')">
|
|
39452
40371
|
<val-text-input [props]="{ control: titleControl, placeholder: t('titlePlaceholder') }" />
|
|
39453
|
-
</
|
|
39454
|
-
<
|
|
39455
|
-
<val-title [props]="{ content: t('subtitleLabel'), size: 'small', color: 'dark', bold: false }" />
|
|
40372
|
+
</val-form-field>
|
|
40373
|
+
<val-form-field [label]="t('subtitleLabel')">
|
|
39456
40374
|
<val-text-input [props]="{ control: subtitleControl, placeholder: t('subtitlePlaceholder') }" />
|
|
39457
|
-
</
|
|
40375
|
+
</val-form-field>
|
|
39458
40376
|
|
|
39459
40377
|
<div class="survey-builder__questions">
|
|
39460
40378
|
<span class="survey-builder__questions-label">{{ t('questionsLabel') }}</span>
|
|
39461
40379
|
|
|
39462
|
-
@
|
|
40380
|
+
@if (!questions().length) {
|
|
40381
|
+
<p class="survey-builder__empty">{{ t('noQuestions') }}</p>
|
|
40382
|
+
}
|
|
40383
|
+
|
|
40384
|
+
@for (row of questions(); track row.id; let i = $index; let first = $first; let last = $last) {
|
|
39463
40385
|
<div class="survey-builder__row">
|
|
39464
|
-
<
|
|
39465
|
-
|
|
39466
|
-
|
|
39467
|
-
|
|
39468
|
-
|
|
39469
|
-
|
|
39470
|
-
|
|
39471
|
-
|
|
39472
|
-
|
|
39473
|
-
|
|
39474
|
-
|
|
39475
|
-
|
|
39476
|
-
|
|
39477
|
-
|
|
39478
|
-
|
|
39479
|
-
|
|
39480
|
-
|
|
39481
|
-
|
|
39482
|
-
|
|
39483
|
-
|
|
39484
|
-
|
|
39485
|
-
|
|
39486
|
-
|
|
39487
|
-
|
|
39488
|
-
|
|
39489
|
-
|
|
39490
|
-
|
|
39491
|
-
/>
|
|
39492
|
-
<val-button
|
|
39493
|
-
[props]="{
|
|
39494
|
-
token: 'q-remove-' + row.id,
|
|
39495
|
-
text: t('removeQuestion'),
|
|
39496
|
-
color: 'danger',
|
|
39497
|
-
fill: 'clear',
|
|
39498
|
-
shape: 'round',
|
|
39499
|
-
size: 'small',
|
|
39500
|
-
type: 'button',
|
|
39501
|
-
state: 'ENABLED',
|
|
39502
|
-
}"
|
|
39503
|
-
(onClick)="removeQuestion(row)"
|
|
39504
|
-
/>
|
|
40386
|
+
<div class="survey-builder__row-head">
|
|
40387
|
+
<div class="survey-builder__row-text">
|
|
40388
|
+
<strong>{{ row.label || t('untitledQuestion') }}</strong>
|
|
40389
|
+
<span>{{ typeLabel(row.type) }}{{ row.required ? ' · ' + t('requiredTag') : '' }}</span>
|
|
40390
|
+
</div>
|
|
40391
|
+
<div class="survey-builder__row-actions">
|
|
40392
|
+
<val-button
|
|
40393
|
+
[props]="iconAction('q-up-' + row.id, 'arrow-up-outline', t('moveUp'), first)"
|
|
40394
|
+
(onClick)="move(i, -1)"
|
|
40395
|
+
/>
|
|
40396
|
+
<val-button
|
|
40397
|
+
[props]="iconAction('q-down-' + row.id, 'arrow-down-outline', t('moveDown'), last)"
|
|
40398
|
+
(onClick)="move(i, 1)"
|
|
40399
|
+
/>
|
|
40400
|
+
<val-button
|
|
40401
|
+
[props]="iconAction('q-copy-' + row.id, 'copy-outline', t('duplicateQuestion'))"
|
|
40402
|
+
(onClick)="duplicate(row)"
|
|
40403
|
+
/>
|
|
40404
|
+
<val-button
|
|
40405
|
+
[props]="iconAction('q-edit-' + row.id, 'create-outline', t('editQuestion'))"
|
|
40406
|
+
(onClick)="toggleEdit(row)"
|
|
40407
|
+
/>
|
|
40408
|
+
<val-button
|
|
40409
|
+
[props]="iconAction('q-remove-' + row.id, 'trash-outline', t('removeQuestion'), false, 'danger')"
|
|
40410
|
+
(onClick)="removeQuestion(row)"
|
|
40411
|
+
/>
|
|
40412
|
+
</div>
|
|
39505
40413
|
</div>
|
|
40414
|
+
|
|
40415
|
+
@if (editingId() === row.id) {
|
|
40416
|
+
<div class="survey-builder__row-editor">
|
|
40417
|
+
<val-field-schema-editor
|
|
40418
|
+
#editor
|
|
40419
|
+
[props]="editorProps(row)"
|
|
40420
|
+
(changed)="draftQuestion($event)"
|
|
40421
|
+
(save)="applyQuestion($event)"
|
|
40422
|
+
/>
|
|
40423
|
+
<val-button
|
|
40424
|
+
[props]="{
|
|
40425
|
+
token: 'q-done-' + row.id,
|
|
40426
|
+
text: t('doneEditing'),
|
|
40427
|
+
color: 'dark',
|
|
40428
|
+
fill: 'solid',
|
|
40429
|
+
shape: 'round',
|
|
40430
|
+
size: 'default',
|
|
40431
|
+
type: 'button',
|
|
40432
|
+
state: 'ENABLED',
|
|
40433
|
+
}"
|
|
40434
|
+
(onClick)="editor.submit()"
|
|
40435
|
+
/>
|
|
40436
|
+
</div>
|
|
40437
|
+
}
|
|
39506
40438
|
</div>
|
|
39507
40439
|
}
|
|
39508
40440
|
|
|
@@ -39522,6 +40454,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39522
40454
|
/>
|
|
39523
40455
|
</div>
|
|
39524
40456
|
|
|
40457
|
+
@if (validationError()) {
|
|
40458
|
+
<p class="survey-builder__error">{{ validationError() }}</p>
|
|
40459
|
+
}
|
|
40460
|
+
|
|
39525
40461
|
<val-button
|
|
39526
40462
|
[props]="{
|
|
39527
40463
|
token: 'survey-builder-save',
|
|
@@ -39529,6 +40465,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39529
40465
|
color: 'dark',
|
|
39530
40466
|
fill: 'solid',
|
|
39531
40467
|
shape: 'round',
|
|
40468
|
+
size: 'large',
|
|
39532
40469
|
expand: 'block',
|
|
39533
40470
|
type: 'button',
|
|
39534
40471
|
state: saving() ? 'WORKING' : 'ENABLED',
|
|
@@ -39536,7 +40473,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39536
40473
|
(onClick)="save()"
|
|
39537
40474
|
/>
|
|
39538
40475
|
</div>
|
|
39539
|
-
`, styles: [":host{display:block}.survey-builder{display:flex;flex-direction:column;gap:16px}.survey-
|
|
40476
|
+
`, 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"] }]
|
|
39540
40477
|
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
39541
40478
|
type: Input
|
|
39542
40479
|
}], saved: [{
|
|
@@ -89158,66 +90095,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
89158
90095
|
* aporta la sesión de escaneo, el feedback y el historial.
|
|
89159
90096
|
*/
|
|
89160
90097
|
|
|
89161
|
-
/**
|
|
89162
|
-
* Primitivo de campo de formulario: label (estilo val-form) + contenido proyectado.
|
|
89163
|
-
*
|
|
89164
|
-
* Usar cuando necesitás un campo fuera de val-form pero con el mismo estilo:
|
|
89165
|
-
* image-picker, date-picker, selectores custom, chips, etc.
|
|
89166
|
-
*
|
|
89167
|
-
* NOTA: para ion-input / ion-textarea NO usar ng-content projection — el Shadow DOM
|
|
89168
|
-
* de Ionic no responde al grid del host. Usá en cambio un `<div class="pf-field">`
|
|
89169
|
-
* plano en el template con `<p class="pf-label">` + ion-input directo.
|
|
89170
|
-
*
|
|
89171
|
-
* ```html
|
|
89172
|
-
* <val-form-field label="Imagen">
|
|
89173
|
-
* <app-image-picker ... />
|
|
89174
|
-
* </val-form-field>
|
|
89175
|
-
*
|
|
89176
|
-
* <!-- Para ion-input: NO val-form-field, usar div plano -->
|
|
89177
|
-
* <div class="pf-field">
|
|
89178
|
-
* <p class="pf-label">Nombre</p>
|
|
89179
|
-
* <ion-input fill="outline" ... />
|
|
89180
|
-
* </div>
|
|
89181
|
-
* ```
|
|
89182
|
-
*
|
|
89183
|
-
* El label usa el mismo val-title que val-form (size=small, color=dark, bold=false).
|
|
89184
|
-
* El spacing entre campos se controla con --val-form-field-gap (default 0.5rem).
|
|
89185
|
-
* El padding horizontal se hereda vía --val-form-field-padding (default 0).
|
|
89186
|
-
* Setearlo en el contenedor padre para consistencia sin override en cada campo:
|
|
89187
|
-
* `.my-card { --val-form-field-padding: 0 16px; }`
|
|
89188
|
-
*/
|
|
89189
|
-
class FormFieldComponent {
|
|
89190
|
-
constructor() {
|
|
89191
|
-
this.label = input('');
|
|
89192
|
-
this.titleProps = computed(() => ({
|
|
89193
|
-
content: this.label(),
|
|
89194
|
-
size: 'small',
|
|
89195
|
-
color: 'dark',
|
|
89196
|
-
bold: false,
|
|
89197
|
-
}));
|
|
89198
|
-
}
|
|
89199
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
89200
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FormFieldComponent, isStandalone: true, selector: "val-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
89201
|
-
@if (label()) {
|
|
89202
|
-
<div class="vff-label">
|
|
89203
|
-
<val-title [props]="titleProps()" />
|
|
89204
|
-
</div>
|
|
89205
|
-
}
|
|
89206
|
-
<ng-content />
|
|
89207
|
-
`, isInline: true, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"], dependencies: [{ kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
89208
|
-
}
|
|
89209
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
89210
|
-
type: Component,
|
|
89211
|
-
args: [{ selector: 'val-form-field', standalone: true, imports: [TitleComponent], template: `
|
|
89212
|
-
@if (label()) {
|
|
89213
|
-
<div class="vff-label">
|
|
89214
|
-
<val-title [props]="titleProps()" />
|
|
89215
|
-
</div>
|
|
89216
|
-
}
|
|
89217
|
-
<ng-content />
|
|
89218
|
-
`, styles: [":host{display:grid;grid-template-columns:1fr;width:100%;box-sizing:border-box;margin:var(--val-form-field-gap, .5rem) 0;padding:var(--val-form-field-padding, 0)}.vff-label{margin-bottom:.25rem}.vff-label ::ng-deep p{margin:0}\n"] }]
|
|
89219
|
-
}] });
|
|
89220
|
-
|
|
89221
90098
|
/**
|
|
89222
90099
|
* Token de inyeccion para la configuracion del Chat.
|
|
89223
90100
|
*/
|
|
@@ -92031,5 +92908,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
92031
92908
|
* Generated bundle index. Do not edit.
|
|
92032
92909
|
*/
|
|
92033
92910
|
|
|
92034
|
-
export { ACCESS_REQUEST_TYPE, ACCESS_REQUEST_VIEW_I18N, ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccessControlService, AccessRequestViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimalCardComponent, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BackButtonComponent, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CanAccessDirective, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ChipSelectComponent, ClientTelemetryService, CodeDisplayComponent, CodeValidatorComponent, CollectionsService, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CommsPreferencesService, CommsPreferencesSettingsComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ConfirmationDialogV2Component, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CANONICAL_FIELD_ALIASES, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMOJI_RATING_FACES, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DangerSectionComponent, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EXPECTED_NOT_FOUND, EditOrgModalComponent, EmojiRatingComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, EntradaSerializada, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeatureControlService, FeatureGuardDirective, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FieldOptionsEditorComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FolderTabsComponent, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GAME_AVATAR_CATALOG_SIZE_PER_STYLE, GameAvatarComponent, GameProfileService, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, GroupMembersComponent, GroupPickerComponent, GroupsService, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandleService, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METADATA_LIST_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAMES_I18N, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetadataListComponent, MeteringService, MetricCardComponent, MfaModalComponent, MiniGameCalloutComponent, MiniGamePlayerProfileService, MiniGameScorePopComponent, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NoticeComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberPickerComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OptionSheetComponent, OptionSheetService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PERSONA_CONFIG, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageBlockComponent, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PersonaService, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileCardComponent, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrBrandValidationError, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RbacService, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestReviewPanelComponent, RequestService, RetroAudioService, RichEditorComponent, RightsFooterComponent, RoleManagerComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SelectSearchPickerModalComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SupportTicketCtaComponent, SurveyBuilderComponent, SurveyResponseComponent, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeSelectorComponent, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ACCESS_FEATURES, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COLLECTIONS_CONFIG, VALTECH_COMMS_PREFERENCES_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_COPYRIGHT_TEMPLATE, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DIAGRAMS, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_LEGAL_ENTITY, VALTECH_MENU_I18N, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VAL_REGISTERED_ICONS, VERSION, ValCommentThreadComponent, ValQuotaWarningComponent, ValtechErrorService, VerifyViewComponent, VideoPlayerComponent, VideoUploadService, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, accessGuard, accessGuardFromRoute, applyDefaultValueToControl, articleToTiptapDoc, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildPlatformMenu, buildSettingsCards, buildSideNavItemsFromBottomNav, button, canSubmitRequestType, classifyChip, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGameAvatarCatalog, createGameAvatarProps, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, defaultQrBrand, docs, errorLoggingInterceptor, evaluateValtechAccess, extractPathParams, firmaDeSesionDeCustomToken, formatClockTime, formatDateSeparator, formatRelativeTime, gameAvatarCatalogEntryToMetadata, gameAvatarDataUri, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, providePersona, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccessFeatures, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechCollections, provideValtechCommsPreferences, provideValtechContent, provideValtechDebugConsole, provideValtechDiagrams, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, qrContrastRatio, qrErrorCorrectionFor, query, rbacGuard, renderGameAvatarSvg, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveCopyrightTemplate, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, roleOf, selectableRequestTypes, storagePaths, suggestEmailFix, superAdminGuard, supportedGameAvatarStyles, tiptapDocToArticle, tiptapDocToArticleElements, toArticle, validateQrBrand, validateRoutes };
|
|
92911
|
+
export { ACCESS_REQUEST_TYPE, ACCESS_REQUEST_VIEW_I18N, ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccessControlService, AccessRequestViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimalCardComponent, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BackButtonComponent, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CanAccessDirective, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ChipSelectComponent, ClientTelemetryService, CodeDisplayComponent, CodeValidatorComponent, CollectionsService, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CommsPreferencesService, CommsPreferencesSettingsComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ConfirmationDialogV2Component, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CANONICAL_FIELD_ALIASES, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMOJI_RATING_FACES, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DangerSectionComponent, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EXPECTED_NOT_FOUND, EditOrgModalComponent, EmojiRatingComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, EntradaSerializada, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FIELD_TYPES_WITH_OPTIONS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeatureControlService, FeatureGuardDirective, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FieldOptionsEditorComponent, FieldSchemaEditorComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FolderTabsComponent, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GAME_AVATAR_CATALOG_SIZE_PER_STYLE, GameAvatarComponent, GameProfileService, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, GroupMembersComponent, GroupPickerComponent, GroupsService, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandleService, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METADATA_LIST_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAMES_I18N, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetadataListComponent, MeteringService, MetricCardComponent, MfaModalComponent, MiniGameCalloutComponent, MiniGamePlayerProfileService, MiniGameScorePopComponent, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NoticeComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberPickerComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OptionSheetComponent, OptionSheetService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PERSONA_CONFIG, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageBlockComponent, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PersonaService, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileCardComponent, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrBrandValidationError, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RbacService, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestReviewPanelComponent, RequestService, RetroAudioService, RichEditorComponent, RightsFooterComponent, RoleManagerComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SURVEY_QUESTION_TYPES, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SelectSearchPickerModalComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SupportTicketCtaComponent, SurveyBuilderComponent, SurveyResponseComponent, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeSelectorComponent, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ACCESS_FEATURES, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COLLECTIONS_CONFIG, VALTECH_COMMS_PREFERENCES_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_COPYRIGHT_TEMPLATE, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DIAGRAMS, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_LEGAL_ENTITY, VALTECH_MENU_I18N, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VAL_REGISTERED_ICONS, VERSION, ValCommentThreadComponent, ValQuotaWarningComponent, ValtechErrorService, VerifyViewComponent, VideoPlayerComponent, VideoUploadService, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, accessGuard, accessGuardFromRoute, applyDefaultValueToControl, articleToTiptapDoc, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildPlatformMenu, buildSettingsCards, buildSideNavItemsFromBottomNav, button, canSubmitRequestType, classifyChip, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGameAvatarCatalog, createGameAvatarProps, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, defaultQrBrand, docs, errorLoggingInterceptor, evaluateValtechAccess, extractPathParams, firmaDeSesionDeCustomToken, formatClockTime, formatDateSeparator, formatRelativeTime, gameAvatarCatalogEntryToMetadata, gameAvatarDataUri, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, providePersona, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccessFeatures, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechCollections, provideValtechCommsPreferences, provideValtechContent, provideValtechDebugConsole, provideValtechDiagrams, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, qrContrastRatio, qrErrorCorrectionFor, query, rbacGuard, renderGameAvatarSvg, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveCopyrightTemplate, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, roleOf, selectableRequestTypes, storagePaths, suggestEmailFix, superAdminGuard, supportedGameAvatarStyles, tiptapDocToArticle, tiptapDocToArticleElements, toArticle, validateQrBrand, validateRoutes };
|
|
92035
92912
|
//# sourceMappingURL=valtech-components.mjs.map
|